diff -u --recursive --new-file v2.4.14/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.14/linux/Documentation/Configure.help Mon Nov 5 15:55:25 2001 +++ linux/Documentation/Configure.help Fri Nov 9 14:18:25 2001 @@ -1,62 +1,71 @@ -# Maintained by Axel Boldt (axel@uni-paderborn.de) +# Maintained by: +# Eric S. Raymond +# Steven Cole +# +# Merged version 2.49: Current with 2.4.15-pre1 and 2.4.13-ac8. # # This version of the Linux kernel configuration help texts # corresponds to the kernel versions 2.4.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 Pierre Tane (tanep@bigfoot.com), at -# http://www.traduc.org/kernelfr -# - Spanish, by Carlos Perelló Marín (fperllo@ehome.encis.es), at -# http://visar.csustan.edu/~carlos/ -# XXX: Site has moved, new location has no Configure.help trans. -# - Italian, by Alessandro Rubini (rubini@linux.it), at -# ftp://ftp-pavia1.linux.it/pub/linux/Configure.help -# XXX: ftp-pavia1.linux.it: Non-existent host/domain -# - 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 +# - Japanese, maintained by the JF Project , at +# +# - Russian, by , at +# +# - French, by Pierre Tane , at +# +# - Polish, by Dominik Mierzejewski , at +# +# - German, by SuSE, at . This patch # also includes infrastructure to support different languages. # # 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 +# an email to 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://www.linuxdoc.org/docs.html#howto . Before you start +# at . 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 +# are listed in the . 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' +# Format of this file: descriptionvariablehelp text. +# 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. 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. # +# Comments of the form "# Choice:" followed by a menu name are used +# internally by the maintainers' consistency-checking tools. +# # 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 +# 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. +# Make them file URLs relative to the top level of the source tree so +# that help browsers can turn them into hotlinks. All URLs ahould be +# surrounded by <>. +# # Repetitions are fine since the help texts are not meant to be read -# in sequence. +# in sequence. It is good style to include URLs pointing to more +# detailed technical information, pictures of the hardware, etc. +# +# The most important thing to include in a help entry is *motivation*. +# Explain why someone configuring a kernel might want to select your +# option. # # All this was shamelessly stolen from several different sources. Many # thanks to all the contributors. Feel free to use these help texts in @@ -66,21 +75,22 @@ Prompt for development and/or incomplete code/drivers CONFIG_EXPERIMENTAL - Some of the various things that Linux supports (such as network - drivers, file systems, network protocols, etc.) can be in a state - of development where the functionality, stability, or the level of + Some of the various things that Linux supports (such as network + drivers, file systems, 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 + known as the "alpha-test" phase among 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). + (before submitting bug reports, please read the documents + , , , + , and + 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 @@ -89,11 +99,18 @@ 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 + cause the configurator 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 +Prompt for drivers for obsolete features and hardware +CONFIG_OBSOLETE + Obsolete drivers have usually been replaced by more recent software + that can talk to the same hardware. Obsolete hardware is things + like MGA monitors that you are very unlikely to see on today's + systems. + +Symmetric Multi-Processing support 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 @@ -114,12 +131,106 @@ Y to "Enhanced Real Time Clock Support", below. The "Advanced Power Management" code will be disabled if you say Y here. - See also the files Documentation/smp.tex, Documentation/smp.txt, - Documentation/i386/IO-APIC.txt, Documentation/nmi_watchdog.txt and the - SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ . - + See also the , + , , + and the SMP-FAQ on the WWW at + . + If you don't know what to do here, say N. +Intel or compatible 80x86 processor +CONFIG_X86 + This is Linux's home port. Linux was originally native to the Intel + 386, and runs on all the later x86 processors including the Intel + 486, 586, Pentiums, and various instruction-set-compatible chips by + AMD, Cyrix, and others. + +Alpha processor +CONFIG_ALPHA + The Alpha is a 64-bit general-purpose processor designed and + marketed by the Digital Equipment Corporation of blessed memory, now + Compaq. Alpha Linux dates from 1995-1996 and was the first non-x86 + port. The Alpha Linux project has a home page at + . + +32-bit Sun Sparc +CONFIG_SPARC32 + SPARC is a family of RISC microprocessors designed and marketed by + Sun Microsystems, incorporated. They are very widely found in Sun + workstations and clones. This port covers the original 32-bit SPARC; + it is old and stable and usually considered one of the "big three" + along with the Intel and Alpha ports. The UltraLinux project + maintains both the SPARC32 and SPARC64 ports; its web page is + available at . + +64-bit Sun Sparc +CONFIG_SPARC64 + SPARC is a family of RISC microprocessors designed and marketed by + Sun Microsystems, incorporated. This port covers the newer 64-bit + UltraSPARC. The UltraLinux project maintains both the SPARC32 and + SPARC64 ports; its web page is available at + . + +Power PC processor +CONFIG_PPC + The PowerPC is a very capable 32-bit RISC processor from Motorola, + the successor to their 68000 and 88000 series. It powers recent + Macintoshes and also a widely-used series of single-board computers + from Motorola. The Linux PowerPC port has a home page at + . + +Motorola 68K processors +CONFIG_M68K + The Motorola 68K microprocessors are now obsolete, having been + superseded by the PowerPC line also from Motorola. But they powered + the first wave of workstation hardware in the 1980s, including Sun + workstations; they were also the basis of the original Amiga and + later Atari personal computers. A lot of this hardware is still + around. The m68k project has a home page at + . + +ARM processors +CONFIG_ARM + The ARM series is a line of low-power-consumption RISC chip designs + licensed by ARM ltd and targeted at embedded applications and + handhelds such as the Compaq IPAQ. ARM-based PCs are no longer + manufactured, but legacy ARM-based PC hardware remains popular in + Europe. There is an ARM Linux project with a web page at + . + +SuperH processors +CONFIG_SUPERH + The SuperH is a RISC processor targeted for use in embedded systems + and consumer electronics; it was also used in the Sega Dreamcast + gaming console. The SuperH port has a home page at + . + +IA64 processors, including Intel Itanium +CONFIG_IA64 + The Itanium is Intel's 64-bit successor to the 32-bit X86 line. As + of early 2001 it is not yet in widespread production use. The Linux + IA-64 project has a home page at . + +HP PA-RISC processor +CONFIG_PARISC + The PA-RISC microprocessor is a RISC chip designed by + Hewlett-Packard and used in their line of workstations. The PA-RISC + Linux project has a home page at . + +IBM System/390 +CONFIG_S390 + Linux now runs on the venerable System/390 mainframe from IBM, in a + guest partition under VM. In fact, over 40,000 simultaneous Linux + images have been run on a single mainframe! The S390 Linux project + has a home page at . + +Axis Communications ETRAX 100LX embedded network CPU +CONFIG_CRIS + Linux has been ported to run on the Axis Communications ETRAX 100LX + CPU and the single-board computers built around it, targeted for + network and embedded applications. For more information see the + Axis Communication site, . + Multiquad support for NUMA systems CONFIG_MULTIQUAD This option is used for getting Linux to run on a (IBM/Sequent) NUMA @@ -127,7 +238,7 @@ and uses Clustered Logical APIC addressing mode instead of Flat Logical. You will need a new lynxer.elf file to flash your firmware with - send email to Martin.Bligh@us.ibm.com - + IO-APIC Support on Uniprocessors CONFIG_X86_UP_IOAPIC An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an @@ -160,7 +271,7 @@ 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. + 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 @@ -172,7 +283,7 @@ 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. + emulation can be found in . If you are not sure, say Y; apart from resulting in a 66 KB bigger kernel, it won't hurt. @@ -211,12 +322,13 @@ functions. You may choose to use both, but the Timer LED function will overrule the CPU usage LED. -Kernel FP software completion (EXPERIMENTAL) +Kernel FP software completion 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. +# Choice: himem High Memory support CONFIG_NOHIGHMEM Linux can use up to 64 Gigabytes of physical memory on x86 systems. @@ -248,23 +360,45 @@ auto detected 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.) + kernel at boot time.) If unsure, say "off". +4GB +CONFIG_HIGHMEM4G + Select this if you have a 32-bit processor and between 1 and 4 + gigabytes of physical RAM. + +64GB +CONFIG_HIGHMEM64G + Select this if you have a 32-bit processor and more than 4 + gigabytes of physical RAM. + 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 Documentation/floppy.txt. That file - also contains the location of the Floppy driver FAQ as well as - location of the fdutils package used to configure additional + Thinkpad users, is contained in . + That 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. + module, say M here and read . + +iSeries Virtual I/O Disk Support +CONFIG_VIODASD + If you are running on an iSeries system and you want to use + virtual disks created and managed by OS/400, say Y. + +iSeries Virtual I/O Disk IDE Emulation +CONFIG_VIODASD_IDE + This causes the iSeries virtual disks to look like IDE disks. + If you have programs or utilities that only support certain + kinds of disks, this option will cause iSeries virtual disks + to pretend to be IDE disks, which may satisfy the program. Support for PowerMac floppy CONFIG_MAC_FLOPPY @@ -278,15 +412,15 @@ 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. + during the initial install of Linux. Note that the kernel command line option "ramdisk=XX" is now - obsolete. For details, read Documentation/ramdisk.txt. + obsolete. For details, read . 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. + say M and read . The module will be + called rd.o. Most normal users won't need the RAM disk functionality, and can thus say N here. @@ -301,15 +435,15 @@ 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. + "real" root file system, etc. See + for details. -Loop device support +Loopback 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. The loop devices + drive partitions, CD-ROM drives or floppy drives. The loop devices are block special device files with major number 7 and typically called /dev/loop0, /dev/loop1 etc. @@ -318,7 +452,7 @@ writing them to floppy. Furthermore, some Linux distributions avoid the need for a dedicated Linux partition by keeping their complete root file system inside a DOS FAT file using this loop device - driver. + driver. The loop device driver can also be used to "hide" a file system in a disk partition, floppy, or regular file, either using encryption @@ -326,58 +460,58 @@ 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.kerneli.org/pub/kerneli/ , and then you need to + , and then you need to say Y to this option. Note that alternative ways to use encrypted file systems are provided by the cfs package, which can be gotten from - ftp://ftp.kerneli.org/pub/kerneli/net-source/ , 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 + , and the newer tcfs + package, available at . You do not need + to say Y here if you want to use one of these. However, using cfs requires saying Y to "NFS file system support" below while using tcfs requires applying a kernel patch. An alternative steganography solution is provided by StegFS, also available from - ftp://ftp.kerneli.org/pub/kerneli/net-source/ . + . 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. + contained in the file . 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. + say M here and read . The module + will be called loop.o. Most users will answer N here. -Network Block Device support +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 file systems 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. + 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. + + Read 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. + say M here and read . The module + will be called nbd.o. If unsure, say N. @@ -385,16 +519,16 @@ CONFIG_IDE If you say Y here, your kernel will be able to manage low cost mass storage units such as ATA/(E)IDE and ATAPI units. The most common - cases are IDE hard drives and ATAPI CDROM drives. + cases are IDE hard drives and ATAPI CD-ROM drives. If your system is pure SCSI and doesn't use these interfaces, you can say N here. - + Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard for mass storage units such as hard disks. It was designed by Western Digital and Compaq Computer in 1984. It was then named ST506. Quite a number of disks use the IDE interface. - + AT Attachment (ATA) is the superset of the IDE specifications. ST506 was also called ATA-1. @@ -407,22 +541,22 @@ ATA/IDE standards by means of fast DMA controllers. ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and - CDROM drives, similar in many respects to the SCSI protocol. - + CD-ROM drives, similar in many respects to the SCSI protocol. + SMART IDE (Self Monitoring, Analysis and Reporting Technology) was designed in order to prevent data corruption and disk crash by detecting pre hardware failure conditions (heat, access time, and - the like...). Disks built since June 1995 may follow this - standard. The kernel itself don't manage this; however there are - quite a number of user programs such as smart that can query the - status of SMART parameters disk. + the like...). Disks built since June 1995 may follow this standard. + The kernel itself don't manage this; however there are quite a + number of user programs such as smart that can query the status of + SMART parameters disk. 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.o. + say M here and read . The module + will be called ide.o. - For further information, please read Documentation/ide.txt. + For further information, please read . If unsure, say Y. @@ -436,21 +570,21 @@ Useful information about large (>540 MB) IDE disks, multiple interfaces, what to do if ATA/IDE devices are not automatically detected, sound card ATA/IDE ports, module support, and other - topics, is contained in Documentation/ide.txt. For detailed + topics, is contained in . For detailed information about hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . To fine-tune ATA/IDE drive/interface parameters for improved performance, look for the hdparm package at - http://www.ibiblio.org/pub/Linux/system/hardware . + . 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-mod.o. Do not - compile this driver as a module if your root file system (the one - containing the directory /) is located on an IDE device. + say M here and read and + . The module will be called ide-mod.o. + Do not compile this driver as a module if your root file system (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 @@ -467,42 +601,42 @@ 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. + 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://www.linuxdoc.org/docs.html#howto . + . 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 + 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 + the 2nd/3rd/4th IDE interfaces. Doing this will prevent you from + having an IDE/ATAPI CD-ROM 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. + addresses. Normally, just say N here; you will then use the new driver for all 4 interfaces. Include IDE/ATA-2 DISK support CONFIG_BLK_DEV_IDEDISK - This will include enhanced support for MFM/RLL/IDE hard disks. If + 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 + 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 file system (the one containing the directory /) is located on - the IDE disk. If unsure, say Y. + say M here and read . The module + will be called ide-disk.o. Do not compile this driver as a module + if your root file system (the one containing the directory /) is + located on the IDE disk. If unsure, say Y. Use multi-mode by default CONFIG_IDEDISK_MULTI_MODE @@ -513,38 +647,43 @@ If in doubt, say N. -Include IDE/ATAPI CDROM support +PCMCIA IDE support +CONFIG_BLK_DEV_IDECS + Support for outboard IDE disks, tape drives, and CD-ROM drives + connected through a PCMCIA card. + +Include IDE/ATAPI CD-ROM 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 + If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is + a newer protocol used by IDE CD-ROM and TAPE drives, similar to the + SCSI protocol. Most new CD-ROM 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 + If you say Y here, the CD-ROM 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 file system support". + CD-ROM drive, you can say N to all other CD-ROM options, but be sure + to say Y or M to "ISO 9660 CD-ROM file system support". - Read the CDROM-HOWTO, available from - http://www.linuxdoc.org/docs.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 . + Read the CD-ROM-HOWTO, available from + and + . Note that older versions of lilo + (the Linux boot loader) cannot properly deal with IDE/ATAPI CD-ROMs, + so install lilo-16 or higher, available from + . 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. + say M here and read . The module + will be called ide-cd.o. 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. + ATAPI is a newer protocol used by IDE tape and CD-ROM drives, + similar to the SCSI protocol. If you have an SCSI tape drive + however, you can say N here. You should also say Y if you have an OnStream DI-30 tape drive; this will not work with the SCSI protocol, until there is support for the @@ -553,27 +692,27 @@ 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/ide/ide-tape.c and Documentation/ide.txt files for usage - information. + (check the boot messages with dmesg). Be sure to consult the + and 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. + say M here and read . 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. + answer Y. ATAPI is a newer protocol used by IDE CD-ROM/tape/floppy + drives, similar to the SCSI protocol. The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by this driver. For information about jumper settings and the question of when a ZIP drive uses a partition table, see - http://www.win.tue.nl/~aeb/linux/zip/zip-1.html . + . (ATAPI PD-CD/CDR drives are not supported by this driver; support - for PD-CD/CDR drives is available if you answer Y to + 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 @@ -582,8 +721,8 @@ 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. + say M here and read . The module + will be called ide-floppy.o. SCSI emulation support CONFIG_BLK_DEV_IDESCSI @@ -625,7 +764,7 @@ 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. + systems. This driver will work automatically in PCI based systems (most new systems have PCI slots). But if your system uses VESA local bus @@ -636,15 +775,15 @@ 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. + details, read . 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. + prefetch on CMD640 IDE interfaces. For details, read + . 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 @@ -654,14 +793,14 @@ 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. + things will operate 100% reliably. 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. - + Support for sharing PCI IDE interrupts CONFIG_IDEPCI_SHARE_IRQ Some ATA/IDE chipsets have hardware support which allows for @@ -681,14 +820,14 @@ 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/ide/ide-dma.c and - the file Documentation/ide.txt for more information. + Read the comments at the beginning of + and the file for more information. It is safe to say Y to this question. -Good-Bad DMA Model-Firmware (EXPERIMENTAL) +Good-Bad DMA Model-Firmware (WIP) CONFIG_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 @@ -701,6 +840,16 @@ If in doubt, say N. +Attempt to HACK around Chipsets that TIMEOUT (WIP) +CONFIG_BLK_DEV_IDEDMA_TIMEOUT + If you say Y here, this is a NASTY UGLY HACK! + + We have to issue an abort and requeue the request DMA engine got + turned off by a goofy ASIC, and we have to clean up the mess, and + here is as good as any. Do it globally for all chipsets. + + If in doubt, say N. + Boot off-board chipsets first support CONFIG_BLK_DEV_OFFBOARD Normally, IDE controllers built into the motherboard (on-board @@ -722,7 +871,7 @@ If in doubt, say N. -Use DMA by default when available +Use PCI 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 @@ -738,29 +887,39 @@ IGNORE word93 Validation BITS CONFIG_IDEDMA_IVB - Since various rules were applied and created ... et al. as it relates - the detection of valid cable signals. This is a result of unclear terms - in ATA-4 and ATA-5 standards. + Since various rules were applied and created ... et al. as it + relates the detection of valid cable signals. This is a result of + unclear terms in ATA-4 and ATA-5 standards. It is normally safe to answer Y; however, the default is N. -Various ATA, Work(s) In Progress (EXPERIMENTAL) +ATA Work(s) In Progress (EXPERIMENTAL)‹ CONFIG_IDEDMA_PCI_WIP If you enable this you will be able to use and test highly - developmental projects. If you say N, this configure script will + developmental projects. If you say N, the configurator will simply skip those options. It is SAFEST to say N to this question. +Asyncronious DMA support (EXPERIMENTAL) +CONFIG_BLK_DEV_ADMA + Please read the comments at the top of + . + +Pacific Digital A-DMA support (EXPERIMENTAL) +CONFIG_BLK_DEV_PDC_ADMA + Please read the comments at the top of . + 3ware Hardware ATA-RAID support CONFIG_BLK_DEV_3W_XXXX_RAID 3ware is the only hardware ATA-Raid product in Linux to date. This card is 2,4, or 8 channel master mode support only. SCSI support required!!! - http://www.3ware.com/ + - Please read the comments at the top of drivers/scsi/3w-xxxx.c + Please read the comments at the top of + . AEC62XX chipset support CONFIG_BLK_DEV_AEC62XX @@ -774,13 +933,13 @@ The ATP860 is an UltraDMA 66 chipset base. The ATP860M(acintosh) version is an UltraDMA 66 chipset base. - Please read the comments at the top of drivers/ide/aec62xx.c - If you say Y here, then say Y to "Use DMA by default when available" as - well. + Please read the comments at the top of . + If you say Y here, then say Y to "Use DMA by default when available" + as well. AEC62XX Tuning support CONFIG_AEC62XX_TUNING - Please read the comments at the top of drivers/ide/aec62xx.c + Please read the comments at the top of . If unsure, say N. ALI M15x3 chipset support @@ -790,8 +949,8 @@ 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/ide/alim15x3.c + when available", above. Please read the comments at the top of + . If unsure, say N. @@ -806,20 +965,21 @@ Using this option can allow WDC drives to run at ATA-4/5 transfer rates with only an ATA-2 support structure. - SAY NO! + SAY N! -AMD7409 chipset support -CONFIG_BLK_DEV_AMD7409 - This driver ensures (U)DMA support for the AMD756 Viper chipset. +AMD Viper support +CONFIG_BLK_DEV_AMD74XX + This driver ensures (U)DMA support for the AMD756/760 Viper + chipsets. 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/ide/amd7409.c + Please read the comments at the top of . If unsure, say N. -AMD Viper ATA-66 Override support (WIP) -CONFIG_AMD7409_OVERRIDE +AMD Viper ATA-66 Override (WIP) +CONFIG_AMD74XX_OVERRIDE This option auto-forces the ata66 flag. This effect can be also invoked by calling "idex=ata66" If unsure, say N. @@ -858,8 +1018,8 @@ HPT34X AUTODMA support (WIP) CONFIG_HPT34X_AUTODMA This is a dangerous thing to attempt currently! Please read the - comments at the top of drivers/ide/hpt34x.c If you say Y here, - then say Y to "Use DMA by default when available" as well. + comments at the top of . If you say Y + here, then say Y to "Use DMA by default when available" as well. If unsure, say N. @@ -868,9 +1028,9 @@ HPT366 is an Ultra DMA chipset for ATA-66. HPT368 is an Ultra DMA chipset for ATA-66 RAID Based. HPT370 is an Ultra DMA chipset for ATA-100. - + This driver adds up to 4 more EIDE devices sharing a single - interrupt. + interrupt. The HPT366 chipset in its current form is bootable. One solution for this problem are special LILO commands for redirecting the @@ -884,21 +1044,22 @@ ide-probe at boot. It is reported to support DVD II drives, by the manufacturer. -NS87415 support (EXPERIMENTAL) +NS87415 chipset 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/ide/ns87415.c. + Please read the comments at the top of . -OPTi 82C621 enhanced support (EXPERIMENTAL) +OPTi 82C621 chipset 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/ide/opti621.c. + Please read the comments at the top of . -ServerWorks OSB4 chipset support (EXPERIMENTAL) -CONFIG_BLK_DEV_OSB4 - This driver adds PIO/DMA support for the Serverworks OSB4 chipset +ServerWorks OSB4/CSB5 chipset support +CONFIG_BLK_DEV_SVWKS + This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5 + chipsets. Intel PIIXn chipsets support CONFIG_BLK_DEV_PIIX @@ -907,7 +1068,7 @@ 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/ide/piix.c. + Please read the comments at the top of . If you say Y here, you should also say Y to "PIIXn Tuning support", below. @@ -926,29 +1087,30 @@ If unsure, say N. -PROMISE PDC20246/PDC20262/PDC20267 support +PROMISE PDC20246/PDC20262/PDC20265/PDC20267/PDC20268 support CONFIG_BLK_DEV_PDC202XX Promise Ultra33 or PDC20246 Promise Ultra66 or PDC20262 - Promise Ultra100 or PDC20265/PDC20267 + Promise Ultra100 or PDC20265/PDC20267/PDC20268 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 + 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)". + "Special UDMA Feature". 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/ide/pdc202xx.c + Please read the comments at the top of + . If unsure, say N. -Special UDMA Feature (EXPERIMENTAL) +Special UDMA Feature CONFIG_PDC202XX_BURST For PDC20246, PDC20262, PDC20265 and PDC20267 Ultra DMA chipsets. Designed originally for PDC20246/Ultra33 that has BIOS setup @@ -956,10 +1118,15 @@ Unknown for PDC20265/PDC20267 Ultra DMA 100. - Please read the comments at the top of drivers/ide/pdc202xx.c + Please read the comments at the top of + . If unsure, say N. +Special FastTrak Feature +CONFIG_PDC202XX_FORCE + For FastTrak enable overriding BIOS. + SiS5513 chipset support CONFIG_BLK_DEV_SIS5513 This driver ensures (U)DMA support for SIS5513 chipset based @@ -969,20 +1136,21 @@ 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/ide/sis5513.c + Please read the comments at the top of . SLC90E66 chipset support CONFIG_BLK_DEV_SLC90E66 This driver ensures (U)DMA support for Victroy66 SouthBridges for SMsC with Intel NorthBridges. This is an Ultra66 based chipset. The nice thing about it is that you can mix Ultra/DMA/PIO devices - and it will handle timing cycles. Since this is an improved look-a-like - to the PIIX4 it should be a nice addition. + and it will handle timing cycles. Since this is an improved + look-a-like to the PIIX4 it should be a nice addition. 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/ide/slc90e66.c + Please read the comments at the top of + . Winbond SL82c105 support CONFIG_BLK_DEV_SL82C105 @@ -990,35 +1158,34 @@ 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) +Tekram TRM290 chipset support 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/ide/trm290.c. + Please read the comments at the top of . VIA82CXXX chipset support CONFIG_BLK_DEV_VIA82CXXX This allows you 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 may not be set by BIOS. It allows you to - pass 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 information from - /proc/ide/via provided you enabled "proc" support. + running PIO/(U)DMA, it will allow you to enable efficiently the + second channel dma usage, as it may not be set by BIOS. It will try + to set fifo configuration at its best. It will allow you to get + information from /proc/ide/via provided you enabled "/proc file + system" support. - Please read the comments at the top of drivers/ide/via82cxxx.c + Please read the comments at the top of + . If you say Y here, then say Y to "Use DMA by default when available" as well. If unsure, say N. -VIA82CXXX Tuning support (WIP) -CONFIG_VIA82CXXX_TUNING - Please read the comments at the top of drivers/ide/via82cxxx.c - - If unsure, say N. +RapIDE interface support +CONFIG_BLK_DEV_IDE_RAPIDE + Say Y here if you want to support the Yellowstone RapIDE controller + manufactured for use with Acorn computers. Other IDE chipset support CONFIG_IDE_CHIPSETS @@ -1030,9 +1197,9 @@ 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. + a list of these in the file . + + People with SCSI-only systems can say N here. Generic 4 drives/port support CONFIG_BLK_DEV_4DRIVES @@ -1045,53 +1212,64 @@ 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 + 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/ide/ali14xx.c for more info. + I/O speeds to be set as well. See the files + and 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/ide/dtc2278.c - files for more info. + well. See the and + 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/ide/ht6560b.c files for - more info. + See the and + 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 + 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/ide/pdc4030.c files for more info. + attached to the secondary interface. CD-ROM and TAPE devices are + not supported yet. This driver is enabled at runtime using the + "ide0=dc4030" kernel boot parameter. See the + and files + for more info. +# This is for Linus's tree. 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/ide/qd6580.c for more - info. + boot parameter. It permits faster I/O speeds to be set. See the + and for + more info. + +# This is for Alan's tree. Note the name difference. +QDI QD65XX support +CONFIG_BLK_DEV_QD65XX + This driver is enabled at runtime using the "ide0=qd65xx" kernel + boot parameter. It permits faster I/O speeds to be set. See the + and 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/ide/umc8672.c for - more info. + See the files and + for more info. -Amiga builtin Gayle IDE interface support +Amiga 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) @@ -1107,11 +1285,11 @@ disks, CD-ROM drives, etc.) that are connected to the builtin IDE interface. -Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL) +Amiga Buddha/Catweasel/X-Surf 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. + This is the IDE driver for the IDE interfaces on the Buddha, + Catweasel and X-Surf expansion boards. It supports up to two interfaces + on the Buddha, three on the Catweasel and two on the X-Surf. 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 @@ -1131,10 +1309,16 @@ 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) +WarpEngine SCSI support +CONFIG_WARPENGINE_SCSI + Support for MacroSystem Development's WarpEngine Amiga SCSI-2 + controller. Info at + . + +Builtin PowerMac IDE support CONFIG_BLK_DEV_IDE_PMAC - This driver provides support for the built-in IDE controller on most - of the recent Apple Power Macintoshes and PowerBooks. + This driver provides support for the built-in IDE controller on + most of the recent Apple Power Macintoshes and PowerBooks. If unsure, say Y. PowerMac IDE DMA support @@ -1164,29 +1348,6 @@ devices (hard disks, CD-ROM drives, etc.) that are connected to the builtin IDE interface. -MPC8xx IDE support -CONFIG_BLK_DEV_MPC8xx_IDE - This option provides support for IDE on Motorola MPC8xx Systems. - Please see 'Type of MPC8xx IDE interface' for details. - - If unsure, say N. - -Type of MPC8xx IDE interface -CONFIG_IDE_8xx_PCCARD - Select how the IDE devices are connected to the MPC8xx system: - - 8xx_PCCARD uses the 8xx internal PCMCIA interface in combination - with a PC Card (e.g. ARGOSY portable Hard Disk Adapter), - ATA PC Card HDDs or ATA PC Flash Cards (example: TQM8xxL - systems) - - 8xx_DIRECT is used for directly connected IDE devices using the 8xx - internal PCMCIA interface (example: IVMS8 systems) - - EXT_DIRECT is used for IDE devices directly connected to the 8xx - bus using some glue logic, but _not_ the 8xx internal - PCMCIA interface (example: IDIF860 systems) - ICS IDE interface support CONFIG_BLK_DEV_IDE_ICSIDE On Acorn systems, say Y here if you wish to use the ICS IDE @@ -1212,12 +1373,12 @@ 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. + 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. + say M here and read . The module + will be called xd.o. It's pretty unlikely that you have one of these: say N. @@ -1225,23 +1386,23 @@ 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. + say M here and read . The module + will be called ps2esdi.o. 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. + eXtremeRAID PCI RAID controllers. See the file + 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. + say M here and read . The module + will be called DAC960.o. Parallel port IDE device support CONFIG_PARIDE @@ -1249,7 +1410,7 @@ 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 Documentation/paride.txt for more information. + Read 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 @@ -1270,13 +1431,13 @@ 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 + 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. @@ -1291,8 +1452,8 @@ 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 file system support" below, because that's the file - system used on CDROMs. + 9660 CD-ROM file system support" below, because that's the file + system used on CD-ROMs. Parallel port ATAPI disks CONFIG_PARIDE_PF @@ -1322,7 +1483,7 @@ 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. + 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, @@ -1333,10 +1494,10 @@ your system. This driver implements an API loosely related to the generic SCSI - driver. See include/linux/pg.h for details. + driver. See . 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 + . Versions 1.6.1a3 and later fully support this driver. ATEN EH-100 protocol @@ -1352,39 +1513,40 @@ Micro Solutions BACKPACK Series 5 protocol CONFIG_PARIDE_BPCK - This option enables support for the Micro Solutions BACKPACK parallel - port Series 5 IDE protocol. (Most BACKPACK drives made before 1999 were - Series 5) Series 5 drives will NOT always have the Series noted on the - bottom of the drive. Series 6 drivers will. + This option enables support for the Micro Solutions BACKPACK + parallel port Series 5 IDE protocol. (Most BACKPACK drives made + before 1999 were Series 5) Series 5 drives will NOT always have the + Series noted on the bottom of the drive. Series 6 drivers will. In other words, if your BACKPACK drive dosen't say "Series 6" on the bottom, enable this option. - 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. + 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. Micro Solutions BACKPACK Series 6 protocol CONFIG_PARIDE_BPCK6 - This option enables support for the Micro Solutions BACKPACK parallel - port Series 6 IDE protocol. (Most BACKPACK drives made after 1999 were - Series 6) Series 6 drives will have the Series noted on the bottom of - the drive. Series 5 drivers don't always have it noted. + This option enables support for the Micro Solutions BACKPACK + parallel port Series 6 IDE protocol. (Most BACKPACK drives made + after 1999 were Series 6) Series 6 drives will have the Series noted + on the bottom of the drive. Series 5 drivers don't always have it + noted. - In other words, if your BACKPACK drive says "Series 6" on the bottom, - enable this option. + In other words, if your BACKPACK drive says "Series 6" on the + bottom, enable this option. - 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 bpck6.o. You - must also have a high-level driver for the type of device that you want - to support. + 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 bpck6.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 + 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 @@ -1393,7 +1555,7 @@ DataStor EP-2000 protocol CONFIG_PARIDE_DSTR - This option enables support for the EP-2000 parallel port IDE + 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 @@ -1412,7 +1574,7 @@ have a high-level driver for the type of device that you want to support. -Shuttle EPAT c7/c8 extension +Shuttle EPAT c7/c8 extension CONFIG_PARIDE_EPATC8 This option enables support for the newer Shuttle EP1284 (aka c7 and c8) chip. You need this if you are using any recent Imation SuperDisk @@ -1453,12 +1615,12 @@ 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 + 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. + of device that you want to support. FreeCom power protocol CONFIG_PARIDE_FRPW @@ -1493,12 +1655,12 @@ OnSpec 90c20 protocol CONFIG_PARIDE_ON20 - This option enables support for the (obsolete) 90c20 parallel port + 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 + 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 @@ -1522,13 +1684,19 @@ to new capacity needs. Logical volumes are accessed as block devices named /dev/VolumeGroupName/LogicalVolumeName. - For details see Documentation/LVM-HOWTO. You will need supporting - user space software; location is in Documentation/Changes. + For details see . You will need + supporting user space software; location is in + . If you want to compile this 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 lvm-mod.o. + want), say M here and read . The + module will be called lvm-mod.o. + +Multiple devices driver support (RAID and LVM) +CONFIG_MD + Support multiple physical spindles through a single logical device. + Required for RAID and logical volume management (LVM). Multiple devices driver support CONFIG_BLK_DEV_MD @@ -1543,7 +1711,7 @@ More information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . There you will also + . There you will also learn where to get the supporting user space utilities raidtools. If unsure, say N. @@ -1552,12 +1720,12 @@ 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. + 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. + say M here and read . The module + will be called linear.o. If unsure, say Y. @@ -1567,40 +1735,40 @@ 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. + 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://www.linuxdoc.org/docs.html#howto . There you will also + . 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. + say M here and read . The module + will be called raid0.o. If unsure, say Y. RAID-1 (mirroring) mode CONFIG_MD_RAID1 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 + 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 + 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. + drives. Information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . There you will also + . 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 + 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. @@ -1616,41 +1784,92 @@ Information about Software RAID on Linux is contained in the Software-RAID mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . There you will also + . 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. +Multipath I/O support +CONFIG_MD_MULTIPATH + Multipath-IO is the ability of certain devices to address the same + physical disk over multiple 'IO paths'. The code ensures that such + paths can be defined and handled at runtime, and ensures that a + transparent failover to the backup path(s) happens if a IO errors + arrives on the primary path. + + If unsure, say N. + +# AC tree only +Support for IDE Raid controllers +CONFIG_BLK_DEV_ATARAID + Say Y or M if you have an IDE Raid controller and want linux + to use its softwareraid feature. You must also select an + appropriate for your board low-level driver below. + + Note, that Linux does not use the Raid implemetation in BIOS, and + the main purpose for this feature is to retain compatibility and + data integrity with other OS-es, using the same disk array. Linux + has its own Raid drivers, which you should use if you need better + performance. + +# AC tree only +Support Promise software RAID (Fasttrak(tm)) +CONFIG_BLK_DEV_ATARAID_PDC + Say Y or M if you have a Promise Fasttrak (tm) Raid controller + and want linux to use the softwareraid feature of this card. + This driver uses /dev/ataraid/dXpY (X and Y numbers) as device + names. + + If you choose to compile this as a module, the module will be called + pdcraid.o. + +# AC tree only +Highpoint 370 software RAID +CONFIG_BLK_DEV_ATARAID_HPT + Say Y or M if you have a Highpoint HPT 370 Raid controller + and want linux to use the softwareraid feature of this card. + This driver uses /dev/ataraid/dXpY (X and Y numbers) as device + names. + + If you choose to compile this as a module, the module will be called + hptraid.o. + 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://oss.sgi.com/mips . + . 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 . + 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 . Support for BAGET MIPS series CONFIG_BAGET_MIPS - This enables support for the Baget, a Russian embedded system. For - more details about the Baget see the Linux/MIPS FAQ on - http://oss.sgi.com/mips . + This enables support for the Baget, a Russian embedded system. For + more details about the Baget see the Linux/MIPS FAQ on + . + +Baget AMD LANCE support +CONFIG_BAGETLANCE + Say Y to enable kernel support for AMD Lance Ethernet cards on the + MIPS-32-based Baget embedded system. This chipset is better known + via the NE2100 cards. Support for DECstations CONFIG_DECSTATION This enables support for DEC's MIPS based workstations. For details - see the Linux/MIPS FAQ on http://oss.sgi.com/mips and the - DECstation porting pages on http://decstation.unix-ag.org . + see the Linux/MIPS FAQ on and the + DECstation porting pages on . If you have one of the following DECstation Models you definitely want to choose R4xx0 for the CPU Type: @@ -1662,6 +1881,25 @@ otherwise choose R3000. +Support for Cobalt Micro Server +CONFIG_COBALT_MICRO_SERVER + Support for MIPS-based Cobalt boxes (they have been bought by Sun + and are now the "Server Appliance Business Unit") including the 2700 + series -- versions 1 of the Qube and Raq. To compile a Linux kernel + for this hardware, say Y here. + +Support for Cobalt 2800 +CONFIG_COBALT_28 + Support for the second generation of MIPS-based Cobalt boxes (they + have been bought by Sun and are now the "Server Appliance Business + Unit") including the 2800 series -- versions 2 of the Qube and Raq. + To compile a Linux kernel for this hardware, say Y here. + +Support for the Momentum Computer Ocelot SBC +CONFIG_MOMENCO_OCELOT + The Ocelot is a MIPS-based Single Board Computer (SBC) made by + Momentum Computer . + Support for NEC DDB Vrc-5074 CONFIG_DDB5074 This enables support for the VR5000-based NEC DDB Vrc-5074 @@ -1673,10 +1911,18 @@ evaluation board. Features : kernel debugging, serial terminal, NFS root fs, on-board - ether port (with a patch to tulip driver), IDE controller, PS2 keyboard - PS2 mouse, etc. + ether port (Need an additional patch at ), + USB, AC97, PCI, PCI VGA card & framebuffer console, IDE controller, + PS2 keyboard, PS2 mouse, etc. + +Support for NEC DDB Vrc-5477 +CONFIG_DDB5477 + This enables support for the R5432-based NEC DDB Vrc-5477 + evaluation board. - TODO : USB, Compact-PCI interface. + Features : kernel debugging, serial terminal, NFS root fs, on-board + ether port (Need an additional patch at ), + USB, AC97, PCI, etc. Support for MIPS Atlas board CONFIG_MIPS_ATLAS @@ -1688,19 +1934,39 @@ This enables support for the VR5000-based MIPS Malta evaluation board. +Support for Galileo Evaluation board or CoSine Orion +CONFIG_ORION + Say Y if configuring for the Galileo evaluation board + or CoSine Orion. More information is available at + . + + Otherwise, say N. + 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://oss.sgi.com/mips. + . + +Enable Qtronix 990P Keyboard Support +CONFIG_QTRONIX_KEYBOARD + Images of Qtronix keyboards are at + . 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://oss.sgi.com/mips. + . + +Support for SNI RM200 PCI +CONFIG_SNI_RM200_PCI + The SNI RM200 PCI was a MIPS-based platform manufactured by Siemens + Nixdorf Informationssysteme (SNI), parent company of Pyramid + Technology and now in turn merged with Fujitsu. Say Y here to + support this machine type. Support for SGI IP22 CONFIG_SGI_IP22 @@ -1709,6 +1975,7 @@ that runs on these, say Y here. Support for SGI IP27 +CONFIG_SGI_IP27 This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics workstations. To compile a Linux kernel that runs on these, say Y here. @@ -1731,11 +1998,49 @@ 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM systems. +MIPS GT96100 support +CONFIG_MIPS_GT96100 + Say Y here to support the Galileo Technology GT96100 communications + controller card. There is a web page at . + +MIPS GT96100 Ethernet support +CONFIG_MIPS_GT96100ETH + Say Y here to support the Ethernet subsystem on your GT96100 card. + +Zalon SCSI support +CONFIG_SCSI_ZALON + The Zalon is an interface chip that sits between the PA-RISC + processor and the NCR 53c720 SCSI controller on K-series PA-RISC + boards (these are used, among other places, on some HP 780 + workstations). Say Y here to make sure it gets initialized + correctly before the Linux kernel tries to talk to the controller. + Kernel floating-point instruction emulation CONFIG_MIPS_FPU_EMULATOR - This option enables the MIPS software floatingpoint support. Due to the - way floatingpoint works you should always enable this option unless - you exactly know what you're doing. + This option enables the MIPS software floatingpoint support. Due to + the way floating point works you should always enable this option + unless you exactly know what you're doing. + +SGI PROM Console Support +CONFIG_SGI_PROM_CONSOLE + Say Y here to set up the boot console on serial port 0. + +DZ11 Serial Support +CONFIG_DZ + DZ11-family serial controllers for VAXstations, including the + DC7085, M7814, and M7819. + + +TURBOchannel support +CONFIG_TC + TurboChannel is a DEC (now Compaq) bus for Alpha and MIPS processors. + Documentation on writing device drivers for TurboChannel is available at: + . + +Z85C30 Serial Support +CONFIG_ZS + Documentation on the Zilog 85C350 serial communications controller + is downloadable at . PCMCIA SCSI adapter support CONFIG_SCSI_PCMCIA @@ -1744,9 +2049,30 @@ size devices often used with laptops. Note that the answer to this question won't directly affect the - kernel: saying N will just cause this configure script to skip all + kernel: saying N will just cause the configurator to skip all the questions PCMCIA SCSI host adapters. +Adaptec APA1480 CardBus support +CONFIG_PCMCIA_APA1480 + Say Y here if you intend to attach this type of CardBus SCSI host + adapter to your computer. + + This driver is also available as a module called apa1480_cb.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 . + +NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support +CONFIG_PCMCIA_NINJA_SCSI + If you intend to attach this type of PCMCIA SCSI host adapter to + your computer, say Y here and read + . + + This driver is also available as a module called nsp_cs.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 . + Adaptec AHA152X PCMCIA support CONFIG_PCMCIA_AHA152X Say Y here if you intend to attach this type of PCMCIA SCSI host @@ -1755,7 +2081,7 @@ This driver is also available as a module called aha152x_cs.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. + here and read . Qlogic PCMCIA support CONFIG_PCMCIA_QLOGIC @@ -1764,8 +2090,8 @@ This driver is also available as a module called qlogic_cs.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. + whenever you want). If you want to compile it as a module, say M + here and read . Future Domain PCMCIA support CONFIG_PCMCIA_FDOMAIN @@ -1774,27 +2100,96 @@ This driver is also available as a module called fdomain_cs.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. - -Adaptec APA1480 CardBus support -CONFIG_PCMCIA_APA1480 - Say Y here if you intend to attach this type of CardBus SCSI host - adapter to your computer. - - This driver is also available as a module called apa1480_cb.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. + whenever you want). If you want to compile it as a module, say M + here and read . +# Choice: mipstype CPU type CONFIG_CPU_R3000 Please make sure to pick the right CPU type. Linux/MIPS is not designed to be generic, i.e. Kernels compiled for R3000 CPUs will - *not* work on R4000 Machines and vice versa. - However, since most the supported Machines have an R4000 (or - similar) CPU, R4xx0 might be a safe bet. - If the resulting Kernel does not work try to recompile with R3000. + *not* work on R4000 machines and vice versa. However, since most + of the supported machines have an R4000 (or similar) CPU, R4x00 + might be a safe bet. If the resulting kernel does not work, + try to recompile with R3000. + + R3000 MIPS Technologies R3000-series processors, + including the 3041, 3051, and 3081. + + R6000 MIPS Technologies R6000-series processors, + including the 64474, 64475, 64574 and 64575. + + R4300 MIPS Technologies R4300-series processors. + + R4x00 MIPS Technologies R4000-series processors other than 4300, + including the 4640, 4650, and 4700. + + R5000 MIPS Technologies R5000-series processors other than the + Nevada. + + R52xx MIPS Technologies R52xx-series ("Nevada") processors. + + R10000 MIPS Technologies R10000-series processors. + +R6000 +CONFIG_CPU_R6000 + MIPS Technologies R6000-series processors, including the 64474, + 64475, 64574 and 64575. + +R4300 +CONFIG_CPU_R4300 + MIPS Technologies R4300-series processors. + +R4x00 +CONFIG_CPU_R4X00 + MIPS Technologies R4000-series processors other than 4300, including + the 4640, 4650, and 4700. + +R5000 +CONFIG_CPU_R5000 + MIPS Technologies R5000-series processors other than the Nevada. + +R52x0 +CONFIG_CPU_NEVADA + MIPS Technologies R52x0-series ("Nevada") processors. + +R8000 +CONFIG_CPU_R8000 + MIPS Technologies R8000-series processors. + +R10000 +CONFIG_CPU_R10000 + MIPS Technologies R10000-series processors. + +Discontiguous Memory Support +CONFIG_DISCONTIGMEM + Say Y to upport efficient handling of discontiguous physical memory, + for architectures which are either NUMA (Non-Uniform Memory Access) + or have huge holes in the physical address space for other reasons. + See for more. + +Mapped kernel support +CONFIG_MAPPED_KERNEL + Change the way a Linux kernel is loaded unto memory on a MIPS64 + machine. This is required in order to support text replication and + NUMA. If you need to undersatand it, read the source code. + +Kernel text replication support +CONFIG_REPLICATE_KTEXT + Say Y here to enable replicating the kernel text across multiple + nodes in a NUMA cluster. This trades memory for speed. + +Exception handler replication support +CONFIG_REPLICATE_EXHANDLERS + Say Y here to enable replicating the kernel exception handlers + across multiple nodes in a NUMA cluster. This trades memory for + speed. + +NUMA support? +CONFIG_NUMA + Say Y to compile the kernel to support NUMA (Non-Uniform Memory + Access). This option is for configuring high-end multiprocessor + server machines. If in doubt, say N. CPU type CONFIG_CPU_VR41XX @@ -1805,14 +2200,18 @@ CPU feature configuration CONFIG_CPU_ADVANCED - Saying yes here allows you to select support for various features your - CPU may or may not have. Most people should say N here. + Saying yes here allows you to select support for various features + your CPU may or may not have. Most people should say N here. -ll and sc instructions +ll/sc Instructions available CONFIG_CPU_HAS_LLSC - Say Y here if your CPU has the ll and sc instructions. Say Y here for - better performance, N if you don't know. You must say Y here for - multiprocessor machines. + MIPS R4000 series and later provide the Load Linked (ll) + and Store Conditional (sc) instructions. More information is + available at . + + Say Y here if your CPU has the ll and sc instructions. Say Y here + for better performance, N if you don't know. You must say Y here + for multiprocessor machines. lld and scd instructions CONFIG_CPU_HAS_LLDSCD @@ -1820,7 +2219,7 @@ equivalents of ll and sc. Say Y here for better performance, N if you don't know. You must say Y here for multiprocessor machines. -Support for writebuffer flushing +Writeback Buffer available CONFIG_CPU_HAS_WB Say N here for slightly better performance. You must say Y here for machines which require flushing of write buffers in software. Saying @@ -1840,6 +2239,12 @@ byte order. These modes require different kernels. Say Y if your machine is little endian, N if it's a big endian machine. +Use power LED as a heartbeat +CONFIG_HEARTBEAT + Use the power-on LED on your machine as a load meter. The exact + behavior is platform-dependent, but normally the flash frequency is + a hyperbolic function of the 5-minute load average. + Networking support CONFIG_NET Unless you really know what you are doing, you should say Y here. @@ -1849,27 +2254,28 @@ 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. + of which are given in . For a general introduction to Linux networking, it is highly recommended to read the NET-3-HOWTO, available from - http://www.linuxdoc.org/docs.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 Documentation/networking/filter.txt for more information. + 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 for more + information. You need to say Y here if you want to use PPP packet filtering (see the CONFIG_PPP_FILTER option below). If unsure, say N. -Network packet filtering +Network packet filtering (replaces ipchains) CONFIG_NETFILTER Netfilter is a framework for filtering and mangling network packets that pass through your Linux box. @@ -1912,21 +2318,21 @@ Various modules exist for netfilter which replace the previous masquerading (ipmasqadm), packet filtering (ipchains), transparent proxying, and portforwarding mechanisms. Please see - Documentation/Changes under "iptables" for the location of these - packages. - + under "iptables" for the location of + these packages. + 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 You can say Y here if you want to get additional messages useful in - debugging the netfilter code. + debugging the netfilter code. -IP: connection tracking (required for masq/NAT) +Connection tracking (required for masq/NAT) CONFIG_IP_NF_CONNTRACK Connection tracking keeps a record of what packets have passed through your machine, in order to figure out how they are related @@ -1938,7 +2344,7 @@ below). If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. IRC Send/Chat support CONFIG_IP_NF_IRC @@ -1961,17 +2367,17 @@ of Network Address Translation on them. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `Y'. + . If unsure, say `Y'. -IP: user space queueing via NETLINK (EXPERIMENTAL) +User space queueing via NETLINK CONFIG_IP_NF_QUEUE Netfilter has the ability to queue packets to user space: the netlink device can be used to access them using this driver. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. -IP: ip tables support (required for filtering/masq/NAT) +IP tables support (required for filtering/masq/NAT) CONFIG_IP_NF_IPTABLES iptables is a general, extensible packet identification framework. The packet filtering and full NAT (masquerading, port forwarding, @@ -1979,41 +2385,7 @@ either of those. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. -CONFIG_IP6_NF_MATCH_LIMIT - limit matching allows you to control the rate at which a rule can be - matched: mainly useful in combination with the LOG target ("LOG - target support", below) and to avoid some Denial of Service attacks. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -MAC address match support -CONFIG_IP6_NF_MATCH_MAC - mac matching allows you to match packets based on the source - ethernet address of the packet. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -Multiple port match support -CONFIG_IP6_NF_MATCH_MULTIPORT - Multiport matching allows you to match TCP or UDP packets based on - a series of source or destination ports: normally a rule can only - match a single range of ports. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -Owner match support (EXPERIMENTAL) -CONFIG_IP6_NF_MATCH_OWNER - Packet owner matching allows you to match locally-generated packets - based on who created them: the user, group, process or session. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - - + . If unsure, say `N'. limit match support CONFIG_IP_NF_MATCH_LIMIT @@ -2022,24 +2394,24 @@ target support", below) and to avoid some Denial of Service attacks. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. MAC address match support CONFIG_IP_NF_MATCH_MAC - mac matching allows you to match packets based on the source - ethernet address of the packet. + MAC matching allows you to match packets based on the source + Ethernet address of the packet. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. -netfilter mark match support +Netfilter MARK match support CONFIG_IP_NF_MATCH_MARK Netfilter mark matching allows you to match packets based on the `nfmark' value in the packet. This can be set by the MARK target (see below). If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. Multiple port match support CONFIG_IP_NF_MATCH_MULTIPORT @@ -2048,7 +2420,7 @@ match a single range of ports. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. TTL match support CONFIG_IP_NF_MATCH_TTL @@ -2064,7 +2436,7 @@ specific value or range of values. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. TOS match support CONFIG_IP_NF_MATCH_TOS @@ -2072,7 +2444,7 @@ Service fields of the IP packet. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. Connection state match support CONFIG_IP_NF_MATCH_STATE @@ -2081,23 +2453,23 @@ is a powerful tool for packet classification. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. -Unclean match support (EXPERIMENTAL) +Unclean match support CONFIG_IP_NF_MATCH_UNCLEAN Unclean packet matching matches any strange or invalid packets, by looking at a series of fields in the IP, TCP, UDP and ICMP headers. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. -Owner match support (EXPERIMENTAL) +Owner match support CONFIG_IP_NF_MATCH_OWNER Packet owner matching allows you to match locally-generated packets based on who created them: the user, group, process or session. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. Packet filtering CONFIG_IP_NF_FILTER @@ -2106,7 +2478,7 @@ local output. See the man page for iptables(8). If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. REJECT target support CONFIG_IP_NF_TARGET_REJECT @@ -2115,24 +2487,24 @@ than silently being dropped. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. -MIRROR target support (EXPERIMENTAL) +MIRROR target support CONFIG_IP_NF_TARGET_MIRROR The MIRROR target allows a filtering rule to specify that an incoming packet should be bounced back to the sender. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. -Full NAT +Full NAT (Network Address Translation) CONFIG_IP_NF_NAT The Full NAT option allows masquerading, port forwarding and other forms of full Network Address Port Translation. It is controlled by the `nat' table in iptables: see the man page for iptables(8). If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. MASQUERADE target support CONFIG_IP_NF_TARGET_MASQUERADE @@ -2143,21 +2515,21 @@ address will be different on next dialup). If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. Basic SNMP-ALG support CONFIG_IP_NF_NAT_SNMP_BASIC - This module implements an Application Layer Gateway (ALG) for - SNMP payloads. In conjunction with NAT, it allows a network - management system to access multiple private networks with - conflicting addresses. It works by modifying IP addresses + This module implements an Application Layer Gateway (ALG) for + SNMP payloads. In conjunction with NAT, it allows a network + management system to access multiple private networks with + conflicting addresses. It works by modifying IP addresses inside SNMP payloads to match IP-layer NAT mapping. - + This is the "basic" form of SNMP-ALG, as described in RFC 2962 - + If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. REDIRECT target support CONFIG_IP_NF_TARGET_REDIRECT @@ -2167,7 +2539,7 @@ useful for transparent proxies. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. Packet mangling CONFIG_IP_NF_MANGLE @@ -2176,7 +2548,7 @@ which can effect how the packet is routed. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. TOS target support CONFIG_IP_NF_TARGET_TOS @@ -2185,19 +2557,19 @@ packet prior to routing. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. MARK target support CONFIG_IP_NF_TARGET_MARK This option adds a `MARK' target, which allows you to create rules in the `mangle' table which alter the netfilter mark (nfmark) field - associated with the packet packet prior to routing. This can change - the routing method (see `IP: use netfilter MARK value as routing + associated with the packet prior to routing. This can change + the routing method (see `Use netfilter MARK value as routing key') and can also be used by other subsystems to change their behavior. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. TCPMSS target support CONFIG_IP_NF_TARGET_TCPMSS @@ -2222,16 +2594,16 @@ -j TCPMSS --clamp-mss-to-pmtu If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. -tcpmss match support +TCPMSS match support CONFIG_IP_NF_MATCH_TCPMSS This option adds a `tcpmss' match, which allows you to examine the MSS value of TCP SYN packets, which control the maximum packet size for that connection. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. LOG target support CONFIG_IP_NF_TARGET_LOG @@ -2239,7 +2611,7 @@ any iptables table which records the packet header to the syslog. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. ipchains (2.2-style) support CONFIG_IP_NF_COMPAT_IPCHAINS @@ -2250,7 +2622,7 @@ the ipchains tool exactly as in 2.2 kernels. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. ipfwadm (2.0-style) support CONFIG_IP_NF_COMPAT_IPFWADM @@ -2261,51 +2633,24 @@ the ipfwadm tool exactly as in 2.0 kernels. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -IP6 tables support (required for filtering/masq/NAT) -CONFIG_IP6_NF_IPTABLES - ip6tables is a general, extensible packet identification framework. - Currently only the packet filtering and packet mangling subsystem - for IPv6 use this, but connection tracking is going to follow. - Say 'Y' or 'M' here if you want to use either of those. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -IPv6 limit match support -CONFIG_IP6_NF_MATCH_LIMIT - limit matching allows you to control the rate at which a rule can be - matched: mainly useful in combination with the LOG target ("LOG - target support", below) and to avoid some Denial of Service attacks. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. MAC address match support CONFIG_IP6_NF_MATCH_MAC mac matching allows you to match packets based on the source - ethernet address of the packet. + Ethernet address of the packet. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. -netfilter mark match support +Netfilter MARK match support CONFIG_IP6_NF_MATCH_MARK Netfilter mark matching allows you to match packets based on the `nfmark' value in the packet. This can be set by the MARK target (see below). If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -LOG target support -CONFIG_IP6_NF_TARGET_LOG - This option adds a `LOG' target, which allows you to create rules in - any ip6tables table which records the packet header to the syslog. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. Packet filtering CONFIG_IP6_NF_FILTER @@ -2314,7 +2659,7 @@ local output. See the man page for iptables(8). If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. Packet mangling CONFIG_IP6_NF_MANGLE @@ -2323,38 +2668,38 @@ which can effect how the packet is routed. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. MARK target support CONFIG_IP6_NF_TARGET_MARK This option adds a `MARK' target, which allows you to create rules in the `mangle' table which alter the netfilter mark (nfmark) field associated with the packet packet prior to routing. This can change - the routing method (see `IP: use netfilter MARK value as routing + the routing method (see `Use netfilter MARK value as routing key') and can also be used by other subsystems to change their behavior. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. TCP Explicit Congestion Notification support CONFIG_INET_ECN Explicit Congestion Notification (ECN) allows routers to notify clients about network congestion, resulting in fewer dropped packets - and increased network performance. This option adds ECN support to the - Linux kernel, as well as a sysctl (/proc/sys/net/ipv4/tcp_ecn) which - allows ECN support to be disabled at runtime. + and increased network performance. This option adds ECN support to + the Linux kernel, as well as a sysctl (/proc/sys/net/ipv4/tcp_ecn) + which allows ECN support to be disabled at runtime. Note that, on the Internet, there are many broken firewalls which refuse connections from ECN-enabled machines, and it may be a while - before these firewalls are fixed. Until then, to access a site behind - such a firewall (some of which are major sites, at the time of this - writing) you will have to disable this option, either by saying N now - or by using the sysctl. + before these firewalls are fixed. Until then, to access a site + behind such a firewall (some of which are major sites, at the time + of this writing) you will have to disable this option, either by + saying N now or by using the sysctl. If in doubt, say N. -IP6 tables support (required for filtering/masq/NAT) +IPv6 tables support (required for filtering/masq/NAT) CONFIG_IP6_NF_IPTABLES ip6tables is a general, extensible packet identification framework. Currently only the packet filtering and packet mangling subsystem @@ -2362,7 +2707,7 @@ Say 'Y' or 'M' here if you want to use either of those. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. IPv6 limit match support CONFIG_IP6_NF_MATCH_LIMIT @@ -2371,54 +2716,7 @@ target support", below) and to avoid some Denial of Service attacks. If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -MAC address match support -CONFIG_IP6_NF_MATCH_MAC - mac matching allows you to match packets based on the source - ethernet address of the packet. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -netfilter mark match support -CONFIG_IP6_NF_MATCH_MARK - Netfilter mark matching allows you to match packets based on the - `nfmark' value in the packet. This can be set by the MARK target - (see below). - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -Packet filtering -CONFIG_IP6_NF_FILTER - Packet filtering defines a table `filter', which has a series of - rules for simple packet filtering at local input, forwarding and - local output. See the man page for iptables(8). - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -Packet mangling -CONFIG_IP6_NF_MANGLE - This option adds a `mangle' table to iptables: see the man page for - iptables(8). This table is used for various packet alterations - which can effect how the packet is routed. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. - -MARK target support -CONFIG_IP6_NF_TARGET_MARK - This option adds a `MARK' target, which allows you to create rules - in the `mangle' table which alter the netfilter mark (nfmark) field - associated with the packet packet prior to routing. This can change - the routing method (see `IP: use netfilter MARK value as routing - key') and can also be used by other subsystems to change their - behavior. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `N'. + . If unsure, say `N'. SYN flood protection CONFIG_SYN_COOKIES @@ -2434,8 +2732,7 @@ 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/syncookies.html . + about SYN cookies, check out . 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 @@ -2450,12 +2747,21 @@ you can enable them by saying Y to "/proc file system support" and "Sysctl support" below and executing the command - echo 1 >/proc/sys/net/ipv4/tcp_syncookies + echo 1 >/proc/sys/net/ipv4/tcp_syncookies at boot time after the /proc file system has been mounted. - - If unsure, say Y. + If unsure, say N. + +HCI EMU (virtual device) driver +CONFIG_BLUEZ_HCIEMU + Bluetooth Virtual HCI device driver. + This driver is required if you want to use HCI Emulation software. + + Say Y here to compile support for Virtual HCI devices into the + kernel or say M to compile it as module (hci_usb.o). + +# Choice: alphatype Alpha system type CONFIG_ALPHA_GENERIC This is the system type of your hardware. A "generic" kernel will @@ -2464,7 +2770,7 @@ 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: + . In summary: Alcor/Alpha-XLT AS 600 Alpha-XL XL-233, XL-266 @@ -2476,7 +2782,7 @@ EB64+ EB64+ 21064 evaluation board EB66 EB66 21066 evaluation board EB66+ EB66+ 21066 evaluation board - Jensen DECpc 150, DEC 2000 model 300, + Jensen DECpc 150, DEC 2000 model 300, DEC 2000 model 500 LX164 AlphaPC164-LX Miata Personal Workstation 433a, 433au, 500a, @@ -2496,21 +2802,160 @@ If you don't know what to do, choose "generic". -EV5 CPU daughtercard +# Most of the information on these variants is from +# +Alcor/Alpha-XLT +CONFIG_ALPHA_ALCOR + For systems using the Digital ALCOR chipset: 5 chips (4, 64-bit data + slices (Data Switch, DSW) - 208-pin PQFP and 1 control (Control, I/O + Address, CIA) - a 383 pin plastic PGA). It provides a DRAM + controller (256-bit memory bus) and a PCI interface. It also does + all the work required to support an external Bcache and to maintain + memory coherence when a PCI device DMAs into (or out of) memory. + +Alpha-XL +CONFIG_ALPHA_XL + XL-233 and XL-266-based Alpha systems. + +AlphaBook1 +CONFIG_ALPHA_BOOK1 + Dec AlphaBook1/Burns Alpha-based laptops. + +Avanti +CONFIG_ALPHA_AVANTI + Avanti AS 200, AS 205, AS 250, AS 255, AS 300, and AS 400-based + Alphas. Info at + . + +Cabriolet +CONFIG_ALPHA_CABRIOLET + Cabriolet AlphaPC64, AlphaPCI64 systems. Derived from EB64+ but now + baby-AT with Flash boot ROM, no on-board SCSI or Ethernet. 3 ISA + slots, 4 PCI slots (one pair are on a shared slot), uses plug-in + Bcache SIMMs. Requires power supply with 3.3V output. + +DP264 +CONFIG_ALPHA_DP264 + Various 21264 systems with the tsunami core logic chipset. + API Networks: 264DP, UP2000(+), CS20; + Compaq: DS10(E,L), XP900, XP1000, DS20(E), ES40. + +EB164 +CONFIG_ALPHA_EB164 + EB164 21164 evaluation board from DEC. Uses 21164 and ALCOR. Has + ISA and PCI expansion (3 ISA slots, 2 64-bit PCI slots (one is + shared with an ISA slot) and 2 32-bit PCI slots. Uses plus-in + Bcache SIMMs. I/O sub-system provides SuperI/O (2S, 1P, FD), KBD, + MOUSE (PS2 style), RTC/NVRAM. Boot ROM is Flash. PC-AT-sized + motherboard. Requires power supply with 3.3V output. + +EB64+ +CONFIG_ALPHA_EB64P + Uses 21064 or 21064A and APECs. Has ISA and PCI expansion (3 ISA, + 2 PCI, one pair are on a shared slot). Supports 36-bit DRAM SIMs. + ISA bus generated by Intel SaturnI/O PCI-ISA bridge. On-board SCSI + (NCR 810 on PCI) Ethernet (Digital 21040), KBD, MOUSE (PS2 style), + SuperI/O (2S, 1P, FD), RTC/NVRAM. Boot ROM is EPROM. PC-AT size. + Runs from standard PC power supply. + +EB66 +CONFIG_ALPHA_EB66 + A Digital DS group board. Uses 21066 or 21066A. I/O sub-system is + identical to EB64+. Baby PC-AT size. Runs from standard PC power + supply. The EB66 schematic was published as a marketing poster + advertising the 21066 as "the first microprocessor in the world with + embedded PCI". + +EB66+ +CONFIG_ALPHA_EB66P + Later variant of the EB66 board. + +Eiger +CONFIG_ALPHA_EIGER + Apparently an obscure OEM single-board computer based on the + Typhoon/Tsunami chipset family. Information on it is scanty. + +Jensen +CONFIG_ALPHA_JENSEN + DEC PC 150 AXP (aka Jensen): This is a very old Digital system - one + of the first-generation Alpha systems. A number of these systems + seem to be available on the second- hand market. The Jensen is a + floor-standing tower system which originally used a 150MHz 21064 It + used programmable logic to interface a 486 EISA I/O bridge to the + CPU. + +LX164 +CONFIG_ALPHA_LX164 + A technical overview of this board is available at + . + +Miata +CONFIG_ALPHA_MIATA + The Digital PersonalWorkStation (PWS 433a, 433au, 500a, 500au, 600a, + or 600au). There is an Installation HOWTO for this hardware at + . + +Mikasa +CONFIG_ALPHA_MIKASA + AlphaServer 1000-based Alpha systems. + +Nautilus +CONFIG_ALPHA_NAUTILUS + Alpha systems based on the AMD 751 & ALI 1543C chipsets. + +Noname +CONFIG_ALPHA_NONAME + The AXPpci33 (aka NoName), is based on the EB66 (includes the Multia + UDB). This design was produced by Digital's Technical OEM (TOEM) + group. It uses the 21066 processor running at 166MHz or 233MHz. It + is a baby-AT size, and runs from a standard PC power supply. It has + 5 ISA slots and 3 PCI slots (one pair are a shared slot). There are + 2 versions, with either PS/2 or large DIN connectors for the + keyboard. + +Noritake +CONFIG_ALPHA_NORITAKE + AlphaServer 1000A, AlphaServer 600A, and AlphaServer 800-based + systems. + +Rawhide +CONFIG_ALPHA_RAWHIDE + AlphaServer 1200, AlphaServer 4000 and AlphaServer 4100 machines. + See HOWTO at + . + +Ruffian +CONFIG_ALPHA_RUFFIAN + Samsung APC164UX. There is a page on known problems and workarounds + at . + +Sable +CONFIG_ALPHA_SABLE + Digital AlphaServer 2000 and 2100-based systems. + +Takara +CONFIG_ALPHA_TAKARA + Alpha 11164-based OEM single-board computer. + +Wildfire +CONFIG_ALPHA_WILDFIRE + AlphaServer GS 40/80/160/320 SMP based on the EV67 core. + +EV5 CPU daughtercard (model 5/xxx) CONFIG_ALPHA_PRIMO Say Y if you have an AS 1000 5/xxx or an AS 1000A 5/xxx. -EV5 CPU(s) +EV5 CPU(s) (model 5/xxx) CONFIG_ALPHA_GAMMA Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx. -Using SRM as bootloader +Use 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 @@ -2521,7 +2966,7 @@ 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. + won't be able to boot from an IDE disk using SRM. If unsure, say N. @@ -2530,20 +2975,20 @@ The 2.4 kernel changed the kernel start address from 0x310000 to 0x810000 to make room for the Wildfire's larger SRM console. - If you're using aboot 0.7 or later, the bootloader will examine - the ELF headers to determine where to transfer control. Unfortunately, - most older bootloaders -- APB or MILO -- hardcoded the kernel - start address rather than examining the ELF headers, and the result - is a hard lockup. + If you're using aboot 0.7 or later, the bootloader will examine the + ELF headers to determine where to transfer control. Unfortunately, + most older bootloaders -- APB or MILO -- hardcoded the kernel start + address rather than examining the ELF headers, and the result is a + hard lockup. - Say Y if you have a broken bootloader. Say N if you do not, or - if you wish to run on Wildfire. + Say Y if you have a broken bootloader. Say N if you do not, or if + you wish to run on Wildfire. Large VMALLOC support CONFIG_ALPHA_LARGE_VMALLOC - Process creation and other aspects of virtual memory management - can be streamlined if we restrict the kernel to one PGD for all - vmalloc allocations. This equates to about 8GB. + Process creation and other aspects of virtual memory management can + be streamlined if we restrict the kernel to one PGD for all vmalloc + allocations. This equates to about 8GB. Under normal circumstances, this is so far and above what is needed as to be laughable. However, there are certain applications (such @@ -2559,11 +3004,11 @@ 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. + 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. + kernel: saying N will just cause the configurator to skip all + the questions about non-standard serial boards. Most people can say N here. @@ -2572,10 +3017,10 @@ 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. + 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 + kernel: saying N will just cause the configurator to skip all the questions about serial driver options. If unsure, say N. Support more than 4 serial ports @@ -2583,22 +3028,30 @@ 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://www.linuxdoc.org/docs.html#howto ), or other custom + from ), 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 serial ports defined by ACPI tables +CONFIG_SERIAL_ACPI + Legacy free machines may not have serial ports at the legacy COM1, + COM2 etc addresses. Serial ports on such machines are described by + the ACPI tables SPCR (Serial Port Console Redirection) table and + DBGP (Debug Port) table. Say Y here if you want to include support + for these serial ports. + 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) +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. + 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. @@ -2612,16 +3065,12 @@ servicing. Say Y here to enable the serial driver to take advantage of those special I/O ports. -SGI PROM Console Support -CONFIG_ARC_CONSOLE - Say Y here if you want to use the PROMs for console I/O. - 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) +SGI Newport Graphics support 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 @@ -2651,14 +3100,14 @@ 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 - multi-function ethernet/modem cards. (PCMCIA- or PC-cards are + multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are credit-card size devices often used with laptops.) 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. + The module will be called serial_cs.o. If you want to compile it as + a module, say M here and read . + If unsure, say N. ACP Modem (Mwave) support CONFIG_MWAVE @@ -2685,17 +3134,14 @@ The module will be called mwave.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -/dev/agpgart (AGP Support) (EXPERIMENTAL) +/dev/agpgart (AGP Support) CONFIG_AGP AGP (Accelerated Graphics Port) is a bus system mainly used to - connect graphics cards to the rest of the system. + connect graphics cards to the rest of the system. If you have an AGP system and you say Y here, it will be possible to use the AGP features of your 3D rendering video card. This code acts - as a sort of "AGP driver" for the motherboard's chipset. The glx - module will then be able to program the GART (graphics aperture - relocation table) registers with appropriate values to transfer - commands to the card. + as a sort of "AGP driver" for the motherboard's chipset. If you need more texture memory than you can get with the AGP GART (theoretically up to 256 MB, but in practice usually 64 or 128 MB @@ -2706,47 +3152,42 @@ write-combining with MTRR support on the AGP bus. Without it, OpenGL direct rendering will be a lot slower but still faster than PIO. - For the moment, you should probably say N, unless you want to test - the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ , or need to use the 810 Xserver in - XFree 3.3.6. - - This driver is 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 agpgart.o. + You should say Y here if you use XFree86 3.3.6 or 4.x and want to + use GLX or DRI. If unsure, say N. + + This driver is available as a module. If you want to compile it as + a module, say M here and read . The + module will be called agpgart.o. -Intel 440LX/BX/GX/815/830M/840/850 support +Intel 440LX/BX/GX/815/820/830/840/845/850/860 support CONFIG_AGP_INTEL This option gives you AGP support for the GLX component of the - XFree86 4.x on Intel 440LX/BX/GX, 815, 830M, 840 and 850 chipsets. + XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850 and 860 chipsets. - For the moment, you should probably say N, unless you want to test - the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ . + You should say Y here if you use XFree86 3.3.6 or 4.x and want to + use GLX or DRI. If unsure, say N. -Intel I810/I810 DC100/I810e support +Intel I810/I815 DC100/I810e support CONFIG_AGP_I810 - This option gives you AGP support for the Xserver on the Intel 810, - 830M and 815 chipset boards for their on-board integrated graphics. - This is required to do any useful video modes with these boards. + This option gives you AGP support for the Xserver on the Intel 810 + 815 and 830m chipset boards for their on-board integrated graphics. This + is required to do any useful video modes with these boards. VIA chipset support CONFIG_AGP_VIA This option gives you AGP support for the GLX component of the XFree86 4.x on VIA MPV3/Apollo Pro chipsets. - For the moment, you should probably say N, unless you want to test - the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ . + You should say Y here if you use XFree86 3.3.6 or 4.x and want to + use GLX or DRI. If unsure, say N. AMD Irongate, 761, and 762 support CONFIG_AGP_AMD This option gives you AGP support for the GLX component of the XFree86 4.x on AMD Irongate, 761, and 762 chipsets. - For the moment, you should probably say N, unless you want to test - the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ . + You should say Y here if you use XFree86 3.3.6 or 4.x and want to + use GLX or DRI. If unsure, say N. Generic SiS support CONFIG_AGP_SIS @@ -2756,33 +3197,47 @@ Note that 5591/5592 AGP chipsets are NOT supported. - For the moment, you should probably say N, unless you want to test - the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ . + You should say Y here if you use XFree86 3.3.6 or 4.x and want to + use GLX or DRI. If unsure, say N. -ALI M1541 support +Serverworks LE/HE support +CONFIG_AGP_SWORKS + Say Y here to support the Serverworks AGP card. See + for product descriptions and images. + +ALI chipset support CONFIG_AGP_ALI This option gives you AGP support for the GLX component of the - XFree86 4.x on the ALi M1541 chipset. + XFree86 4.x on the following ALi chipsets. The supported chipsets + include M1541, M1621, M1631, M1632, M1641,M1647,and M1651. + For the ALi-chipset question, ALi suggests you refer to + . - This chipset can do AGP 1x and 2x, but note that there is an + The M1541 chipset can do AGP 1x and 2x, but note that there is an acknowledged incompatibility with Matrox G200 cards. Due to timing issues, this chipset cannot do AGP 2x with the G200. This is a hardware limitation. AGP 1x seems to be fine, though. - For the moment, you should probably say N, unless you want to test - the GLX component for XFree86 3.3.6, which can be downloaded from - http://utah-glx.sourceforge.net/ . + You should say Y here if you use XFree86 3.3.6 or 4.x and want to + use GLX or DRI. If unsure, say N. -PCI support +Support for ISA-bus hardware +CONFIG_ISA + Find out whether you have ISA slots on your motherboard. ISA 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 PCI, EISA, MicroChannel + (MCA) or VESA. ISA is an older system, now being displaced by PCI; + newer boards don't support it. If you have ISA, say Y, otherwise N. + +Support for PCI bus hardware 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. + 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://www.linuxdoc.org/docs.html#howto , contains valuable + , contains valuable information about which PCI hardware does work under Linux and which doesn't. @@ -2790,11 +3245,11 @@ CONFIG_PCI_INTEGRATOR 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. + 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://www.linuxdoc.org/docs.html#howto , contains valuable + , contains valuable information about which PCI hardware does work under Linux and which doesn't. @@ -2802,14 +3257,15 @@ CONFIG_PCI_QSPAN 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. + 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://www.linuxdoc.org/docs.html#howto , contains valuable + , contains valuable information about which PCI hardware does work under Linux and which doesn't. +# Choice: pci_access PCI access mode CONFIG_PCI_GOBIOS On PCI systems, the BIOS can be used to detect the PCI devices and @@ -2838,22 +3294,56 @@ When in doubt, say Y. +PCI Hotplug support +CONFIG_HOTPLUG_PCI + Say Y here if you have a motherboard with a PCI Hotplug controller. + This allows you to add and remove PCI cards while the machine is + powered up and running. The file system pcihpfs must be mounted + in order to interact with any PCI Hotplug controllers. + + 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 pci_hotplug.o. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +PCI Compaq Hotplug controller +CONFIG_HOTPLUG_PCI_COMPAQ + Say Y here if you have a motherboard with a Compaq PCI Hotplug + controller. + + 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 cpqphp.o. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +PCI Compaq Hotplug controller NVRAM support +CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM + Say Y here if you have a Compaq server that has a PCI Hotplug + controller. This will allow the PCI Hotplug driver to store the PCI + system configuration options in NVRAM. + + When in doubt, say N. + 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. + laptops. It is a bus system similar to PCI or ISA. See + (and especially the web page given + there) before attempting to build an MCA bus kernel. -EISA support +Support for EISA-bus hardware CONFIG_EISA The Extended Industry Standard Architecture (EISA) bus was developed as an open alternative to the IBM MicroChannel bus. The EISA bus provided some of the features of the IBM MicroChannel bus while maintaining backward compatibility with cards made for - the older ISA bus. The EISA bus saw limited use between 1988 and 1995 - when it was made obsolete by the PCI bus. + the older ISA bus. The EISA bus saw limited use between 1988 and + 1995 when it was made obsolete by the PCI bus. Say Y here if you are building a kernel for an EISA-based machine. @@ -2866,7 +3356,7 @@ 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. + See for more. SGI Visual Workstation framebuffer support CONFIG_FB_SGIVW @@ -2891,8 +3381,8 @@ 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 i2o_config.o. + . You will get modules called + i2o_core.o and i2o_config.o. If unsure, say N. @@ -2904,7 +3394,7 @@ 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. + here and read . I2O Block OSM CONFIG_I2O_BLOCK @@ -2914,7 +3404,7 @@ 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. + here and read . I2O LAN OSM CONFIG_I2O_LAN @@ -2925,7 +3415,7 @@ 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. + here and read . I2O SCSI OSM CONFIG_I2O_SCSI @@ -2936,7 +3426,7 @@ 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. + here and read . I2O /proc support CONFIG_I2O_PROC @@ -2947,7 +3437,7 @@ 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. + here and read . Plug and Play support CONFIG_PNP @@ -2959,24 +3449,41 @@ 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 say N here and configure your PnP + below. Alternatively, you can say N here and 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. - Some information is in Documentation/isapnp.txt. - + Some information is in . + 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. + here and read . + + If unsure, say Y. + +PNPBIOS support +CONFIG_PNPBIOS + Linux uses the PNPBIOS as defined in "Plug and Play BIOS + Specification Version 1.0A May 5, 1994" to autodetect built-in + mainboard resources (e.g. parallel port resources). + + Other features (e.g. change resources, ESCD, event notification, + Docking station information, ISAPNP services) are not used. + + Note: ACPI is expected to supersede PNPBIOS some day, currently it + co-exists nicely. + + See latest pcmcia-cs (stand-alone package) for a nice "lspnp" tools, + or have a look at /proc/bus/pnp. If unsure, say Y. @@ -2992,50 +3499,50 @@ example, used on modern desktops as well as laptops, is USB. Enable HOTPLUG and KMOD, and build a modular kernel. Get agent - software (at http://linux-hotplug.sourceforge.net) and install it. + software (at ) and install it. Then your kernel will automatically call out to a user mode "policy agent" (/sbin/hotplug) to load modules and set up software needed to use devices as you hotplug them. -PCMCIA/Cardbus support +PCMCIA/CardBus support CONFIG_PCMCIA Say Y here if you want to attach PCMCIA- or PC-cards to your Linux - computer. These are credit-card size devices such as network cards, - modems or hard drives often used with laptops computers. There are + computer. These are credit-card size devices such as network cards, + modems or hard drives often used with laptops computers. There are actually two varieties of these cards: the older 16 bit PCMCIA cards - and the newer 32 bit CardBus cards. If you want to use CardBus + and the newer 32 bit CardBus cards. If you want to use CardBus cards, you need to say Y here and also to "CardBus support" below. - To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file Documentation/Changes for - location). Please also read the PCMCIA-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto + To use your PC-cards, you will need supporting software from David + Hinds' pcmcia-cs package (see the file + for location). Please also read the PCMCIA-HOWTO, available from + . 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. + read . CardBus support CONFIG_CARDBUS - CardBus is a bus mastering architecture for PC-cards, which allows - for 32 bit PC-cards (the original PCMCIA standard specifies only + CardBus is a bus mastering architecture for PC-cards, which allows + for 32 bit PC-cards (the original PCMCIA standard specifies only a 16 bit wide bus). Many newer PC-cards are actually CardBus cards. - To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file Documentation/Changes for - location). + To use your PC-cards, you will need supporting software from David + Hinds' pcmcia-cs package (see the file + for location). If unsure, say Y. -i82365/Yenta compatible bridge support +i82365 compatible bridge support CONFIG_I82365 - Say Y here to 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. - "Bridge" is the name used for the hardware inside your computer that - PCMCIA cards are plugged into. If unsure, say Y. + Say Y here to include support for PCMCIA bridges that are register + compatible with the Intel i82365 specification: this includes + virtually all common PCMCIA bridges that are not 'Yenta' Cardbus + bridges. "Bridge" is the name used for the hardware inside your + computer that PCMCIA cards are plugged into. If unsure, say Y. Databook TCIC host bridge support CONFIG_TCIC @@ -3052,60 +3559,67 @@ 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://www.linuxdoc.org/docs.html#howto ), you'll need to say Y + ), 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://www.linuxdoc.org/docs.html#guide . + . 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 + 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. - + list is in the struct acct in ). 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 + 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 file system 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. + files in . 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. +# Choice: kcore Kernel core (/proc/kcore) format CONFIG_KCORE_ELF - If you enabled support for /proc file system then the file - /proc/kcore will contain the kernel core image. This can be used + If you enabled support for /proc file system 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 - You have two choices here: ELF and A.OUT. Selecting ELF will make + You have two choices here: ELF and A.OUT. 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 the - "-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 + This is especially useful if you have compiled the kernel with the + "-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. +# Choice: kcore +Select a.out format for /proc/kcore +CONFIG_KCORE_AOUT + Not necessary unless you're using a very out-of-date binutils + version. You probably want KCORE_ELF. + Kernel support for ELF binaries CONFIG_BINFMT_ELF ELF (Executable and Linkable Format) is a format for libraries and @@ -3120,21 +3634,21 @@ want to say Y here. Information about ELF is contained in the ELF HOWTO available from - http://www.linuxdoc.org/docs.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). + ld.so (check the file 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. + say M here and read . 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 +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 @@ -3162,12 +3676,17 @@ 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". + "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 SOM binaries +CONFIG_BINFMT_SOM + SOM is a binary executable format inherited from HP/UX. Say Y here + to be able to load and execute SOM binaries directly. + Kernel support for MISC binaries CONFIG_BINFMT_MISC If you say Y here, it will be possible to plug wrapper-driven binary @@ -3175,15 +3694,15 @@ 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://www.linuxdoc.org/docs.html#howto ). Once you have + ). 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. + to learn how to use this + feature, and for information about how + to include Java support. You must say Y to "/proc file system support" (CONFIG_PROC_FS) to use this part of the kernel. @@ -3192,16 +3711,33 @@ 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) +Kernel support for JAVA binaries +CONFIG_BINFMT_JAVA + If you say Y here, the kernel will load and execute Java J-code + binaries directly. Note: this option is obsolete and scheduled for + removal, use CONFIG_BINFMT_MISC instead. + +Solaris binary emulation CONFIG_SOLARIS_EMUL This is experimental code which will enable you to run (many) - Solaris binaries on your SPARC Linux machine. + 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. + module, say M here and read . + +SUN SME environment monitoring +CONFIG_ENVCTRL + Kernel support for temperature and fan monitoring on Sun SME + machines. + + 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 envctrl.o. If you want to compile it as a + module, say M here and read . +# Choice: x86 Processor family CONFIG_M386 This is the processor type of your CPU. This information is used for @@ -3215,17 +3751,17 @@ Here are the settings recommended for greatest speed: - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI - 486DLC/DLC2, UMC 486SX-S and NexGen Nx586. Only "386" kernels will - run on a 386 class machine. + 486DLC/DLC2, UMC 486SX-S and NexGen Nx586. 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 and UMC U5D or U5S. - - "586" for generic Pentium CPUs, possibly lacking the TSC + - "586" for generic Pentium CPUs, possibly lacking the TSC (time stamp counter) register. - "Pentium-Classic" for the Intel Pentium. - "Pentium-MMX" for the Intel Pentium MMX. - "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II. - "Pentium-III" for the Intel Pentium III - and Celerons based on the coppermine core. + and Celerons based on the Coppermine core. - "Pentium-4" for the Intel Pentium 4. - "K6" for the AMD K6, K6-II and K6-III (aka K6-3D). - "Athlon" for the AMD K7 family (Athlon/Duron/Thunderbird). @@ -3237,18 +3773,54 @@ If you don't know what to do, choose "386". +486 +CONFIG_M486 + Select this for a x486 processor, ether Intel or one of the + compatible processors from AMD, Cyrix, IBM, or Intel. Includes DX, + DX2, and DX4 variants; also SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or + U5S. + +586/K5/5x86/6x86/6x86MX +CONFIG_M586 + Select this for an x586 or x686 processor such as the AMD K5, the + Intel 5x86 or 6x86, or the Intel 6x86MX. This choice does not + assume the RDTSC instruction. + +Pentium Classic +CONFIG_M586TSC + Select this for a Pentium Classic processor with the RDTSC (Read + Time Stamp Counter) instruction for benchmarking. + +32-bit PDC +CONFIG_PDC_NARROW + Saying Y here will allow developers with a C180, C200, C240, C360, + J200, J210, and/or a J2240 to test 64-bit kernels by providing a + wrapper for the 32-bit PDC calls. Since the machines which require + this option do not support over 4G of RAM, this option is targeted + for developers of these machines wishing to test changes on both + 32-bit and 64-bit configurations. + + If unsure, say N. + 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. + 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. +Distribute interrupts on all CPUs by default +CONFIG_IRQ_ALL_CPUS + This option gives the kernel permission to distribute IRQs across + multiple CPUs. Saying N here will route all IRQs to the first + CPU. Generally SMP PowerMacs can answer Y. SMP IBM CHRP boxes or + Power3 boxes should say N for now. + Video mode selection support CONFIG_VIDEO_SELECT This enables support for text mode selection on kernel startup. If @@ -3260,16 +3832,16 @@ "man bootparam" or see the documentation of your boot loader about how to pass options to the kernel.) - Read the file Documentation/svga.txt for more information about the - Video mode selection support. If unsure, say N. + Read the file for more information + about the Video mode selection support. If unsure, say N. -Support for frame buffer devices (EXPERIMENTAL) +Support for frame buffer devices 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. + 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 @@ -3277,14 +3849,14 @@ 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 + buffer devices. Please read + and the Framebuffer-HOWTO at + for more information. Say Y here and to the driver for your graphics board below if you @@ -3302,6 +3874,27 @@ hardware found in Acorn RISC PCs and other ARM-based machines. If unsure, say N. +Permedia2 support +CONFIG_FB_PM2 + This is the frame buffer device driver for the Permedia2 AGP frame + buffer card from ASK, aka `Graphic Blaster Exxtreme'. There is a + product page at + . + +Enable FIFO disconnect feature +CONFIG_FB_PM2_FIFO_DISCONNECT + Support the Permedia2 FIFOI disconnect feature (see CONFIG_FB_PM2). + +Generic Permedia2 PCI board support +CONFIG_FB_PM2_PCI + Say Y to enable support for Permedia2 AGP frame buffer card from + 3Dlabs (aka `Graphic Blaster Exxtreme') on the PCI bus. + +Phase5 CVisionPPC/BVisionPPC support +CONFIG_FB_PM2_CVPPC + Say Y to enable support for the Amiga Phase 5 CVisionPPC BVisionPPC + framebuffer cards. Phase 5 is no longer with us, alas. + Amiga native chipset support CONFIG_FB_AMIGA This is the frame buffer device driver for the builtin graphics @@ -3310,7 +3903,7 @@ 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 amifb.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . Amiga OCS chipset support CONFIG_FB_AMIGA_OCS @@ -3348,7 +3941,7 @@ Say Y if you have a NetWinder or a graphics card containing this device, otherwise say N. -Amiga CyberVision3D support (EXPERIMENTAL) +Amiga CyberVision3D support 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 @@ -3357,13 +3950,13 @@ kernel. Please note that this driver DOES NOT support the older Cybervision 64 card, as they use incompatible video chips. -Amiga RetinaZ3 support (EXPERIMENTAL) +Amiga RetinaZ3 support 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) +Cirrus Logic generic driver 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. @@ -3371,21 +3964,17 @@ 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. + Please read the file . 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 +Apollo 3c505 "EtherLink Plus" 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, @@ -3397,16 +3986,21 @@ This is the frame buffer device driver for the builtin graphics chipset found in Ataris. -Open Firmware frame buffer device support +Amiga FrameMaster II/Rainbow II support +CONFIG_FB_FM2 + This is the frame buffer device driver for the Amiga FrameMaster + card from BSC (exhibited 1992 but not shipped as a CBM product). + +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 +S3 Trio frame buffer device support CONFIG_FB_S3TRIO - If you have a S3 Trio say Y. Say N for S3 Virge. + If you have a S3 Trio say Y. Say N for S3 Virge. -3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL) +3Dfx Banshee/Voodoo3 display support CONFIG_FB_3DFX This driver supports graphics boards with the 3Dfx Banshee/Voodoo3 chips. Say Y if you have such a graphics board. @@ -3414,9 +4008,9 @@ 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 tdfxfb.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . -nVidia Riva support (EXPERIMENTAL) +nVidia Riva support CONFIG_FB_RIVA This driver supports graphics boards with the nVidia Riva/Geforce chips. @@ -3425,9 +4019,9 @@ 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 rivafb.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . -ATI Mach64 display support (EXPERIMENTAL) +ATI Mach64 display support CONFIG_FB_ATY This driver supports graphics boards with the ATI Mach64 chips. Say Y if you have such a graphics board. @@ -3435,30 +4029,54 @@ 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. - -ATI Mach64 GX display support (EXPERIMENTAL) -CONFIG_FB_ATY_GX - This options adds support for the first generation ATI Mach64 - graphics chips, i.e. the Mach64 GX and CX. Note that this support is - limited. - -ATI Mach64 CT/VT/GT/LT display support (EXPERIMENTAL) -CONFIG_FB_ATY_CT - This option adss support for ATI Mach64 graphics chips starting - with the Mach64 CT family. This includes the Mach64 VT (limited - support), GT (3D RAGE family), and LT. + module, say M here and read . -ATI Rage128 display support (EXPERIMENTAL) +ATI Rage128 display support CONFIG_FB_ATY128 This driver supports graphics boards with the ATI Rage128 chips. Say Y if you have such a graphics board and read - Documentation/fb/aty128fb.txt. + . 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 aty128fb.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . + +# AC tree only +Maxine (Personal DECstation) onboard framebuffer support +CONFIG_FB_MAXINE + Say Y here to directly support the on-board framebuffer in the + Maxine (5000/20, /25, /33) version of the DECstation. There is a + page dedicated to Linux on DECstations at . + +# AC tree only +PMAG-BA TURBOchannel framebuffer support +CONFIG_FB_PMAG_BA + Say Y here to directly support the on-board PMAG-BA framebuffer in + the 5000/1xx versions of the DECstation. There is a page dedicated + to Linux on DECstations at . + +# AC tree only +PMAGB-B TURBOchannel framebuffer support +CONFIG_FB_PMAGB_B + Say Y here to directly support the on-board PMAGB-B framebuffer in + the 5000/1xx versions of the DECstation. There is a page dedicated + to Linux on DECstations at . + +FutureTV PCI card +CONFIG_ARCH_FTVPCI + Say Y here if you intend to run this kernel on a FutureTV (nee Nexus + Electronics) StrongARM PCI card. + +P720T +CONFIG_ARCH_P720T + Say Y here if you intend to run this kernel on the ARM Prospector + 720T. + +Link-Up Systems LCD support +CONFIG_FB_L7200 + This driver supports the L7200 Color LCD. + Say Y if you want graphics support. PowerMac "control" frame buffer device support CONFIG_FB_CONTROL @@ -3490,13 +4108,13 @@ 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. + read . If unsure, say Y. VGA 16-color planar support CONFIG_FBCON_VGA_PLANES This low level frame buffer console driver enable the kernel to use the 16-color planar modes of the old VGA cards where the bits of - each pixel are separated into 4 planes. + each pixel are separated into 4 planes. Only answer Y here if you have a (very old) VGA card that isn't VESA 2 compatible. @@ -3509,7 +4127,29 @@ 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. + . The module will be called + vga16fb.o. + +Generic STI frame buffer device support +CONFIG_FB_STI + STI refers to the HP "Standard Text Interface" which is a set of + BIOS routines contained in a ROM chip in HP PA-RISC based machines. + Enabling this option will implement the linux framebuffer device and + an fbcon color text console using calls to the STI BIOS routines. + The HP framebuffer device is usually planar, uses a strange memory + layout, and changing the plane mask to create colored pixels + requires a call to the STI routines, so do not expect /dev/fb to + actually be useful. However, it is the best we have as far as + graphics on the HP chipsets due to lack of hardware level + documentation for the various on-board HP chipsets used in these + systems. It is sufficient for basic text console functions, + including fonts. + + You should probably enable this option, unless you are having + trouble getting video when booting the kernel (make sure it isn't + just that you are running the console on the serial port, though). + Really old HP boxes may not have STI, and must use the PDC BIOS + console or the IODC BIOS. Select other compiled-in fonts CONFIG_FBCON_FONTS @@ -3517,7 +4157,7 @@ your frame buffer console usually use. Note that the answer to this question won't directly affect the - kernel: saying N will just cause this configure script to skip all + kernel: saying N will just cause the configurator to skip all the questions about foreign fonts. If unsure, say N (the default choices are safe). @@ -3549,14 +4189,29 @@ VGA 8x8 font CONFIG_FONT_8x8 This is the "high resolution" font for the VGA frame buffer (the one - provided by the text console 80x50 (and higher) modes). + provided by the text console 80x50 (and higher) modes). Note that this is a poor quality font. The VGA 8x16 font is quite a - lot more readable. + lot more readable. Given the resolution provided by the frame buffer device, answer N here is safe. +Mac console 6x11 font (not supported by all drivers) +CONFIG_FONT_6x11 + Small console font with Macintosh-style high-half glyphs. Some Mac + framebuffer drivers don't support this one at all. + +Pearl (old m68k) console 8x8 font +CONFIG_FONT_PEARL_8x8 + Small console font with PC-style control-character and high-half + glyphs. + +Acorn console 8x8 font +CONFIG_FONT_ACORN_8x8 + Small console font with PC-style control characters and high-half + glyphs. + Backward compatibility mode for Xpmac CONFIG_FB_COMPAT_XPMAC If you use the Xpmac X server (common with mklinux), you'll need to @@ -3564,35 +4219,61 @@ includes a server that supports the frame buffer device directly (XF68_FBDev). -HGA monochrome support (EXPERIMENTAL) +Hercules (HGA) mono graphics support CONFIG_FB_HGA Say Y here if you have a Hercules mono graphics card. 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 hgafb.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read . As this card technology is 15 years old, most people will answer N here. +Epson 1355 framebuffer support +CONFIG_FB_E1355 + Build in support for the SED1355 Epson Research Embedded RAMDAC + LCD/CRT Controller (since redesignated as the S1D13505) as a + framebuffer. Product specs at + . + +Dreamcast Frame Buffer support +CONFIG_FB_DC + Say Y here to enable support for the framebuffer on the Sega + Dreamcast. This driver is also available as a module, dcfb.o. + +Register Base Address +CONFIG_E1355_REG_BASE + Epson SED1355/S1D13505 LCD/CRT controller register base address. + See the manuals at + for + discussion. + +Framebuffer Base Address +CONFIG_E1355_FB_BASE + Epson SED1355/S1D13505 LCD/CRT controller memory base address. See + the manuals at + for + discussion. + NEC PowerVR 2 display support CONFIG_FB_PVR2 - Say Y here if you have a PowerVR 2 card in your box. If you plan to - run linux on your Dreamcast, you will have to say Y here. This driver - may or may not work on other PowerVR 2 cards, but is totally untested. - Use at your own risk. If unsure, say N. + Say Y here if you have a PowerVR 2 card in your box. If you plan to + run linux on your Dreamcast, you will have to say Y here. + This driver may or may not work on other PowerVR 2 cards, but is + totally untested. Use at your own risk. If unsure, say N. 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 pvr2fb.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + The module will be called pvr2fb.o. If you want to compile it as + a module, say M here and read . You can pass several parameters to the driver at boot time or at - module load time. The parameters look like "video=pvr2:XXX", where + module load time. The parameters look like "video=pvr2:XXX", where the meaning of XXX can be found at the end of the main source file - (drivers/video/pvr2fb.c). Please see the file - Documentation/fb/pvr2fb.txt. + (). Please see the file + . Debug pvr2fb CONFIG_FB_PVR2_DEBUG @@ -3600,26 +4281,26 @@ messages. Most people will want to say N here. If unsure, you will also want to say N. -Matrox unified accelerated driver (EXPERIMENTAL) +Matrox unified accelerated driver CONFIG_FB_MATROX Say Y here if you have a Matrox Millennium, Matrox Millennium II, Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video, - Matrox G400 or G450 card in your box. At this time, support for the G100 - is untested and support for G450 is highly experimental. + Matrox G400 or G450 card in your box. At this time, support for the + G100 is untested and support for G450 is highly experimental. 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. + a module, say M here and read . 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. + (). Please see + . -Matrox Millennium support +Matrox Millennium I/II 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, @@ -3638,9 +4319,9 @@ Matrox G100/G200/G400/G450 support CONFIG_FB_MATROX_G100 Say Y here if you have a Matrox G100, G200, G400 or G450 based - 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 + 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. If you need support for G400 secondary head, you must first say Y to @@ -3654,14 +4335,14 @@ DDC (I2C) bus present on all Matroxes, an I2C bus which interconnects Matrox optional devices, like MGA-TVO on G200 and G400, and the secondary head DDC bus, present on G400 only. - - You can say Y or M here if you want to experiment with monitor + + You can say Y or M here if you want to experiment with monitor detection code. You must say Y or M here if you want to use either second head of G400 or MGA-TVO on G200 or G400. - + If you compile it as module, it will create a module named i2c-matroxfb.o. - + Matrox G400 second head support CONFIG_FB_MATROX_MAVEN WARNING !!! This support does not work with G450 !!! @@ -3672,26 +4353,24 @@ secondary head output is blanked while you are in X. With XFree 3.9.17 preview you can use both heads if you use SVGA over fbdev or the fbdev driver on first head and the fbdev driver on second head. - + If you compile it as module, two modules are created, matroxfb_crtc2.o and matroxfb_maven.o. Matroxfb_maven is needed for both G200 and G400, matroxfb_crtc2 is needed only by G400. You must also load i2c-matroxfb to get it to run. - + The driver starts in monitor mode and you must use the matroxset - tool (available at ftp://platan.vc.cvut.cz/pub/linux/matrox-latest) - to switch it to PAL or NTSC or to swap primary and secondary head - outputs. Secondary head driver also always start in 640x480 - resolution, you must use fbset to change it. - + tool (available at + ) to switch it to + PAL or NTSC or to swap primary and secondary head outputs. + Secondary head driver also always start in 640x480 resolution, you + must use fbset to change it. + Also do not forget that second head supports only 16 and 32 bpp packed pixels, so it is a good idea to compile them into the kernel - too. You can use only some font widths, as the driver uses generic + too. You can use only some font widths, as the driver uses generic painting procedures (the secondary head does not use acceleration engine). - - There is no need for enabling 'Matrox multihead support' if you have - only one Matrox card in the box. Matrox G450 second head support CONFIG_FB_MATROX_G450 @@ -3703,10 +4382,10 @@ want two independent display devices. The driver starts in monitor mode and currently does not support - output in TV modes. You must use the matroxset tool (available - at ftp://platan.vc.cvut.cz/pub/linux/matrox-latest) to swap primary - and secondary head outputs. Secondary head driver always start in - 640x480 resolution and you must use fbset to change it. + output in TV modes. You must use the matroxset tool (available + at ) to swap + primary and secondary head outputs. Secondary head driver always + start in 640x480 resolution and you must use fbset to change it. Also do not forget that second head supports only 16 and 32 bpp packed pixels, so it is a good idea to compile them into the kernel @@ -3714,9 +4393,6 @@ painting procedures (the secondary head does not use acceleration engine). - There is no need for enabling 'Matrox multihead support' if you have - only one Matrox card in the box. - Matrox unified driver multihead support CONFIG_FB_MATROX_MULTIHEAD Say Y here if you have more than one (supported) Matrox device in @@ -3732,6 +4408,24 @@ for the different Matrox devices. This method is slightly faster but uses 40 KB of kernel memory per Matrox card. + There is no need for enabling 'Matrox multihead support' if you have + only one Matrox card in the box. + +3Dfx Voodoo Graphics / Voodoo2 frame buffer support +CONFIG_FB_VOODOO1 + Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or + Voodoo2 (cvg) based graphics card. + + 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 sstfb.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + + WARNING: Do not use any application that uses the 3D engine + (namely glide) while using this driver. + Please read the file Documentation/fb/README-sstfb.txt for supported + options and other important info support. + MDA text console (dual-headed) CONFIG_MDA_CONSOLE Say Y here if you have an old MDA or monochrome Hercules graphics @@ -3739,15 +4433,15 @@ 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. - + a module, say M here and read . + If unsure, say N. -SBUS and UPA frame buffers +SBUS and UPA framebuffers CONFIG_FB_SBUS Say Y if you want support for SBUS or UPA based frame buffer device. @@ -3769,11 +4463,59 @@ CONFIG_FB_CGTHREE This is the frame buffer device driver for the CGthree frame buffer. +CGfourteen (SX) support +CONFIG_FB_CGFOURTEEN + This is the frame buffer device driver for the CGfourteen frame + buffer on Desktop SPARCsystems with the SX graphics option. + +P9100 (Sparcbook 3 only) support +CONFIG_FB_P9100 + This is the frame buffer device driver for the P9100 card + supported on Sparcbook 3 machines. + +Leo (ZX) support +CONFIG_FB_LEO + This is the frame buffer device driver for the SBUS-based Sun ZX + (leo) frame buffer cards. + +IGA 168x display support +CONFIG_FB_IGA + This is the framebuffer device for the INTERGRAPHICS 1680 and + successor frame buffer cards. + TCX (SS4/SS5 only) support CONFIG_FB_TCX This is the frame buffer device driver for the TCX 24/8bit frame buffer. +HD64461 Frame Buffer support +CONFIG_FB_HIT + This is the frame buffer device driver for the Hitachi HD64461 LCD + frame buffer card. + +SIS 630/540 display support +CONFIG_FB_SIS + This is the frame buffer device driver for the SiS 630 and 640 Super + Socket 7 UMA cards. Specs available at . + +# AC tree only +SIS 630/540/730 support +CONFIG_FB_SIS_300 + This is the frame buffer device driver for the SiS 630 and related + Super Socket 7 UMA cards. Specs available at + . + +# AC tree only +SIS 315H/315 support +CONFIG_FB_SIS_315 + This is the frame buffer device driver for the SiS 315 graphics + card. Specs available at . + +IMS Twin Turbo display support +CONFIG_FB_IMSTT + The IMS Twin Turbo is a PCI-based frame buffer card bundled with + many Macintosh and compatible computers. + Virtual Frame Buffer support (ONLY FOR TESTING!) CONFIG_FB_VIRTUAL This is a `virtual' frame buffer device. It operates on a chunk of @@ -3788,13 +4530,48 @@ 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. - + say M here and read . + If unsure, say N. +Mach64 CT/VT/GT/LT (incl. 3D RAGE) support +CONFIG_FB_ATY_CT + Say Y here to support use of ATI's 64-bit Rage boards (or other + boards based on the Mach64 CT, VT, GT, and LT chipsets) as a + framebuffer device. The ATI product support page for these boards + is at . + +Sony Vaio Picturebook laptop LCD panel support +CONFIG_FB_ATY_CT_VAIO_LCD + Say Y here if you want to use the full width of the Sony Vaio + Picturebook laptops LCD panels (you will get a 128x30 console). + + Note that you need to activate this mode using the 'vga=0x301' + option from your boot loader (lilo or loadlin). See the + documentation of your boot loader about how to pass options to the + kernel. + +Mach64 GX support +CONFIG_FB_ATY_GX + Say Y here to support use of the ATI Mach64 Graphics Expression + board (or other boards based on the Mach64 GX chipset) as a + framebuffer device. The ATI product support page for these boards + is at + . + +# AC tree only +ATI Radeon display support +CONFIG_FB_RADEON + Choose this option if you want to use an ATI Radeon graphics card as + a framebuffer device. There are both PCI and AGP versions. You + don't need to choose this to run the Radeon in plain VGA mode. + There is a product page at + . + +SA-1100 LCD support CONFIG_FB_SA1100 This is a framebuffer device for the SA-1100 LCD Controller. - See http://www.linux-fbdev.org/ for information on framebuffer + See for information on framebuffer devices. If you plan to use the LCD display with your SA-1100 system, say @@ -3819,8 +4596,8 @@ 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. - + (some of) them as modules, read . + If unsure, say N. Monochrome support @@ -3890,10 +4667,10 @@ 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. - -HGA monochrome support (EXPERIMENTAL) + +HGA monochrome support CONFIG_FBCON_HGA - This is the low level frame buffer console driver for Hercules mono + This is the low level frame buffer console driver for Hercules mono graphics cards. VGA characters/attributes support @@ -3909,21 +4686,21 @@ 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/parport/BUGS-parport. + and drivers/parport/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. + to the parallel port see 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/parport.txt. + 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 + . 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 . If unsure, say Y. @@ -3931,20 +4708,21 @@ 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. + ports. - This code is also available as a module. If you want to compile it + 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. - + . The module will be called + parport_pc.o. + If unsure, say Y. Parallel+serial PCI card support CONFIG_PARPORT_SERIAL - This adds support for multi-IO PCI cards that have parallel and serial - ports. You should say Y or M here. If you say M, the module will be - called parport_serial.o. + This adds support for multi-IO PCI cards that have parallel and + serial ports. You should say Y or M here. If you say M, the module + will be called parport_serial.o. Use FIFO/DMA if available CONFIG_PARPORT_PC_FIFO @@ -3952,12 +4730,12 @@ 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, + 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. + FIFO. See to find out how to + specify which IRQ/DMA to use. -SuperIO chipset support (EXPERIMENTAL) +SuperIO chipset support CONFIG_PARPORT_PC_SUPERIO Saying Y here enables some probes for Super-IO chipsets in order to find out things like base addresses, IRQ lines and DMA channels. It @@ -3974,12 +4752,6 @@ 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. - Amiga built-in parallel port support CONFIG_PARPORT_AMIGA Say Y here if you need support for the parallel port hardware on @@ -3992,51 +4764,51 @@ Atari machines. This code is also available as a module (say M), called parport_atari.o. If in doubt, saying N is the safe plan. -Multiface 3 parallel port card support +Multiface III parallel port support CONFIG_PARPORT_MFC3 Say Y here if you need parallel port support for the MFC3 card. This code is also available as a module (say M), called parport_mfc3.o. If in doubt, saying N is the safe plan. -Support IEEE1284 status readback +Support IEEE 1284 status readback CONFIG_PRINTER_READBACK If you have a device on your parallel port that support this protocol, this option will allow the device to report its status. It is safe to say Y. -IEEE1284 transfer modes +IEEE 1284 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. + , 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 + 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 + the modutils package (check the file + 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. + 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 @@ -4048,11 +4820,11 @@ 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. + in . -ARP daemon support (EXPERIMENTAL) +ARP daemon support CONFIG_ARPD - Normally, the kernel maintains an internal cache which maps IP + 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 @@ -4060,7 +4832,7 @@ 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. + 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 @@ -4084,35 +4856,35 @@ For an excellent introduction to Linux networking, please read the NET-3-HOWTO, available from - http://www.linuxdoc.org/docs.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 file system 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 +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 + . 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. + . For most people, it's + safe to say N. -IP: advanced router +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 @@ -4120,7 +4892,7 @@ 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 + answering N will just cause the configurator to skip all the questions about advanced routing. Note that your box can only act as a router if you enable IP @@ -4130,7 +4902,7 @@ echo "1" > /proc/sys/net/ipv4/ip_forward - at boot time after the /proc file system has been mounted. + at boot time after the /proc file system 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 @@ -4148,26 +4920,27 @@ If unsure, say N here. -IP: policy routing +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 + address into account. Furthermore, if you also say Y to "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, + you say Y here and to "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/ - + documentation at + and . + You will need supporting software from + . + If unsure, say N. - -IP: equal cost multipath + +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 @@ -4177,20 +4950,20 @@ equal "cost" and chooses one of them in a non-deterministic fashion if a matching packet arrives. -IP: use TOS value as routing key +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. + 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 netfilter MARK value as routing key +Use netfilter MARK 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 mark values (see iptables(8), MARK target). -IP: verbose route monitoring +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 @@ -4199,20 +4972,20 @@ handled by the klogd daemon which is responsible for kernel messages ("man klogd"). -IP: large routing tables +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 +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 + 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: kernel level autoconfiguration +Kernel level IP 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 @@ -4233,7 +5006,22 @@ 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. + Read for details. + +DHCP support +CONFIG_IP_PNP_DHCP + If you want your Linux box to mount its whole root file system (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 DHCP 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 DHCP 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 DHCP, a DHCP server + must be operating on your network. Read + for details. RARP support CONFIG_IP_PNP_RARP @@ -4243,10 +5031,10 @@ 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 + operating on your network. Read for details. -IP: tunneling +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 @@ -4256,13 +5044,13 @@ 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 +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 @@ -4270,18 +5058,18 @@ 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: + 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 +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. + to do that, say Y here and to "IP multicast routing" below. -IP: multicast routing +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 @@ -4289,118 +5077,69 @@ 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. + . If you haven't heard + about it, you don't need it. -IP: PIM-SM version 1 support +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 + (pimd-v1). Please see 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 +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 - Documentation/networking/ncsa-telnet. - -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 + 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 + 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. + whenever you want). If you want to compile it as a module, say M + here and read . 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) +The IPv6 protocol 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 ; + IPv6, see ; 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. + 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. + given in . 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. + as a module, say M here and read . It is safe to say N here for now. @@ -4410,8 +5149,8 @@ through the old netlink interface. However, a better option is to say Y to "Kernel/User network link driver" and to "Routing messages" instead. - -Kernel httpd acceleration (EXPERIMENTAL) + +Kernel httpd acceleration CONFIG_KHTTPD The kernel httpd acceleration daemon (kHTTPd) is a (limited) web server built into the kernel. It is limited since it can only serve @@ -4430,17 +5169,17 @@ The kHTTPd is experimental. Be careful when using it on a production machine. Also note that kHTTPd doesn't support virtual servers yet. -IPX networking +The IPX protocol 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 + 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://www.linuxdoc.org/docs.html#howto ). In order to do the - former, you'll also have to say Y to "NCP file system support", - below. + ) or from + within the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, + available from ). In order + to do the former, you'll also have to say Y to "NCP file system + 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 @@ -4448,22 +5187,22 @@ 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://www.linuxdoc.org/docs.html#howto . + or + mars_nwe from . For more + information, read the IPX-HOWTO available from + . General information about how to connect Linux, Windows machines and - Macs is on the WWW at http://www.eats.com/linux_mac_win.html . + Macs is on the WWW at . 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. + 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 . Unless you want to + integrate your Linux box with a local Novell network, say N. -IPX: Full internal IPX network +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 @@ -4472,7 +5211,7 @@ 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://www.linuxdoc.org/docs.html#howto for details. + for details. The full internal IPX network enables you to allocate sockets on different virtual nodes of the internal network. This is done by @@ -4485,12 +5224,17 @@ '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 . + can be found on . If you don't know what you are doing, say N. -IPX: SPX networking (EXPERIMENTAL) +#(We're told this will come back someday) + +SPX networking CONFIG_SPX + * Orphaned entry retained 20 April 2001 by Petr Vandrovec * + * If you read this note from the configurator, please contact * + * the Configure.help maintainers. * 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 @@ -4502,26 +5246,26 @@ 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://www.linuxdoc.org/docs.html#howto for details. + 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. + module, say M here and read . -DECnet networking (EXPERIMENTAL) +DECnet networking CONFIG_DECNET The DECnet networking protocol was used in many products made by - Digital (now Compaq). It provides reliable stream and sequenced + 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/ + look at Patrick Caulfield's web site: + . - More detailed documentation is available in the - Documentation/networking/decnet.txt file. + More detailed documentation is available in + . Be sure to say Y to "/proc file system support" and "Sysctl support" below when using DECnet, since you will need sysctl support to aid @@ -4533,27 +5277,27 @@ 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. + 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. -DECnet Router Support (EXPERIMENTAL) + If unsure, say N. + +DECnet router support 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 - say Y here, then make sure that you also say Y to "Kernel/User - network link driver", "Routing messages" and "Network packet - filtering". The first two are required to allow configuration via - rtnetlink (currently you need Alexey Kuznetsov's iproute2 package - from ftp://ftp.inr.ac.ru). The "Network packet filtering" option - will be required for the forthcoming routing daemon to work. + 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 say Y here, then make sure that you also say Y to "Kernel/User + network link driver", "Routing messages" and "Network packet + filtering". The first two are required to allow configuration via + rtnetlink (currently you need Alexey Kuznetsov's iproute2 package + from ). The "Network packet filtering" option + will be required for the forthcoming routing daemon to work. - See Documentation/networking/decnet.txt for more information. + See for more information. -DECnet: use FWMARK value as routing key +Use FWMARK value as DECnet routing key CONFIG_DECNET_ROUTE_FWMARK If you say Y here, you will be able to specify different routes for packets with different FWMARK ("firewalling mark") values @@ -4568,28 +5312,29 @@ AppleTalk protocol support 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 + 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://www.zettabyte.net/netatalk/ 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. + server for Macs as well as access AppleTalk printers. Check out + 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 + Macs is on the WWW at . The NET-3-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , contains valuable + , 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. You almost - certainly want to compile it as a module so you can restart your - AppleTalk stack without rebooting your machine. I hear that the - GNU boycott of Apple is over, so even politically correct people + The module is called appletalk.o. If you want to compile it as a + module, say M here and read . You + almost certainly want to compile it as a module so you can restart + your AppleTalk stack without rebooting your machine. 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 @@ -4600,7 +5345,7 @@ 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. + 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 @@ -4609,11 +5354,11 @@ 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. + running kernel whenever you want, read + ). 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 @@ -4621,20 +5366,20 @@ 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. + 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. + Please see 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 @@ -4643,7 +5388,7 @@ 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. + See the file . COPS LocalTalk PC card support CONFIG_COPS @@ -4652,7 +5397,7 @@ 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. + Please read the file . Dayna firmware support CONFIG_COPS_DAYNA @@ -4668,15 +5413,15 @@ 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 + here. You want to read and the HAM-HOWTO and the AX25-HOWTO, both available from - http://www.linuxdoc.org/docs.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 + kernel: saying N will just cause the configurator to skip all the questions about amateur radio. -Amateur Radio AX.25 Level 2 +Amateur Radio AX.25 Level 2 protocol 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 @@ -4694,15 +5439,16 @@ 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://www.linuxdoc.org/docs.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 . + . You might also want to + check out the file in the + kernel source. More information about digital amateur radio in + general is on the WWW at + . 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. + module, say M here and read . AX.25 DAMA Slave support CONFIG_AX25_DAMA_SLAVE @@ -4722,7 +5468,7 @@ slaves. If you say Y here, your Linux box will act as a DAMA server. If unsure, say N. -Amateur Radio NET/ROM +Amateur Radio NET/ROM support CONFIG_NETROM NET/ROM is a network layer protocol on top of AX.25 useful for routing. @@ -4730,15 +5476,15 @@ 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://www.linuxdoc.org/docs.html#howto . You also might want to - check out the file Documentation/networking/ax25.txt. More + . You also might want to + check out the file . 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. + module, say M here and read . Amateur Radio X.25 PLP (Rose) CONFIG_ROSE @@ -4749,15 +5495,15 @@ 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://www.linuxdoc.org/docs.html#howto . You also might want to - check out the file Documentation/networking/ax25.txt. More + . You also might want to + check out the file . 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. + module, say M here and read . Serial port KISS driver for AX.25 CONFIG_MKISS @@ -4773,8 +5519,8 @@ 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. + say M here and read . The module + will be called mkiss.o. Serial port 6PACK driver for AX.25 CONFIG_6PACK @@ -4787,12 +5533,12 @@ 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. + driver, read . 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. + say M here and read . The module + will be called 6pack.o. BPQ Ethernet driver CONFIG_BPQETHER @@ -4813,7 +5559,7 @@ Currently, this driver supports Ottawa PI/PI2, Paccomm/Gracilis PackeTwin, and S5SCC/DMA boards. They are detected automatically. If you have one of these cards, say Y here and read the AX25-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + available from . This driver can operate multiple boards simultaneously. If you compile it as a module (by saying M instead of Y), it will be called @@ -4829,7 +5575,7 @@ 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/ . Please be sure to get + . Please be sure to get at least version 1.27 of dmascc_cfg, as older versions will not work with the current driver. @@ -4837,27 +5583,28 @@ 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://www.linuxdoc.org/docs.html#howto . Also - make sure to say Y to "Amateur Radio AX.25 Level 2" support. + this, read and the + AX25-HOWTO, available from + . 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. + say M here and read . The module + will be called scc.o. -additional delay for PA0HZP OptoSCC compatible boards +Support for TRX that feedback the tx signal to rx +CONFIG_SCC_TRXECHO + Some transmitters feed the transmitted signal back to the receive + line. Say Y here to foil this by explicitly disabling the receiver + during data transmission. If in doubt, say Y. + +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. -### -# + working properly; please read + for details. If unsure, + say N. YAM driver for AX.25 CONFIG_YAM @@ -4867,7 +5614,7 @@ 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. + say M here and read . BAYCOM picpar and par96 driver for AX.25 CONFIG_BAYCOM_PAR @@ -4875,13 +5622,13 @@ 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. + the modems, see and the file + . 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. + say M here and read . This is + recommended. The module will be called baycom_par.o. BAYCOM EPP driver for AX.25 CONFIG_BAYCOM_EPP @@ -4889,48 +5636,49 @@ 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. + modems, see and the file + . 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. + say M here and read . This is + recommended. The module will be called baycom_par.o. -BAYCOM ser12 full duplex driver for AX.25 +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 + 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, "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. + information on the modems, see and + . 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. + say M here and read . This is + recommended. The module will be called baycom_ser_fdx.o. -BAYCOM ser12 half duplex driver for AX.25 +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 + 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 + 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. + and + . 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. + say M here and read . This is + recommended. The module will be called baycom_ser_hdx.o. Sound card modem driver for AX.25 CONFIG_SOUNDMODEM @@ -4942,13 +5690,13 @@ 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. + and + . 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. + say M here and read . This is + recommended. The module will be called soundmodem.o. Sound card modem support for Sound Blaster and compatible cards CONFIG_SOUNDMODEM_SBC @@ -4957,7 +5705,7 @@ 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. + supports SB16/32/64 in full-duplex mode. Sound card modem support for WSS and Crystal cards CONFIG_SOUNDMODEM_WSS @@ -4965,8 +5713,8 @@ 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 + 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 @@ -5026,7 +5774,7 @@ can only use one protocol at a time, depending on what the other end can understand). -CCITT X.25 Packet Layer (EXPERIMENTAL) +CCITT X.25 Packet Layer 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 @@ -5037,13 +5785,13 @@ 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). + (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 . + You can read more about X.25 at and + . Information about X.25 for Linux is contained in the files - Documentation/networking/x25.txt and - Documentation/networking/x25-iface.txt. + and + . 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 @@ -5051,14 +5799,14 @@ 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). + 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. + say M here and read . The module + will be called x25.o. If unsure, say N. -LAPB Data Link Driver (EXPERIMENTAL) +LAPB Data Link Driver 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 @@ -5069,41 +5817,42 @@ 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. + 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. + want), say M here and read . The + module will be called lapb.o. If unsure, say N. -802.2 LLC (EXPERIMENTAL) +802.2 LLC CONFIG_LLC This is a Logical Link Layer protocol used for X.25 connections over - Ethernet, using ordinary Ethernet cards. - + Ethernet, using ordinary Ethernet cards. -Frame Diverter (EXPERIMENTAL) +Frame Diverter CONFIG_NET_DIVERT The Frame Diverter allows you to divert packets from the - network, that are not aimed at the interface receiving it (in - promisc. mode). Typically, a Linux box setup as an ethernet bridge - with the Frames Diverter on, can do some *really* transparent www + network, that are not aimed at the interface receiving it (in + promisc. mode). Typically, a Linux box setup as an Ethernet bridge + with the Frames Diverter on, can do some *really* transparent www caching using a Squid proxy for example. This is very useful when you don't want to change your router's config (or if you simply don't have access to it). - The other possible usages of diverting Ethernet Frames are numberous: + The other possible usages of diverting Ethernet Frames are + numberous: - reroute smtp traffic to another interface - traffic-shape certain network streams - transparently proxy smtp connections - etc... For more informations, please refer to: - http://www.freshmeat.net/projects/etherdivert - http://perso.wanadoo.fr/magpie/EtherDivert.html + + - If unsure, say N + If unsure, say N. 802.1d Ethernet Bridging CONFIG_BRIDGE @@ -5113,21 +5862,22 @@ Several such bridges can work together to create even larger networks of Ethernets using the IEEE 802.1 spanning tree algorithm. As this is a standard, Linux bridges will cooperate properly with - other third party bridge products. + other third party bridge products. + + In order to use the Ethernet bridge, you'll need the bridge + configuration tools; see + for location. Please read the Bridge mini-HOWTO for more + information. - In order to use the ethernet bridge, you'll need the bridge - configuration tools; see Documentation/networking/bridge.txt for - location. 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 in http://www.linuxdoc.org/docs.html#howto . + available from in . If you want to compile this 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 bridge.o. + say M here and read . The module + will be called bridge.o. If unsure, say N. @@ -5135,15 +5885,15 @@ 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. + 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. + whenever you want). If you want to compile it as a module, say M + here and read ; 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. @@ -5157,17 +5907,17 @@ Kernel/User network link driver CONFIG_NETLINK This driver allows for two-way communication between the kernel and - user processes. It does so by creating a new socket family, PF_NETLINK. - Over this socket, the kernel can send and receive datagrams carrying - information. It is documented on many systems in netlink(7), a HOWTO is - provided as well, for example on - http://snafu.freedom.org/linux2.2/docs/netlink-HOWTO.html + user processes. It does so by creating a new socket family, + PF_NETLINK. Over this socket, the kernel can send and receive + datagrams carrying information. It is documented on many systems in + netlink(7), a HOWTO is provided as well, for example on + . 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 + 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. @@ -5177,7 +5927,7 @@ CONFIG_RTNETLINK If you say Y here, user space programs can receive some network related routing information over the netlink. 'rtmon', supplied - with the iproute2 package (ftp://ftp.inr.ac.ru), can read and + with the iproute2 package (), can read and interpret this data. Information sent to the kernel over this link is ignored. @@ -5192,17 +5942,17 @@ 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 + 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/networking/atm.txt for further - details. + of ATM. See the file for + further details. Classical IP over ATM CONFIG_ATM_CLIP @@ -5247,9 +5997,9 @@ The driver works with MMF (-MF or ...F) and UTP-5 (-U5 or ...D) adapters. - This driver 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 eni.o. + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . The module will be called eni.o. Enable extended debugging CONFIG_ATM_ENI_DEBUG @@ -5296,7 +6046,7 @@ 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 @@ -5331,9 +6081,9 @@ Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM adapters. - This driver 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 zatm.o. + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . The module will be called zatm.o. Enable extended debugging CONFIG_ATM_ZATM_DEBUG @@ -5345,12 +6095,13 @@ Fujitsu FireStream (FS50/FS155) CONFIG_ATM_FIRESTREAM - Driver for the Fujitsu FireStream 155 (MB86697) and + Driver for the Fujitsu FireStream 155 (MB86697) and FireStream 50 (MB86695) ATM PCI chips. - This driver 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 firestream.o. + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . The module will be called + firestream.o. Enable usec resolution timestamps CONFIG_ATM_ZATM_EXACT_TS @@ -5368,21 +6119,22 @@ 25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE series. Say Y if you have one of those. - This driver 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 nicstar.o. + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . The module will be called + nicstar.o. -ForeRunner LE155 PHYsical layer +Use suni PHY driver (155Mbps) CONFIG_ATM_NICSTAR_USE_SUNI Support for the S-UNI and compatible PHYsical layer chips. These are found in most 155Mbps NICStAR based ATM cards, namely in the - ForeRunner LE155 cards. This driver provides detection of cable + ForeRunner LE155 cards. This driver provides detection of cable~ removal and reinsertion and provides some statistics. This driver doesn't have removal capability when compiled as a module, so if you need that capability don't include S-UNI support (it's not needed to make the card work). -ForeRunner LE25 PHYsical layer +Use IDT77015 PHY driver (25Mbps) CONFIG_ATM_NICSTAR_USE_IDT77105 Support for the PHYsical layer chip in ForeRunner LE25 cards. In addition to cable removal/reinsertion detection, this driver allows @@ -5399,11 +6151,12 @@ 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 + 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. + string "Dxxxx" to VCI 1023 (where x is a hex digit). See the file + 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 @@ -5418,28 +6171,29 @@ 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 + 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. + string "Dxxxx" to VCI 1023 (where x is a hex digit). See the file + 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. -Interphase ATM PCI x575/x525/x531 +Interphase ATM PCI x575/x525/x531 CONFIG_ATM_IA This is a driver for the Interphase (i)ChipSAR adapter cards - which include a variety of variants in term of the size of the - control memory (128K-1KVC, 512K-4KVC), the size of the packet - memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3, + which include a variety of variants in term of the size of the + control memory (128K-1KVC, 512K-4KVC), the size of the packet + memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3, UTP155, UTP25, DS3 and E3). Go to: www.iphase.com/products/ClassSheet.cfm?ClassID=ATM - for more info about the cards. Say Y (or M to compile as a module + for more info about the cards. Say Y (or M to compile as a module named iphase.o) here if you have one of these cards. - See the file Documentation/networking/iphase.txt for further + See the file for further details. Enable debugging messages @@ -5447,9 +6201,11 @@ 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 (Get the debug utility, iadbg, from - ftp.iphase.com/pub/atm/pci). See the file drivers/atm/iphase.h - for the meanings of the bits in the mask. + dynamically using an ioctl (Get the debug utility, iadbg, from + ). + + See the file 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 @@ -5458,36 +6214,37 @@ Linux telephony support CONFIG_PHONE Say Y here if you have a telephony card, which for example allows - you to use a regular phone for voice-over-IP applications. + you to use a regular phone for voice-over-IP applications. - Note: this has nothing to do with modems. You do not need to say Y + Note: this has nothing to do with modems. You do not need to say Y here in order to be able to use a modem under Linux. - 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 phonedev.o. + This support is also available as a module. If you want to compile + it as a module, say M here and read + . The module will be called + phonedev.o. Compaq Smart Array support CONFIG_BLK_CPQ_CISS_DA - This is the driver for Compaq Smart Array 5xxx controllers. - Everyone using these boards should say Y here. - See Documentation/cciss.txt for the current list of - boards supported by this driver, and for further information - on the use of this driver. + This is the driver for Compaq Smart Array 5xxx controllers. + Everyone using these boards should say Y here. + See for the current list of + boards supported by this driver, and for further information + on the use of this driver. QuickNet Internet LineJack/PhoneJack support CONFIG_PHONE_IXJ Say M if you have a telephony card manufactured by Quicknet Technologies, Inc. These include the Internet PhoneJACK and Internet LineJACK Telephony Cards. You will get a module called - ixj.o. + ixj.o. For the ISA versions of these products, you can configure the cards using the isapnp tools (pnpdump/isapnp) or you can use the - isapnp support. Please read Documentation/telephony/ixj.txt. + isapnp support. Please read . For more information on these cards, see Quicknet's web site at: - http://www.quicknet.net/ . + . If you do not have any Quicknet telephony cards, you can safely say N here. @@ -5498,66 +6255,66 @@ cards. It simultaneously supports PCA-200E and SBA-200E models on PCI and SBUS hosts. Say Y (or M to compile as a module named fore_200e.o) here if you have one of these ATM adapters. - + Note that the driver will actually be compiled only if you additionally enable the support for PCA-200E and/or SBA-200E cards. - See the file Documentation/networking/fore200e.txt for further - details. - + See the file for + further details. + Enable PCA-200E card support on PCI-based hosts CONFIG_ATM_FORE200E_PCA Say Y here if you want your PCA-200E cards to be probed. - + Use default PCA-200E firmware CONFIG_ATM_FORE200E_PCA_DEFAULT_FW Use the default PCA-200E firmware data shipped with the driver. - + Normal users do not have to deal with the firmware stuff, so they should say Y here. - + Pathname of user-supplied binary firmware CONFIG_ATM_FORE200E_PCA_FW This defines the pathname of an alternative PCA-200E binary firmware image supplied by the user. This pathname may be absolute or relative to the drivers/atm directory. - + The driver comes with an adequate firmware image, so normal users do not have to supply an alternative one. They just say Y to "Use default PCA-200E firmware" instead. - + Enable SBA-200E card support on SBUS-based hosts CONFIG_ATM_FORE200E_SBA Say Y here if you want your SBA-200E cards to be probed. - + Use default SBA-200E firmware CONFIG_ATM_FORE200E_SBA_DEFAULT_FW Use the default SBA-200E firmware data shipped with the driver. - + Normal users do not have to deal with the firmware stuff, so they should say Y here. - + Pathname of user-supplied binary firmware CONFIG_ATM_FORE200E_SBA_FW This defines the pathname of an alternative SBA-200E binary firmware image supplied by the user. This pathname may be absolute or relative to the drivers/atm directory. - + The driver comes with an adequate firmware image, so normal users do not have to supply an alternative one. They just say Y to "Use default SBA-200E firmware", above. - + Maximum number of tx retries CONFIG_ATM_FORE200E_TX_RETRY Specifies the number of times the driver attempts to transmit a message before giving up, if the transmit queue of the ATM card is transiently saturated. - + Saturation of the transmit queue may occur only under extreme conditions, e.g. when a fast host continuously submits very small frames (<64 bytes) or raw AAL0 cells (48 bytes) to the ATM adapter. - + Note that under common conditions, it is unlikely that you encounter a saturation of the transmit queue, so the retry mechanism never comes into play. @@ -5567,54 +6324,168 @@ Specifies the level of debugging messages issued by the driver. The verbosity of the driver increases with the value of this parameter. - + When active, these messages can have a significant impact on the performances of the driver, and the size of your syslog files! Keep the debugging level to 0 during normal operations. -SCSI support? +Fusion MPT device support +CONFIG_FUSION + LSI Logic Fusion(TM) Message Passing Technology (MPT) device support + provides high performance SCSI host initiator, and LAN [1] interface + services to a host system. The Fusion architecture is capable of + duplexing these protocols on high-speed Fibre Channel + (up to 2 GHz x 2 ports = 4 GHz) and parallel SCSI (up to Ultra-320) + physical medium. + + [1] LAN is not supported on parallel SCSI medium. + + These drivers require a Fusion MPT compatible PCI adapter installed + in the host system. MPT adapters contain specialized I/O processors + to handle I/O workload, and more importantly to offload this work + from the host CPU(s). + + If you have Fusion MPT hardware and want to use it, you can say + Y or M here to add MPT (base + ScsiHost) drivers. + = build lib (fusion.o), and link [static] into the kernel [2] + proper + = compiled as [dynamic] modules [3] named: (mptbase.o, + mptscsih.o) + + [2] In order enable capability to boot the linux kernel + natively from a Fusion MPT target device, you MUST + answer Y here! (currently requires CONFIG_BLK_DEV_SD) + [3] 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 as + modules, say M here and read + . + + If unsure, say N. + + If you say Y or M here you will get a choice of these + additional protocol and support module options: Module Name: + Enhanced SCSI error reporting (isense.o) + Fusion MPT misc device (ioctl) driver (mptctl.o) + Fusion MPT LAN driver (mptlan.o) + + --- + Fusion MPT is trademark of LSI Logic Corporation, and its + architecture is based on LSI Logic's Message Passing Interface (MPI) + specification. + +Fusion MPT enhanced SCSI error reporting [optional] module +CONFIG_FUSION_ISENSE + The isense module (roughly stands for Interpret SENSE data) is + completely optional. It simply provides extra English readable + strings in SCSI Error Report(s) that might be generated from the + Fusion MPT SCSI Host driver, for example when a target device + returns a SCSI check condition on a I/O. Without this module + loaded you might see: + + SCSI Error Report =-=-= (ioc0,scsi5:0) + SCSI_Status=02h (CHECK_CONDITION) + Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 + SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 + SenseKey=2h (NOT READY); FRU=02h + ASC/ASCQ=29h/00h + + Where otherwise, if this module had been loaded, you would see: + + SCSI Error Report =-=-= (ioc0,scsi5:0) + SCSI_Status=02h (CHECK_CONDITION) + Original_CDB[]: 2A 00 00 00 00 41 00 00 02 00 - "WRITE(10)" + SenseData[12h]: 70 00 02 00 00 00 00 0A 00 00 00 00 04 02 02 00 00 00 + SenseKey=2h (NOT READY); FRU=02h + ASC/ASCQ=29h/00h "LOGICAL UNIT NOT READY, INITIALIZING CMD. REQUIRED" + + Say M for "Enhanced SCSI error reporting" to compile this optional module, + creating a driver named: isense.o. + + NOTE: Support for building this feature into the kernel is not + available, due to kernel size considerations. + +Fusion MPT misc device (ioctl) driver [optional] module +CONFIG_FUSION_CTL + The Fusion MPT misc device driver provides specialized control + of MPT adapters via system ioctl calls. Use of ioctl calls to + the MPT driver requires that you create and use a misc device + node ala: + mknod /dev/mptctl c 10 240 + + One use of this ioctl interface is to perform an upgrade (reflash) + of the MPT adapter firmware. Refer to readme file(s) distributed + with the Fusion MPT linux driver for additional details. + + If enabled by saying M to this, a driver named: mptctl.o + will be compiled. + + If unsure whether you really want or need this, say N. + +Fusion MPT LAN driver [optional] +CONFIG_FUSION_LAN + This module supports LAN IP traffic over Fibre Channel port(s) + on Fusion MPT compatible hardware (LSIFC9xx chips). + The physical interface used is defined in RFC 2625. + Please refer to that document for details. + + Installing this driver requires the knowledge to configure and + activate a new network interface, "fc0", using standard Linux tools. + + If enabled by saying M to this, a driver named: mptlan.o + will be compiled. + + If unsure whether you really want or need this, say N. + + NOTES: This feature is NOT available nor supported for linux-2.2.x + kernels. You must be building a linux-2.3.x or linux-2.4.x kernel + in order to configure this option. + Support for building this feature into the linux kernel is not + yet available. + +SCSI support CONFIG_SCSI - If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or + If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM 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. + 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://www.linuxdoc.org/docs.html#howto . The + . 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 file system (the one containing the directory /) is - located on a SCSI device. + The module will be called scsi_mod.o. If you want to compile it as + a module, say M here and read and + . However, do not compile this as a + module if your root file system (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://www.linuxdoc.org/docs.html#howto . This is NOT for SCSI - CDROMs. + . This is NOT for SCSI + CD-ROMs. 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 file system (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. + The module will be called sd_mod.o. If you want to compile it as a + module, say M here and read and + . Do not compile this driver as a + module if your root file system (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. -Extra SCSI Disks +Maximum number of SCSI disks that can be loaded as modules CONFIG_SD_EXTRA_DEVS This controls the amount of additional space allocated in tables for drivers that are loaded as modules after the kernel is booted. In @@ -5628,63 +6499,76 @@ If you don't understand what's going on, go with the default. +Maximum number of SCSI tapes that can be loaded as modules +CONFIG_ST_EXTRA_DEVS + This controls the amount of additional space allocated in tables for + drivers that are loaded as modules after the kernel is booted. In + the event that the SCSI core itself was loaded as a module, this + value is the number of additional tapes that can be loaded after the + first host driver is loaded. + + Admittedly this isn't pretty, but there are tons of race conditions + involved with resizing the internal arrays on the fly. Someday this + flag will go away, and everything will work automatically. + + If you don't understand what's going on, go with the default. + 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://www.linuxdoc.org/docs.html#howto , and - drivers/scsi/README.st in the kernel source. This is NOT for SCSI - CDROMs. + , and + in the kernel source. This is NOT for + SCSI CD-ROMs. 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 . + module, say M here and read and + . OnStream SC-x0 SCSI tape support CONFIG_CHR_DEV_OSST - The OnStream SC-x0 SCSI tape drives can not be driven by the - standard st driver, but instead need this special osst driver and - use the /dev/osstX char device nodes (major 206). - Via usb-storage and ide-scsi, you may be able to drive the USB-x0 - and DI-x0 drives as well. Note that there is also a second generation - of OnStream tape drives (ADR-x0) that supports the standard SCSI-2 - commands for tapes (QIC-157) and can be driven by the standard - driver st. + The OnStream SC-x0 SCSI tape drives can not be driven by the + standard st driver, but instead need this special osst driver and + use the /dev/osstX char device nodes (major 206). Via usb-storage + and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives + as well. Note that there is also a second generation of OnStream + tape drives (ADR-x0) that supports the standard SCSI-2 commands for + tapes (QIC-157) and can be driven by the standard driver st. For more information, you may have a look at the SCSI-HOWTO - ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and - drivers/scsi/README.osst in the kernel source. - More info on the OnStream driver may be found on - http://linux1.onstream.nl/test/ + and + in the kernel source. + More info on the OnStream driver may be found on + Please also have a look at the standard st docu, as most of it applies to osst 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 osst.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt and - Documentation/scsi.txt . + module, say M here and read and + . -SCSI CDROM support +SCSI CD-ROM 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://www.linuxdoc.org/docs.html#howto . Also make sure to say Y - or M to "ISO 9660 CDROM file system support" later. + If you want to use a SCSI CD-ROM under Linux, say Y and read the + SCSI-HOWTO and the CD-ROM-HOWTO at + . Also make sure to say Y + or M to "ISO 9660 CD-ROM file system 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 . + module, say M here and read and + . -Extra SCSI CDROMs +Maximum number of CD-ROM devices that can be loaded as modules CONFIG_SR_EXTRA_DEVS This controls the amount of additional space allocated in tables for drivers that are loaded as modules after the kernel is booted. In the event that the SCSI core itself was loaded as a module, this - value is the number of additional CDROMs that can be loaded after + value is the number of additional CD-ROMs that can be loaded after the first host driver is loaded. Admittedly this isn't pretty, but there are tons of race conditions @@ -5693,7 +6577,7 @@ If you don't understand what's going on, go with the default. -Enable vendor-specific extensions (for SCSI CDROM) +Enable vendor-specific extensions (for SCSI CD-ROM) 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 @@ -5704,27 +6588,27 @@ 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 + CD-ROMs 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 scanners, look at SANE (http://www.mostang.com/sane). For CD + For scanners, look at SANE (). For CD writer software look at cdrecord - (http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html) + () and for burning a "disk at once": cdrdao - (http://www.ping.de/sites/daneb/cdrdao.html). Cdparanoia is a high - quality digital reader of audio CDs (http://www.xiph.org/paranoia). + (). Cdparanoia is a high + quality digital reader of audio CDs (). For other devices, it's possible that you'll have to write the driver software yourself. Please read the file - Documentation/scsi-generic.txt for more information. + 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 M here and read and + . The module will be called sg.o. If unsure, say N. -Debug new queueing code for SCSI +Enable extra checks in SCSI queueing code CONFIG_SCSI_DEBUG_QUEUES This option turns on a lot of additional consistency checking for the new queueing code. This will adversely affect performance, but @@ -5732,14 +6616,14 @@ This will typically cause the kernel to panic if an error is detected, but it would have probably crashed if the panic weren't there. Comments/questions/problems to linux-scsi mailing list - please. See http://www.andante.org/scsi_queue.html for more + please. See for more up-to-date information. 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. + 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 @@ -5754,7 +6638,7 @@ SCSI logging facility CONFIG_SCSI_LOGGING This turns on a logging facility that can be used to debug a number - of SCSI related problems. + 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 file system support" and @@ -5765,25 +6649,37 @@ at boot time after the /proc file system 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. + find them in the source: ), 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. +SGI WD93C93 SCSI Driver +CONFIG_SCSI_SGIWD93 + Say Y here to support the on-board WD93C93 SCSI controller found (a) + on the Indigo2 and other MIPS-based SGI machines, and (b) on ARCS + ARM-based machines. + +DEC NCR53C94 SCSI Driver +CONFIG_SCSI_DECNCR + Say Y here to support the NCR53C94 SCSI controller chips on IOASIC + based TURBOchannel DECstations and TURBOchannel PMAZ-A cards. + 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. + . The module will be called + advansys.o. Adaptec AHA152X/2825 support CONFIG_SCSI_AHA152X @@ -5792,49 +6688,61 @@ must be manually specified in this case. It is explained in section 3.3 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . You might also want to - read the file drivers/scsi/README.aha152x. + . You might also want to + read the file . 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. + module, say M here and read . Adaptec AHA1542 support CONFIG_SCSI_AHA1542 - This is support for a SCSI host adapter. It is explained in section + This is support for a SCSI host adapter. It is explained in section 3.4 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Note that Trantor was + . 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. - + sold under the Adaptec name. If it doesn't work out of the box, you + may have to change some settings in . + 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. + say M here and read . 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 + This is support for a SCSI host adapter. It is explained in section 3.5 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . 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. + The module will be called aha1740.o. If you want to compile it as a + module, say M here and read . -Adaptec AIC7xxx chipset SCSI controller support +Adaptec AIC7xxx support CONFIG_SCSI_AIC7XXX - This driver supports all of Adaptec's PCI based SCSI controllers (not - the hardware RAID controllers though) as well as the aic7770 based - EISA and VLB SCSI controllers (the 274x and 284x series). This is - an Adaptec sponsored driver written by Justin Gibbs. It is intended - to replace the previous aic7xxx driver maintained by Doug Ledford since - Doug is no longer maintaining that driver. + This driver supports all of Adaptec's PCI based SCSI controllers + (not the hardware RAID controllers though) as well as the aic7770 + based EISA and VLB SCSI controllers (the 274x and 284x series). + This is an Adaptec sponsored driver written by Justin Gibbs. It is + intended to replace the previous aic7xxx driver maintained by Doug + Ledford since Doug is no longer maintaining that driver. + +Adaptec I2O RAID controllers +CONFIG_SCSI_DPT_I2O + This driver supports all of Adaptec's I2O based RAID controllers as + well as the DPT SmartRaid V cards. This is an Adaptec maintained + driver by Deanna Bonds. See . + + 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 + . The module will be called + dpt_i2o.o. Default number of TCQ commands per device CONFIG_AIC7XXX_CMDS_PER_DEVICE @@ -5852,21 +6760,31 @@ Default: 253 -Initial Bus Reset Settle Delay +Delay in seconds after SCSI bus reset CONFIG_AIC7XXX_RESET_DELAY_MS The number of milliseconds to delay after an initial bus reset. The bus settle delay following all error recovery actions is dictated by the SCSI layer and is not affected by this value. - Default: 5000 (5 seconds) + Default: 15000 (15 seconds) -Old Adaptec AIC7xxx chipset SCSI controller support +Build Adapter Firmware with Kernel Build +CONFIG_AIC7XXX_BUILD_FIRMWARE + This option should only be enabled if you are modifying the firmware + source to the aic7xxx driver and wish to have the generated firmware + include files updated during a normal kernel build. The assembler + for the firmware requires lex and yacc or their equivalents, as well + as the db v1 library. You may have to install additional packages + or modify the assembler make file or the files it includes if your + build environment is different than that of the author. + +Old Adaptec AIC7xxx support CONFIG_SCSI_AIC7XXX_OLD - WARNING This driver is an older aic7xxx driver and is no longer under - active development. Adaptec, Inc. is writing a new driver to take the - place of this one, and it is recommended that whenever possible, people - should use the new Adaptec written driver instead of this one. This - driver will eventually be phased out entirely. + WARNING This driver is an older aic7xxx driver and is no longer + under active development. Adaptec, Inc. is writing a new driver to + take the place of this one, and it is recommended that whenever + possible, people should use the new Adaptec written driver instead + of this one. This driver will eventually be phased out entirely. This is support for the various aic7xxx based Adaptec SCSI controllers. These include the 274x EISA cards; 284x VLB cards; @@ -5889,47 +6807,47 @@ 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/aic7xxx_old/README.aic7xxx - at a minimum before contacting the maintainer with any questions. - The SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , can also be of great - help. + configuration options. You should read + at a minimum before + contacting the maintainer with any questions. The SCSI-HOWTO, + available from , 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_old.o. + say M here and read . The module + will be called aic7xxx_old.o. -Enable or Disable Tagged Command Queueing by default +Enable tagged command queueing (TCQ) by default CONFIG_AIC7XXX_OLD_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. + 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 + 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. + 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 + with the use of the tag_info boot parameter. See the file + 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. + should at least read the 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 + 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. @@ -5947,7 +6865,7 @@ 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 @@ -5964,14 +6882,14 @@ 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 file system support", below. + you also say Y to "/proc file system support", below. If unsure, say N. -IBM ServeRAID Support +IBM ServeRAID support CONFIG_SCSI_IPS This is support for the IBM ServeRAID hardware RAID controllers. - See http://www.developer.ibm.com/welcome/netfinity/serveraid.html + See for more information. If this driver does not work correctly without modification please contact the author by email at ipslinux@us.ibm.com. @@ -5979,14 +6897,14 @@ You can 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 ips.o. + as a module, say M here and read . + The module will be called ips.o. BusLogic SCSI support CONFIG_SCSI_BUSLOGIC This is support for BusLogic MultiMaster and FlashPoint SCSI Host Adapters. Consult the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , and the files + , 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 @@ -5995,8 +6913,8 @@ 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. + as a module, say M here and read . + The module will be called BusLogic.o. Omit BusLogic SCSI FlashPoint support CONFIG_SCSI_OMIT_FLASHPOINT @@ -6005,81 +6923,86 @@ substantial, so users of MultiMaster Host Adapters may wish to omit it. +Compaq Fibre Channel 64-bit/66Mhz HBA support +CONFIG_SCSI_CPQFCTS + Say Y here to compile in support for the Compaq StorageWorks Fibre + Channel 64-bit/66Mhz Host Bus Adapter. + DMX3191D SCSI support CONFIG_SCSI_DMX3191D This is support for Domex DMX3191D SCSI Host 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 will be called dmx3191d.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called dmx3191d.o. If you want to compile it as + a module, say M here and read . DTC3180/3280 SCSI support CONFIG_SCSI_DTC3280 - This is support for DTC 3180/3280 SCSI Host Adapters. Please read + This is support for DTC 3180/3280 SCSI Host Adapters. Please read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , and the file - drivers/scsi/README.dtc3x80. + , and the file + . 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. + The module will be called dtc.o. If you want to compile it as a + module, say M here and read . 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. + 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://www.linuxdoc.org/docs.html#howto . + 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 . 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. + The module will be called eata_dma.o. If you want to compile it as + a module, say M here and read . 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 + 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://www.linuxdoc.org/docs.html#howto . + numerous features. You might want to have a look at the SCSI-HOWTO, + available from . 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. + say M here and read . 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://www.linuxdoc.org/docs.html#howto . Note that there is also + The source at contains some + information about this hardware. If the driver doesn't work out of + the box, you may have to change some settings in + . Read the SCSI-HOWTO, available from + . 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 + 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. + The module will be called u14-34f.o. If you want to compile it as a + module, say M here and read . 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 + This option enables elevator sorting for all probed SCSI disks and + CD-ROMs. 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 @@ -6098,7 +7021,7 @@ 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://www.linuxdoc.org/docs.html#howto . + . NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI @@ -6108,7 +7031,7 @@ 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. + module, say M here and read . Future Domain MCS-600/700 SCSI support CONFIG_SCSI_FD_MCS @@ -6121,71 +7044,90 @@ 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. + module, say M here and read . 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 + confused with the NCR 53c7 or 8xx controllers. It is explained in section 3.8 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . 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. + The module will be called g_NCR5380.o. If you want to compile it as + a module, say M here and read . 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. + 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 does + not detect your card. See the file + for details. +# Choice: ncr5380 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. +NCR Dual 700 MCA SCSI support +CONFIG_SCSI_NCR_D700 + This is a driver for the MicroChannel Dual 700 card produced by + NCR and commonly used in 345x/35xx/4100 class machines. It always + tries to negotiate sync and uses tag command queueing. + + Unless you have an NCR manufactured machine, the chances are that + you do not have this SCSI card, so say N. + +HP LASI SCSI support for 53c700 +CONFIG_SCSI_LASI700 + This is a driver for the lasi baseboard in some parisc machines + which is based on the 53c700 chip. Will also support LASI subsystems + based on the 710 chip using 700 emulation mode. + + Unless you know you have a 53c700 or 53c710 based lasi, say N here + 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://www.linuxdoc.org/docs.html#howto . If it doesn't work out + controllers, not to be confused with the NCR 5380 controllers. It + is explained in section 3.8 of the SCSI-HOWTO, available from + . 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. + . Please read + 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 + ("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. + The module will be called 53c7,8xx.o. If you want to compile it as + a module, say M here and read . -always negotiate synchronous transfers +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] +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 +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 @@ -6197,10 +7139,67 @@ to hang, which might cause a system crash. The safe answer therefore is to say N. +SYM53C8XX Version 2 SCSI support +CONFIG_SCSI_SYM53C8XX_2 + This driver supports the whole NCR53C8XX/SYM53C8XX family of + PCI-SCSI controllers. It also supports the subset of LSI53C10XX + Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS + language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI + controllers. + + If your system has problems using this new major version of the + SYM53C8XX driver, you may switch back to driver version 1. + + Please read drivers/scsi/sym53c8xx_2/Documentation.txt for more + information. + +PCI DMA addressing mode +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE + This option only applies to PCI-SCSI chip that are PCI DAC capable + (875A, 895A, 896, 1010-33, 1010-66, 1000). + + When set to 0, only PCI 32 bit DMA addressing (SAC) will be performed. + When set to 1, 40 bit DMA addressing (with upper 24 bits of address + set to zero) is supported. The addressable range is here 1 TB. + When set to 2, full 64 bits of address for DMA are supported, but only + 16 segments of 4 GB can be addressed. The addressable range is so + limited to 64 GB. + + The safest value is 0 (32 bit DMA addressing) that is guessed to still + fit most of real machines. + + The preferred value 1 (40 bit DMA addressing) should make happy + properly engineered PCI DAC capable host bridges. You may configure + this option for Intel platforms with more than 4 GB of memory. + + The still experimental value 2 (64 bit DMA addressing with 16 x 4GB + segments limitation) can be used on systems that require PCI address + bits past bit 39 to be set for the addressing of memory using PCI + DAC cycles. + +use normal IO +CONFIG_SCSI_SYM53C8XX_IOMAPPED + If you say Y here, the driver will preferently use normal IO rather than + memory mapped IO. + +maximum number of queued commands +CONFIG_SCSI_SYM53C8XX_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 driver supports up to 256 queued commands per device. + This value is used as a compiled-in hard limit. + +default tagged command queue depth +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS + This is the default value of the command queue depth the driver will + announce to the generic SCSI layer for devices that support tagged + command queueing. This value can be changed from the boot command line. + This is a soft limit that cannot exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS. + 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, + 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. @@ -6208,21 +7207,22 @@ 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 + 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 + 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. + Please read for more + information. -SYM53C8XX SCSI support +SYM53C8XX Version 1 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 + 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 @@ -6231,32 +7231,33 @@ 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 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 + Please read for more + information. + +Synchronous transfer frequency in MHz CONFIG_SCSI_NCR53C8XX_SYNC The SCSI Parallel Interface-2 Standard defines 5 classes of transfer - rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. 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. + rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. 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 80, depending on the capability of your SCSI - controller. The higher the number, the faster the data transfer. + controller. The higher the number, the faster the data transfer. Note that 80 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 + 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 @@ -6270,18 +7271,18 @@ There is no safe option other than using good cabling, right terminations and SCSI conformant devices. -use normal IO +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. + 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 +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 @@ -6289,7 +7290,7 @@ 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 +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 @@ -6300,33 +7301,33 @@ 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 + 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 + 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 +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 + 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) +Assume boards are SYMBIOS compatible 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 @@ -6335,7 +7336,7 @@ 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. @@ -6344,16 +7345,16 @@ use BIOS and drivers from SYMBIOS, you would want to say Y here, otherwise N. N is the safe answer. -enable profiling statistics gathering +Enable traffic profiling 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 + 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 +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 @@ -6366,23 +7367,24 @@ 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. + series computers. These machines have an MCA bus, so you need to + answer Y to "MCA support" as well and read + . 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 + 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. 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. + say M here and read . The module + will be called ibmmca.o. Standard SCSI-order CONFIG_IBMMCA_SCSI_ORDER_STANDARD @@ -6399,7 +7401,7 @@ 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 + process-control-machines, like VME-CPUs running under realtime-OSes (e.g. LynxOS, OS9) do. If you like to run Linux on your MCA-machine with the same @@ -6428,96 +7430,96 @@ you know that one of your older devices needs it; N is the safe answer. -NCR 53C9x MCA support +NCR MCA 53C9x SCSI support CONFIG_SCSI_MCA_53C9X - Some Microchannel machines, notably the NCR 35xx line, use a SCSI + 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. + 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. - + M here and read . 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. + This is support for an ISA bus SCSI host adapter. You'll find more + information in . 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. + say M here and read . 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 + This is support for the Initio 91XXU(W) SCSI host adapter. Please read the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.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 + say M here and read . 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 + This is support for a SCSI host adapter. It is explained in section 3.10 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . 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. + The module will be called pas16.o. If you want to compile it as a + module, say M here and read . 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://www.linuxdoc.org/docs.html#howto . + This is support for the Initio INI-A100U2W SCSI host adapter. + Please read the SCSI-HOWTO, available from + . - If you want to compile this as a module ( = code which can be + 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 + say M here and read . 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://www.linuxdoc.org/docs.html#howto . + SCSI host adapter. Please read the SCSI-HOWTO, available from + . 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. + whenever you want). If you want to compile it as a module, say M + here and read . 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://www.linuxdoc.org/docs.html#howto . + SCSI host adapter. Please read the SCSI-HOWTO, available from + . 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. + whenever you want). If you want to compile it as a module, say M + here and read . 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://www.linuxdoc.org/docs.html#howto . + SCSI host adapter. Please read the SCSI-HOWTO, available from + . 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. + whenever you want). If you want to compile it as a module, say M + here and read . Qlogic FAS SCSI support CONFIG_SCSI_QLOGIC_FAS @@ -6530,31 +7532,32 @@ SCSI support"), below. Information about this driver is contained in - drivers/scsi/README.qlogicfas. You should also read the SCSI-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + . You should also read the + SCSI-HOWTO, available from + . 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. + a module, say M here and read . -Qlogic ISP SCSI support (EXPERIMENTAL) +Qlogic ISP SCSI support 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). + 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://www.linuxdoc.org/docs.html#howto . + Please read the file . You + should also read the SCSI-HOWTO, available from + . 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. + The module will be called qlogicisp.o. If you want to compile it as + a module, say M here and read . Qlogic ISP FC SCSI support CONFIG_SCSI_QLOGIC_FC @@ -6562,8 +7565,8 @@ 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. + The module will be called qlogicfc.o. If you want to compile it as + a module, say M here and read . Qlogic QLA 1280 SCSI support CONFIG_SCSI_QLOGIC_1280 @@ -6572,61 +7575,63 @@ 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 qla1280.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read . 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://www.linuxdoc.org/docs.html#howto . If it + this driver. It is explained in section 3.9 of the SCSI-HOWTO, + available from . 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. + The module will be called seagate.o. If you want to compile it as a + module, say M here and read . 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://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . 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. + . 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. + The module will be called t128.o. If you want to compile it as a + module, say M here and read . 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 + adapter family. This driver is explained in section 3.12 of the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . If it doesn't work out + . 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. + say M here and read . 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. + family. Some information is in the source: + . 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. + 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 . ACARD SCSI support CONFIG_SCSI_ACARD @@ -6635,40 +7640,41 @@ 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. + module, say M here and read . 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", + 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 + You want to read the start of and the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.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. + available: "EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti, + Alphatronix) 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. + say M here and read . The module + will be called eata.o. -enable tagged command queuing +enable tagged command queueing 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 + This option enables elevator sorting for all probed SCSI disks and + CD-ROMs. 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. @@ -6684,21 +7690,21 @@ 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://www.linuxdoc.org/docs.html#howto . + This is support for the NCR53c406a SCSI host adapter. For user + configurable parameters, check out + in the kernel source. Also read the SCSI-HOWTO, available from + . 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. + say M here and read . The module + will be called NCR53c406.o. -Symbios Logic sym53c416 support +Symbios 53c416 SCSI 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 + 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 @@ -6710,8 +7716,8 @@ 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. + read . The module will be called + sym53c416.o. Simple 53c710 SCSI support (Compaq, NCR machines) CONFIG_SCSI_SIM710 @@ -6720,46 +7726,46 @@ More complex drivers for this chip are available ("NCR53c7,8xx SCSI support", above), but they require that the scsi chip be able to do DMA block moves between memory and on-chip registers, which can - cause problems under certain conditions. This driver is designed to + cause problems under certain conditions. This driver is designed to avoid these problems and is intended to work with any Intel machines using 53c710 chips, including various Compaq and NCR machines. Please read the comments at the top of the file - drivers/scsi/sim710.c for more information. + for more information. 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 sim710.o. + say M here and read . The module + will be called sim710.o. -Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support +Tekram DC390(T) and Am53/79C974 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 drivers/scsi/README.tmscsim. - + Documentation can be found in . + 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. + "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. + say M here and read . 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 drivers/scsi/README.tmscsim. + 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 . 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 + 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. @@ -6767,40 +7773,42 @@ 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://www.linuxdoc.org/docs.html#howto , is for - you. + This is support for the AM53/79C974 SCSI host adapters. Please read + for details. Also, the + SCSI-HOWTO, available from + , is for you. Note that there is another driver for AM53C974 based adapters: - "Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support", above. You + "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. + say M here and read . 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. + 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. + say M here and read . The module + will be called megaraid.o. -GDT SCSI Disk Array Controller support +Intel/ICP (former GDT SCSI Disk Array) RAID 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. + Formerly called GDT SCSI Disk Array Controller Support. + + This is a driver for RAID/SCSI Disk Array Controllers (EISA/ISA/PCI) + manufactured by Intel/ICP vortex (an Intel Company). 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 @@ -6817,17 +7825,17 @@ 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://www.linuxdoc.org/docs.html#howto . If you use this driver, + read the file . You should also read + the SCSI-HOWTO, which is available from + . 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 + 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. + . The module will be called ppa.o. IOMEGA parallel port (imm - newer drives) CONFIG_SCSI_IMM @@ -6844,17 +7852,17 @@ 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://www.linuxdoc.org/docs.html#howto . If you use this driver, + read the file . You should also read + the SCSI-HOWTO, which is available from + . 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 + 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. + . The module will be called imm.o. Force the Iomega ZIP drivers to use EPP-16 CONFIG_SCSI_IZIP_EPP16 @@ -6866,7 +7874,7 @@ 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 @@ -6881,67 +7889,7 @@ Generally, saying N is fine. -Parallel port SCSI device support -CONFIG_PPSCSI - There are many external CD-ROM and disk devices that connect through - your computer's parallel port. Lots of them are actually SCSI - devices using a parallel port SCSI adapter. This option enables the - ppSCSI subsystem which contains drivers for many of these external - drives. You may also want to look at CONFIG_PARIDE (Parallel port - IDE device support). - - If you built ppSCSI 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 - ppscsi.o. - - To use the ppSCSI support, you must say Y or M here and also to at - least one protocol driver (e.g. "Shuttle EPST adapter", "Iomega VPI0 - adapter", "Shining ScarSCI adapter" etc.). - -Adaptec APA-348 adapter -CONFIG_PPSCSI_T348 - This option enables support for the APA-348 adapter from Adaptec - (also known as Trantor T348). If you build this as a module it will - be called t348.o. - -Adaptec APA-358 adapter -CONFIG_PPSCSI_T358 - This option enables support for the APA-358 adapter from Adaptec - (also known as Trantor T358). If you build this as a module it will - be called t358.o. - -Iomega VPI0 adapter -CONFIG_PPSCSI_VPI0 - This option enables support for the Iomega VPI0 adapter found in the - original ZIP-100 drives and the Jaz Traveller. If you build this as - a module it will be called vpi0.o. - -OnSpec 90c26 adapter -CONFIG_PPSCSI_ONSCSI - This option enables support for the OnSpec 90c26 in its SCSI adapter - mode. If you build this as a module it will be called onscsi.o. - -Shining SparSCI adapter -CONFIG_PPSCSI_SPARCSI - This option enables support for the WBS-11A parallel port SCSI - adapter. This adapter has been marketed by LinkSys as the - "ParaSCSI+" and by Shining Technologies as the "SparCSI". If you - build this as a module it will be called sparcsi.o. - -Shuttle EPSA-2 adapter -CONFIG_PPSCSI_EPSA2 - This option enables support for the Shuttle Technologies EPSA2 - parallel port SCSI adapter. EPAS2 is a predecessor to the EPST. If - you build this as a module it will be called epsa2.o. - -Shuttle EPST adapter -CONFIG_PPSCSI_EPST - This option enables support for the Shuttle Technologies EPST - parallel port SCSI adapter. If you build this as a module is will - be called epst.o. - -SCSI Debug host simulator. (EXPERIMENTAL) +SCSI debugging host simulator 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 @@ -6950,7 +7898,7 @@ 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 and FC4 SCSI support +Fibre Channel and FC4 SCSI support CONFIG_FC4 Fibre Channel is a high speed serial protocol mainly used to connect large storage devices to the computer; it is compatible with @@ -6966,7 +7914,7 @@ If unsure, say N. -Sun SOC +Sun SOC/Sbus 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. Note @@ -6976,7 +7924,7 @@ This support is also available as a module called soc.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. + here and read . Sun SOC+ (aka SOCAL) CONFIG_FC4_SOCAL @@ -6989,16 +7937,16 @@ This support is also available as a module called socal.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. + here and read . SparcSTORAGE Array 100 and 200 series CONFIG_SCSI_PLUTO - If you never bought a disk array made by Sun, go with N. + If you never bought a disk array made by Sun, go with N. This support is also available as a module called pluto.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. + here and read . Sun Enterprise Network Array (A5000 and EX500) CONFIG_SCSI_FCAL @@ -7010,14 +7958,14 @@ This support is also available as a module called fcal.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. + here and read . If unsure, say N. -AcornSCSI support +Acorn SCSI card (aka30) 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 +Support SCSI 2 Tagged queueing CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE Say Y here to enable tagged queuing support on the Acorn SCSI card. @@ -7026,7 +7974,7 @@ 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 +Support SCSI 2 Synchronous Transfers CONFIG_SCSI_ACORNSCSI_SYNC Say Y here to enable synchronous transfer negotiation with all targets on the Acorn SCSI card. @@ -7034,6 +7982,16 @@ In general, this improves performance; however some SCSI devices don't implement it properly, so the safe answer is N. +ARXE SCSI support +CONFIG_SCSI_ARXESCSI + Around 1991, Arxe Systems Limited released a high density floppy + disc interface for the Acorn Archimedes range, to allow the use of + HD discs from the then new A5000 on earlier models. This interface + was either sold on its own or with an integral SCSI controller. + Technical details on this NCR53c94-based device are available at + + Say Y here to compile in support for the SCSI controller. + Oak SCSI support CONFIG_SCSI_OAK1 This enables support for the Oak SCSI card. If you have an Acorn @@ -7044,7 +8002,7 @@ 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) +Cumana SCSI II support 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. @@ -7055,17 +8013,17 @@ in the Econet socket. If you have an Acorn system with one of these, say Y. If unsure, say N. -EESOX SCSI support (EXPERIMENTAL) +EESOX SCSI support 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) +PowerTec SCSI support 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. -IEEE 1394 (aka FireWire) support +IEEE 1394 (FireWire) support CONFIG_IEEE1394 IEEE 1394 describes a high performance serial bus, which is also known as FireWire(tm) or i.Link(tm) and is used for connecting all @@ -7078,10 +8036,10 @@ 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 ieee1394.o. + say M here and read . The module + will be called ieee1394.o. -TI PCILynx IEEE 1394 support +Texas Instruments PCILynx support CONFIG_IEEE1394_PCILYNX Say Y here if you have an IEEE-1394 controller with the Texas Instruments PCILynx chip. Note: this driver is written for revision @@ -7089,8 +8047,8 @@ 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 pcilynx.o. + say M here and read . The module + will be called pcilynx.o. Use local RAM on PCILynx board CONFIG_IEEE1394_PCILYNX_LOCALRAM @@ -7100,7 +8058,7 @@ computer's motherboard. Local RAM may speed up command processing because no PCI transfers are necessary during use of the Packet Control Lists. - + Note that there are no known PCILynx systems providing local RAM except for the evaluation boards by Texas Instruments and that the PCILynx does not reliably report missing RAM. This means that it is @@ -7114,32 +8072,43 @@ This option enables driver code to access the RAM, ROM and AUX ports of the PCILynx through character devices in /dev. If you don't know what this is about then you won't need it. - + If unsure, say N. +#Adaptec AIC-5800 IEEE 1394 support +#CONFIG_IEEE1394_AIC5800 +# Say Y here if you have a IEEE 1394 controller using the Adaptec +# AIC-5800 chip. All Adaptec host adapters (89xx series) use this +# chip, as well as miro's DV boards. +# +# 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 . The module +# will be called aic5800.o. +# OHCI-1394 support CONFIG_IEEE1394_OHCI1394 Enable this driver if you have an IEEE 1394 controller based on the OHCI-1394 specification. The current driver is only tested with OHCI chipsets made by Texas Instruments and NEC. Most third-party vendors - use one of these chipsets. It should work with any OHCI-1394 compliant - card, however. + use one of these chipsets. It should work with any OHCI-1394 + compliant card, however. 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 ohci1394.o. + say M here and read . The module + will be called ohci1394.o. OHCI-1394 Video support CONFIG_IEEE1394_VIDEO1394 - This option enables video device usage for OHCI-1394 cards. Enable this - option only if you have an IEEE 1394 video device connected to an - OHCI-1394 card. + This option enables video device usage for OHCI-1394 cards. Enable + this option only if you have an IEEE 1394 video device connected to + an OHCI-1394 card. SBP-2 support (Harddisks etc.) CONFIG_IEEE1394_SBP2 - This option enables you to use SBP-2 devices connected to your IEEE 1394 - bus. SBP-2 devices include harddrives and DVD devices. + This option enables you to use SBP-2 devices connected to your IEEE + 1394 bus. SBP-2 devices include harddrives and DVD devices. Raw IEEE 1394 I/O support CONFIG_IEEE1394_RAWIO @@ -7150,8 +8119,8 @@ 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 raw1394.o. + say M here and read . The module + will be called raw1394.o. Excessive debugging output CONFIG_IEEE1394_VERBOSEDEBUG @@ -7164,18 +8133,18 @@ Say Y if you really want or need the debugging output, everyone else says N. -Network device support? +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://www.linuxdoc.org/docs.html#howto ) or dialing up a shell + ) 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 @@ -7191,7 +8160,7 @@ 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 http://www.linuxdoc.org/docs.html#guide . If + Guide", to be found in . If unsure, say Y. Dummy net driver support @@ -7204,14 +8173,15 @@ 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://www.linuxdoc.org/docs.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. + say M here and read . 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. Bonding driver support CONFIG_BONDING @@ -7219,7 +8189,7 @@ Channels together. This is called 'Etherchannel' by Cisco, 'Trunking' by Sun, and 'Bonding' in Linux. - If you have two ethernet connections to some other computer, you can + If you have two Ethernet connections to some other computer, 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 Bonding Linux driver, a Cisco 5500 switch or a @@ -7230,8 +8200,8 @@ 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 bonding.o. + say M here and read . The module + will be called bonding.o. SLIP (serial line) support CONFIG_SLIP @@ -7247,23 +8217,23 @@ 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 + ) 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://www.linuxdoc.org/docs.html#howto , explains how to + , 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 + ). 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. + say M here and read as well as + . The module will be + called slip.o. CSLIP compressed headers CONFIG_SLIP_COMPRESSED @@ -7272,10 +8242,10 @@ 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 + ) 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://www.linuxdoc.org/docs.html#howto , explains how to configure + , explains how to configure CSLIP. This won't enlarge your kernel. Keepalive and linefill @@ -7296,24 +8266,24 @@ PPP (point-to-point protocol) support CONFIG_PPP - PPP (Point to Point Protocol) is a newer and better SLIP. It serves + 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 + 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://www.linuxdoc.org/docs.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. + in the PPP-HOWTO, available at + . Make sure that you have + the version of pppd recommended in . + 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 + 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 + 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. @@ -7321,12 +8291,12 @@ 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. + 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 + as well as + . -PPP multilink support (EXPERIMENTAL) +PPP multilink support CONFIG_PPP_MULTILINK PPP multilink is a protocol (defined in RFC 1990) which allows you to combine several (logical or physical) lines into one logical PPP @@ -7337,7 +8307,7 @@ If unsure, say N. -PPP filtering (EXPERIMENTAL) +PPP filtering CONFIG_PPP_FILTER Say Y here if you want to be able to filter the packets passing over PPP interfaces. This allows you to control which packets count as @@ -7357,7 +8327,7 @@ 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. + it as a module, say M here and read . If unsure, say Y. @@ -7369,20 +8339,22 @@ 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. + it as a module, say M here and read + . 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 + 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 + 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. + it as a module, say M here and read + . PPP BSD-Compress compression CONFIG_PPP_BSDCOMP @@ -7401,14 +8373,14 @@ 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. -PPP over Ethernet (EXPERIMENTAL) +PPP over Ethernet CONFIG_PPPOE Support for PPP over Ethernet. This driver requires a specially patched pppd daemon. The patch to pppd, along with binaries of a patched pppd package can be found at: - http://www.shoshin.uwaterloo.ca/~mostrows - + . + Wireless LAN (non-hamradio) CONFIG_NET_RADIO Support for wireless LANs and everything having to do with radio, @@ -7425,18 +8397,18 @@ driver (or Linux). If you wish to use Wireless Extensions with wireless PCMCIA (PC-) cards, you need to say Y here; you can fetch the tools from - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html . + . 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 + (on the WWW at ) 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 @@ -7447,50 +8419,51 @@ 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. + 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. + here and read . 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 + + 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). + Hinds' pcmcia-cs package (see the file + for location). If you want to use an ISA WaveLAN card under Linux, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Some more specific - information is contained in Documentation/networking/wavelan.txt and - in the source code drivers/net/wavelan.p.h. + . Some more specific + information is contained in + and in the source code + . You will also need the wireless tools package available from - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html . + . 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. + The module will be called wavelan.o. If you want to compile it as a + module, say M here and read as well + as . 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 the latest information. - + for the 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. @@ -7499,27 +8472,27 @@ www.aironet.com (recently bought by Cisco) makes these 802.11 DS adapters. Driver by Elmer Joandi (elmer@ylenurme.ee). - Say Y here if you have such an adapter, and then say Y below to - the option that applies to your particular type of card (PCI, ISA, + Say Y here if you have such an adapter, and then say Y below to + the option that applies to your particular type of card (PCI, ISA, or PCMCIA). 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 aironet4500_core.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. + The module will be called aironet4500_core.o. If you want to + compile it as a module, say M here and read + as well as + . - quick config parameters: + quick config parameters: SSID=tsunami - "The Password" adhoc=1 there are no Access Points around - master=1 Adhoc master (the one who creates network + master=1 Adhoc master (the one who creates network sync) - slave=1 Adhoc slave (btw, it is still forming own net + slave=1 Adhoc slave (btw, it is still forming own net sometimes, and has problems with firmware... change IbssJoinNetTimeout from /proc...) channel=1..? meaningful in adhoc mode - + If you have problems with screwing up card, both_bap_lock=1 is a conservative value (performance hit 15%). @@ -7527,107 +8500,107 @@ Aironet 4500/4800 ISA/PCI/PNP/365 support CONFIG_AIRONET4500_NONCS - If you have an ISA, PCI or PCMCIA Aironet 4500/4800 wireless LAN - card, say Y here, and then also to the options below that apply + If you have an ISA, PCI or PCMCIA Aironet 4500/4800 wireless LAN + card, say Y here, and then also to the options below that apply to 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 aironet4500_card.o. If you want to - compile it as a module, say M here and read - Documentation/modules.txt + The module will be called aironet4500_card.o. If you want to + compile it as a module, say M here and read + . Aironet 4500/4800 PNP support CONFIG_AIRONET4500_PNP - If you have an ISA Aironet 4500/4800 card which you want to use in - PNP (Plug and Play) mode, say Y here. This is the recommended mode - for ISA cards. Remember however to enable the PNP jumper on the + If you have an ISA Aironet 4500/4800 card which you want to use in + PnP (Plug and Play) mode, say Y here. This is the recommended mode + for ISA cards. Remember however to enable the PnP jumper on the board if you say Y here. Aironet 4500/4800 PCI support CONFIG_AIRONET4500_PCI If you have an PCI Aironet 4500/4800 card, say Y here. -Aironet 4500/4800 ISA broken support (EXPERIMENTAL) +Aironet 4500/4800 ISA broken support CONFIG_AIRONET4500_ISA If you have an ISA Aironet 4500/4800 card which you want to run in - non-PNP mode, say Y here. This is not recommended and does not work + non-PnP mode, say Y here. This is not recommended and does not work correctly at this point. Say N. -Aironet 4500/4800 I365 broken support (EXPERIMENTAL) +Aironet 4500/4800 I365 broken support CONFIG_AIRONET4500_I365 - If you have a PCMCIA Aironet 4500/4800 card which you want to use - without the standard PCMCIA cardservices provided by the pcmcia-cs + If you have a PCMCIA Aironet 4500/4800 card which you want to use + without the standard PCMCIA cardservices provided by the pcmcia-cs package, say Y here. This is not recommended, so say N. Aironet 4500/4800 PCMCIA support CONFIG_AIRONET4500_CS - Say Y here if you have a PCMCIA Aironet 4500/4800 card which you + Say Y here if you have a PCMCIA Aironet 4500/4800 card which you want to use with the standard PCMCIA cardservices provided by the pcmcia-cs 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 aironet4500_cs.o. If you want to - compile it as a module, say M here and read - Documentation/modules.txt. - + The module will be called aironet4500_cs.o. If you want to + compile it as a module, say M here and read + . + Aironet 4500/4800 PROC interface CONFIG_AIRONET4500_PROC - If you say Y here (and to the "/proc file system" below), you will - be able to configure your Aironet card via the + If you say Y here (and to the "/proc file system" below), you will + be able to configure your Aironet card via the /proc/sys/aironet4500 interface. - Additional info: look in drivers/net/aironet4500_rids.c. + Additional info: look in . 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 aironet4500_proc.o. If you want to - compile it as a module, say M here and read - Documentation/modules.txt. + The module will be called aironet4500_proc.o. If you want to + compile it as a module, say M here and read + . NOTE: the proc interface uses a lot of memory, so it is recommended - to compile it as a module and remove the module after + to compile it as a module and remove the module after configuration. 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 + 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". + 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. + say M here and read . 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 + ordinary modems. Experts should note that this driver doesn't currently comply with the asynchronous HDLS framing protocols in - CCITT recommendation X.25. + 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. + say M here and read . 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 or CardBus network adapters, then say Y to the driver for your particular card - below. PCMCIA- or PC-cards are credit-card size devices often used + below. PCMCIA- or PC-cards are credit-card size devices often used with laptops computers; CardBus is the newer and faster version of - PCMCIA. + PCMCIA. To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file Documentation/Changes for - location). You also want to check out the PCMCIA-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + Hinds' pcmcia-cs package (see the file + for location). You also want to check out the PCMCIA-HOWTO, + available from . If unsure, say N. @@ -7638,9 +8611,9 @@ 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. + The module will be called 3c589_cs.o. If you want to compile it as + a module, say M here and read . If + unsure, say N. 3Com 3c574 PCMCIA support CONFIG_PCMCIA_3C574 @@ -7649,9 +8622,9 @@ 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. + The module will be called 3c574_cs.o. If you want to compile it as + a module, say M here and read . If + unsure, say N. Fujitsu FMV-J18x PCMCIA support CONFIG_PCMCIA_FMVJ18X @@ -7660,9 +8633,9 @@ 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. + The module will be called fmvj18x_cs.o. If you want to compile it + as a module, say M here and read . + If unsure, say N. NE2000 compatible PCMCIA support CONFIG_PCMCIA_PCNET @@ -7671,9 +8644,9 @@ 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. + The module will be called pcnet_cs.o. If you want to compile it as + a module, say M here and read . If + unsure, say N. New Media PCMCIA support CONFIG_PCMCIA_NMCLAN @@ -7682,9 +8655,9 @@ 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. + The module will be called nmclan_cs.o. If you want to compile it as + a module, say M here and read . If + unsure, say N. SMC 91Cxx PCMCIA support CONFIG_PCMCIA_SMC91C92 @@ -7693,20 +8666,20 @@ 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. + The module will be called smc91c92_cs.o. If you want to compile it + as a module, say M here and read . + 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. + 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. + The module will be called xirc2ps_cs.o. If you want to compile it + as a module, say M here and read . + If unsure, say N. COM20020 ARCnet PCMCIA support CONFIG_ARCNET_COM20020_CS @@ -7715,20 +8688,20 @@ 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_cs.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. If - unsure, say N. + The module will be called com20020_cs.o. If you want to compile it + as a module, say M here and read . + If unsure, say N. IBM PCMCIA Token Ring adapter support CONFIG_PCMCIA_IBMTR Say Y here if you intend to attach this type of Token Ring PCMCIA card to your computer. You then also need to say Y to "Token Ring - driver support". + driver support". 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_cs.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + The module will be called ibmtr_cs.o. If you want to compile it as + a module, say M here and read . Xircom Tulip-like CardBus support CONFIG_PCMCIA_XIRTULIP @@ -7739,20 +8712,20 @@ 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 xircom_tulip_cb.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. + The module will be called xircom_tulip_cb.o. If you want to compile + it as a module, say M here and read + . If unsure, say N. -Pcmcia Wireless LAN +PCMCIA Wireless LAN CONFIG_NET_PCMCIA_RADIO Say Y here if you would like to use a PCMCIA (PC-card) device to connect to a wireless local area network. Then say Y to the driver for your particular card below. To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file Documentation/Changes for - location). You also want to check out the PCMCIA-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + Hinds' pcmcia-cs package (see the file + for location). You also want to check out the PCMCIA-HOWTO, + available from . Hermes chipset 802.11b support (Orinoco/Prism2/Symbol cards) CONFIG_HERMES @@ -7772,7 +8745,7 @@ You will also very likely also need the Wireless Tools in order to configure your card and that /etc/pcmcia/wireless.opts works : - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html + Apple Airport support (built-in) CONFIG_APPLE_AIRPORT @@ -7796,24 +8769,24 @@ CONFIG_PCMCIA_HERMES A driver for "Hermes" chipset based PCMCIA wireless adaptors, such as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). - It should also be usable on various Prism II based cards such as the - Linksys, D-Link and Farallon Skyline. It should also work on Symbol - cards such as the 3Com AirConnect and Ericsson WLAN. + EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and + others). It should also be usable on various Prism II based cards + such as the Linksys, D-Link and Farallon Skyline. It should also + work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN. To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file Documentation/Changes for - location). You also want to check out the PCMCIA-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + Hinds' pcmcia-cs package (see the file + for location). You also want to check out the PCMCIA-HOWTO, + available from . You will also very likely also need the Wireless Tools in order to - configure your card and that /etc/pcmcia/wireless.opts works : - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html + configure your card and that /etc/pcmcia/wireless.opts works: + . Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards CONFIG_AIRO - This is the standard Linux driver to support Cisco/Aironet ISA - and PCI 802.11 wireless cards. + This is the standard Linux driver to support Cisco/Aironet ISA and + PCI 802.11 wireless cards. It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - with or without encryption) as well as card before the Cisco aquisition (Aironet 4500, Aironet 4800, Aironet 4800B). @@ -7827,7 +8800,7 @@ Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards CONFIG_AIRO_CS This is the standard Linux driver to support Cisco/Aironet PCMCIA - 802.11 wireless cards. This driver is the same as the Aironet + 802.11 wireless cards. This driver is the same as the Aironet driver part of the Linux Pcmcia package. It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - with or without encryption) as well as card before the Cisco @@ -7840,22 +8813,28 @@ Cisco Linux utilities can be used to configure the card. To use your PC-cards, you will need supporting software from David - Hinds' pcmcia-cs package (see the file Documentation/Changes for - location). You also want to check out the PCMCIA-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto . + Hinds' pcmcia-cs package (see the file + for location). You also want to check out the PCMCIA-HOWTO, + available from . 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. - Please read the file Documentation/networking/ray_cs.txt for + Please read the file 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 ray_cs.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. If unsure, - say N. + The module will be called ray_cs.o. If you want to compile it as a + module, say M here and read . If + unsure, say N. + +Apple Airport support (built-in) +CONFIG_APPLE_AIRPORT + Say Y here to support the Airport 802.11b wireless Ethernet hardware + built into the Macintosh iBook and other recent PowerPC-based + Macintosh machines. Xircom Netwave AirSurfer wireless support CONFIG_PCMCIA_NETWAVE @@ -7864,9 +8843,9 @@ 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. + The module will be called netwave_cs.o. If you want to compile it + as a module, say M here and read . + If unsure, say N. AT&T/Lucent Wavelan wireless support CONFIG_PCMCIA_WAVELAN @@ -7876,44 +8855,45 @@ 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. + The module will be called wavelan_cs.o. If you want to compile it + as a module, say M here and read . + 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 + 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 + CD-ROM 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. + . 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 () + 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://www.linuxdoc.org/docs.html#howto . Note that the PLIP + . 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 + 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. + say M here and read as well as + . 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 @@ -7921,39 +8901,41 @@ 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 + 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. + 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://www.linuxdoc.org/docs.html#howto . + Say Y if you want this and read + . You may also want to read + section 6.2 of the NET-3-HOWTO, available from + . 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. + The module will be called eql.o. If you want to compile it as a + module, say M here and read . If + unsure, say N. -Universal TUN/TAP device driver. +Universal TUN/TAP device driver support CONFIG_TUN - TUN/TAP provides packet reception and transmission for user space programs. - It can be viewed as a simple Point-to-Point or Ethernet device, which - instead of receiving packets from a physical media, receives them from - user space program and instead of sending packets via physical media - writes them to the user space program. + TUN/TAP provides packet reception and transmission for user space + programs. It can be viewed as a simple Point-to-Point or Ethernet + device, which instead of receiving packets from a physical media, + receives them from user space program and instead of sending packets + via physical media writes them to the user space program. + + When a program opens /dev/net/tun, driver creates and registers + corresponding net device tunX or tapX. After a program closed above + devices, driver will automatically delete tunXX or tapXX device and + all routes corresponding to it. - When a program opens /dev/net/tun, driver creates and registers - corresponding net device tunX or tapX. After a program closed above - devices, driver will automatically delete tunXX or tapXX device and all - routes corresponding to it. - - Please read Documentation/networking/tuntap.txt for more information. + Please read 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 tun.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called tun.o. If you want to compile it as a + module, say M here and read . If you don't know what to use this for, you don't need it. @@ -7963,7 +8945,7 @@ 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 + 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 @@ -7971,19 +8953,19 @@ 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. + 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. + module, say M here and read . 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 @@ -7997,6 +8979,21 @@ of the Cisco HDLC/PPP driver (syncppp.c). The SyncLink WAN driver (in character devices) must also be enabled. +FarSync T-Series support +CONFIG_FARSYNC + This driver supports the FarSync T-Series X.21 (and V.35/V.24) cards + from FarSite Communications Ltd. + Synchronous communication is supported on all ports at speeds up to + 8Mb/s (128K on V.24) using synchronous PPP or Cisco HDLC. + + 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 . + The module will be called farsync.o and if you want the module to be + automatically loaded when the interface is referenced then you + should add "alias syncX farsync" to /etc/modules.conf for each + interface, where X is 0, 1, 2, ... + Frame Relay (DLCI) support CONFIG_DLCI This is support for the frame relay protocol; frame relay is a fast @@ -8006,15 +9003,15 @@ 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 + 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. + module, say M here and read . Max open DLCI CONFIG_DLCI_COUNT @@ -8029,19 +9026,19 @@ handled by each of your hardware frame relay access devices. Go with the default. -Sangoma S502A FRAD support +SDLA (Sangoma S502/S508) 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. + read . 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. + module, say M here and read . -Acorn Econet/AUN protocols (EXPERIMENTAL) +Acorn Econet/AUN protocols 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 @@ -8057,7 +9054,7 @@ 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. + module, say M here and read . AUN over UDP CONFIG_ECONET_AUNUDP @@ -8070,7 +9067,7 @@ Say Y here if you have a native Econet network card installed in your computer. -WAN Router +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 @@ -8082,16 +9079,17 @@ 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 + 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 driver for your card, below. You will then need the + wan-tools package which is available from . + Read 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. + running kernel whenever you want). If you want to compile it as a + module, say M here and read . If unsure, say N. @@ -8103,13 +9101,13 @@ 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"). + However, it will work with all options in the "Advanced router" + section (except for "Use TOS value as routing key" and + "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. @@ -8119,7 +9117,7 @@ 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 @@ -8146,68 +9144,75 @@ 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/ . + from the package iproute2+tc at . That package also contains some documentation; for more, check out - http://snafu.freedom.org/linux2.2/iproute-notes.html . + . This Quality of Service (QoS) support will enable you to use Differentiated Services (diffserv) and Resource Reservation Protocol (RSVP) on your Linux router if you also say Y to "QoS support", "Packet classifier API" and to some classifiers below. Documentation - and software is at http://icawww1.epfl.ch/linux-diffserv/ . + and software is at . If you say Y here and to "/proc file system" 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 + 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. - + See the top of 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 + 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. + whenever you want). If you want to compile it as a module, say M + here and read . 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 + 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). - + real-time applications (see the top of + 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. + here and read . -#ATM pseudo-scheduler -#CONFIG_NET_SCH_ATM -# -# ??? -# - -The simplest PRIO pseudo scheduler +ATM pseudo-scheduler +CONFIG_NET_SCH_ATM + Say Y here if you want to use the ATM pseudo-scheduler. This + provides a framework for invoking classifiers (aka "filters"), which + in turn select classes of this queuing discipline. Each class maps + the flow(s) it is handling to a given virtual circuit (see the top of + ). + + This code is also available as a module called sch_atm.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 . + +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 @@ -8216,32 +9221,56 @@ 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. + here and read . + +Diffserv field marker +CONFIG_NET_SCH_DSMARK + Say Y if you want to schedule packets avccording to the + Differentiated Services architecture proposed in RFC 2475. + Technical information on this method, with pointers to associated + RFCs, is available at . + + This code is also available as a module called sch_dsmark.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 . + +GRED queue +CONFIG_NET_SCH_GRED + Say Y here if you want to use the Generic Random Early Detection + (RED) packet scheduling algorithm for some of your network devices + (see the top of for details and + references about the algorithm). + + This code is also available as a module called sch_gred.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 . 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). + the top of 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. + whenever you want). If you want to compile it as a module, say M + here and read . 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). + 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. + here and read . TEQL queue CONFIG_NET_SCH_TEQL @@ -8249,30 +9278,36 @@ 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 + one virtual device. (see the top of 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. + here and read . 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). + 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. + here and read . + +Ingress Qdisc +CONFIG_NET_SCH_INGRESS + If you say Y here, you will be able to police incoming bandwidth + and drop packets when this bandwidth exceeds your desired rate. + If unsure, say Y. -### Add these -#+tristate ' GRED queue' CONFIG_NET_SCH_GRED -#+tristate ' Diffserv field marker' CONFIG_NET_SCH_DSMARK -#+tristate ' Ingress Qdisc' CONFIG_NET_SCH_INGRESS + This code is also available as a module called cls_ingress.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 . QoS support CONFIG_NET_QOS @@ -8284,10 +9319,10 @@ Differentiated Services (diffserv) and Resource Reservation Protocol (RSVP) on your Linux router if you also say Y to "Packet classifier API" and to some classifiers below. Documentation and software is at - http://icawww1.epfl.ch/linux-diffserv/ . + . Note that the answer to this question won't directly affect the - kernel: saying N will just cause this configure script to skip all + kernel: saying N will just cause the configurator to skip all the questions about QoS support. Rate estimator @@ -8307,10 +9342,24 @@ This will enable you to use Differentiated Services (diffserv) and Resource Reservation Protocol (RSVP) on your Linux router. Documentation and software is at - http://icawww1.epfl.ch/linux-diffserv/ . + . + +Traffic policing (needed for in/egress) +CONFIG_NET_CLS_POLICE + Say Y to support traffic policing (bandwidth limits). Needed for + ingress and egress rate limiting. + +TC index classifier +CONFIG_NET_CLS_TCINDEX + If you say Y here, you will be able to classify outgoing packets + according to the tc_index field of the skb. You will want this + feature if you want to implement Differentiated Services using + sch_dsmark. If unsure, say Y. -### Add -#tristate ' TC index classifier' CONFIG_NET_CLS_TCINDEX + This code is also available as a module called cls_tcindex.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 . Routing tables based classifier CONFIG_NET_CLS_ROUTE4 @@ -8319,8 +9368,8 @@ 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. + whenever you want). If you want to compile it as a module, say M + here and read . Firewall based classifier CONFIG_NET_CLS_FW @@ -8329,8 +9378,8 @@ 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. + whenever you want). If you want to compile it as a module, say M + here and read . U32 classifier CONFIG_NET_CLS_U32 @@ -8339,8 +9388,8 @@ 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 + whenever you want). If you want to compile it as a module, say M + here and read . Special RSVP classifier CONFIG_NET_CLS_RSVP @@ -8353,8 +9402,8 @@ 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 + whenever you want). If you want to compile it as a module, say M + here and read . Special RSVP classifier for IPv6 CONFIG_NET_CLS_RSVP6 @@ -8368,15 +9417,8 @@ 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 - -# -# Traffic policing (needed for in/egress) -# CONFIG_NET_CLS_POLICE -### -### Some expert please fill these in -### + whenever you want). If you want to compile it as a module, say M + here and read . Network code profiler CONFIG_NET_PROFILE @@ -8405,10 +9447,10 @@ 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 +COSA/SRP sync serial board support CONFIG_COSA This is a driver for COSA and SRP synchronous serial boards. These boards allow to connect synchronous serial devices (for example @@ -8419,59 +9461,60 @@ 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 + up. Look at the 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 + 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. + modules read . -Etinc PCISYNC serial boards support +Etinc PCISYNC serial board support CONFIG_DSCC4 This is a driver for Etinc PCISYNC boards based on the Infineon (ex. Siemens) DSCC4 chipset. It is supposed to work with the four - ports card. Take a look at http://www.cogenit.fr/dscc4 + ports card. Take a look at for further informations about the driver and his configuration. 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 dscc4.o. For general information about - modules read Documentation/modules.txt. + modules read . -Lan Media sync serial boards support +LanMedia Corp. serial boards (SSI/V.35, T1/E1, HSSI, T3) CONFIG_LANMEDIA - This is a driver for the following Lan Media family of serial boards. - + This is a driver for the following Lan Media family of serial + boards. + LMC 1000 board allows you 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. - + LMC 1200 with on board DSU board allows you to connect your Linux box dirrectly to a T1 or E1 circuit. - - LMC 5200 board provides a HSSI interface capable of runnig up to + + LMC 5200 board provides a HSSI interface capable of running up to 52 mbits per second. - + LMC 5245 board connects directly to a T3 circuit saving the additional external hardware. - + To change setting such as syncPPP vs cisco HDLC or clock source you - will need lmcctl. It it available at ftp.lanmedia.com. - + will need lmcctl. It is available at . + This code is also available as a module called lmc.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. + here and read . Fibre Channel driver support CONFIG_NET_FC Fibre Channel is a high speed serial protocol mainly used to connect large storage devices to the computer; it is compatible with and - intended to replace SCSI. + intended to replace SCSI. If you intend to use Fibre Channel, you need to have a Fibre channel adaptor card in your computer; say Y here and to the driver for your @@ -8485,9 +9528,9 @@ The 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 iph5526.o. For general information about - modules read Documentation/modules.txt. - -Red Creek Hardware VPN (EXPERIMENTAL) + modules read . + +Red Creek Hardware VPN CONFIG_RCPCI This is a driver for hardware which provides a Virtual Private Network (VPN). Say Y if you have it. @@ -8495,19 +9538,28 @@ 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. - -SBNI12-xx support + here and read . + +Granch SBNI12 Leased Line adapter driver CONFIG_SBNI This is a driver for ISA SBNI12-xx cards which are low cost alternatives to leased line modems. Say Y if you want to insert the driver into the kernel or say M to compile it as a module (the - module will be called sbni.o). - - You can find more information and last versions of drivers and - utilities at http://www.granch.ru . If you have any question you + module will be called sbni.o). + + You can find more information and last versions of drivers and + utilities at . If you have any question you can send email to sbni@granch.ru. - + + Say N if unsure. + +SBNI Adapters Multiline feature +CONFIG_SBNI_MULTILINE + Schedule traffic for some parallel lines, via SBNI12 adapters. + If you have two computers connected with two parallel lines it's + possible to increase transfer rate nearly twice. You should have + a program named 'sbniconfig' to configure adapters. + Say N if unsure. WAN router drivers @@ -8519,27 +9571,26 @@ Router". You will need the wan-tools package which is available from - ftp://ftp.sangoma.com . Read Documentation/networking/wan-router.txt - for more information. + . Read + for more information. Note that the answer to this question won't directly affect the - kernel: saying N will just cause this configure script to skip all + kernel: saying N will just cause the configurator to skip all the questions about WAN router drivers. If unsure, say N. Sangoma WANPIPE(tm) multiprotocol cards CONFIG_VENDOR_SANGOMA + WANPIPE from Sangoma Technologies Inc. () + is a family of intelligent multiprotocol WAN adapters with data + transfer rates up to 4Mbps. They are also known as Synchronous + Data Link Adapters (SDLA) and are designated as S514-PCI or + S508-ISA. These cards support + + - X.25, Frame Relay, PPP, Cisco HDLC protocols. + + - API support for protocols like HDLC (LAPB), + HDLC Streaming, X.25, Frame Relay and BiSync. - WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com) - is a family of intelligent multiprotocol WAN adapters with data - transfer rates up to 4Mbps. They are also known as Synchronous - Data Link Adapters (SDLA) and are designated as S514-PCI or S508-ISA. - These cards support - - - X.25, Frame Relay, PPP, Cisco HDLC protocols. - - - API support for protocols like HDLC (LAPB), - HDLC Streaming, X.25, Frame Relay and BiSync. - - Ethernet Bridging over Frame Relay protocol. - MULTILINK PPP @@ -8547,32 +9598,32 @@ - Async PPP (Modem Dialup) If you have one or more of these cards, say M 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. + may then also want to read the file + . 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. + The module will be called wanpipe.o. For general information about + modules read . 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. Note, this feature also includes the X.25 API support used to develope custom applications over the X.25 protocol. - If you say N, the X.25 support will not be included in the driver. + If you say N, the X.25 support will not be included in the driver. The X.25 option is supported on S514-PCI and S508-ISA cards. 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, or use frame relay API to develope - custom applications over the Frame Relay protocol. + to a frame relay network, or use frame relay API to develope + custom applications over the Frame Relay protocol. This feature also contains the Ethernet Bridging over Frame Relay, - where a WANPIPE frame relay link can be directly connected to the Linux - kernel bridge. If you say N, the frame relay support will - not be included in the driver. The Frame Relay option is + where a WANPIPE frame relay link can be directly connected to the + Linux kernel bridge. If you say N, the frame relay support will + not be included in the driver. The Frame Relay option is supported on S514-PCI and S508-ISA cards. WANPIPE PPP support @@ -8582,70 +9633,71 @@ the PPP support will not be included in the driver. The PPP option is supported on S514-PCI/S508-ISA cards. -WANPIPE MultiPort PPP support +WANPIPE Multi-Port PPP support CONFIG_WANPIPE_MULTPPP Say Y to this option if you are planning to connect a WANPIPE card - to a leased line using Point-to-Point protocol (PPP). Note, the - MultiPort PPP uses the Linux Kernel SyncPPP protocol over the Sangoma - HDLC Streaming adapter. In this case each Sangoma adapter port - can support an independent PPP connection. For example, a single - Quad-Port PCI adapter can support up to four independent - PPP links. If you say N,the PPP support will not be included - in the driver. The PPP option is supported on S514-PCI/S508-ISA cards. - + to a leased line using Point-to-Point protocol (PPP). Note, the + MultiPort PPP uses the Linux Kernel SyncPPP protocol over the + Sangoma HDLC Streaming adapter. In this case each Sangoma adapter + port can support an independent PPP connection. For example, a + single Quad-Port PCI adapter can support up to four independent + PPP links. If you say N,the PPP support will not be included in the + driver. The PPP option is supported on S514-PCI/S508-ISA cards. + WANPIPE Cisco HDLC support CONFIG_WANPIPE_CHDLC Say Y to this option if you are planning to connect a WANPIPE card to a leased line using the Cisco HDLC protocol. This now supports - Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards. - This support also allows user to build applications using the - HDLC streaming API. - + Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards. + This support also allows user to build applications using the + HDLC streaming API. + CHDLC Streaming driver also supports MULTILINK PPP support that can bind multiple WANPIPE T1 cards into a single logical channel. - - If you say N, the Cisco HDLC support and - HDLC streaming API and MULTILINK PPP will not be + + If you say N, the Cisco HDLC support and + HDLC streaming API and MULTILINK PPP will not be included in the driver. -MultiGate/COMX support +MultiGate (COMX) synchronous serial board support CONFIG_COMX Say Y if you want to use any board from the MultiGate (COMX) family. These boards are synchronous serial adapters for the PC, manufactured by ITConsult-Pro Co, Hungary. - Read linux/Documentation/networking/comx.txt for help on configuring - and using COMX interfaces. Further info on these cards can be found - at http://www.itc.hu or . + Read for help on + configuring and using COMX interfaces. Further info on these cards + can be found at or . You must say Y to "/proc file system support" (CONFIG_PROC_FS) to use this driver. If you want to compile this as a module, say M and read - Documentation/modules.txt. The module will be called comx.o. + . The module will be called comx.o. -COMX/CMX/HiCOMX board support +Support for COMX/CMX/HiCOMX boards CONFIG_COMX_HW_COMX Hardware driver for the 'CMX', 'COMX' and 'HiCOMX' boards from the - MultiGate family. Say Y if you have one of these. + MultiGate family. Say Y if you have one of these. You will need additional firmware to use these cards, which are - downloadable from ftp://ftp.itc.hu/. + downloadable from . If you want to compile this as a module, say M and read - Documentation/modules.txt. The module will be called comx-hw-comx.o. + . The module will be called + comx-hw-comx.o. -LoCOMX board support +Support for LoCOMX board CONFIG_COMX_HW_LOCOMX Hardware driver for the 'LoCOMX' board from the MultiGate family. Say Y if you have a board like this. If you want to compile this as a module, say M and read - Documentation/modules.txt. The module will be called + . The module will be called comx-hw-locomx.o. -MixCOM board support +Support for MixCOM board CONFIG_COMX_HW_MIXCOM Hardware driver for the 'MixCOM' board from the MultiGate family. Say Y if you have a board like this. @@ -8655,63 +9707,63 @@ configuration. The ISDN interface of this card is Teles 16.3 compatible, you should enable it in the ISDN configuration menu. The driver for the flash ROM of this card is available separately on - ftp://ftp.itc.hu/. + . If you want to compile this as a module, say M and read - Documentation/modules.txt. The module will be called + . The module will be called comx-hw-mixcom.o. -i810 TCO support +i810 TCO timer/watchdog support CONFIG_I810_TCO Hardware driver for the TCO timer built into the Intel i810 and i815 - chipset family. The TCO (Total Cost of Ownership) timer is a watchdog - timer that will reboot the machine after it's second expiration. The - expiration time can be configured by commandline argument - "i810_margin=" where is the counter initial value. It is - decremented every 0.6 secs, the default is 50 which gives a timeout - of 30 seconds and one minute until reset. + chipset family. The TCO (Total Cost of Ownership) timer is a + watchdog timer that will reboot the machine after its second + expiration. The expiration time can be configured by commandline + argument "i810_margin=" where is the counter initial value. + It is decremented every 0.6 secs, the default is 50 which gives a + timeout of 30 seconds and one minute until reset. On some motherboards the driver may fail to reset the chipset's - NO_REBOOT flag which prevents the watchdog from rebooting the machine. - If this is the case you will get a kernel message like + NO_REBOOT flag which prevents the watchdog from rebooting the + machine. If this is the case you will get a kernel message like "i810tco init: failed to reset NO_REBOOT flag". If you want to compile this as a module, say M and read - Documentation/modules.txt. The module will be called + . The module will be called i810-tco.o. -MultiGate Cisco-HDLC and synchronous PPP protocol support +Support for HDLC and syncPPP protocols on MultiGate boards CONFIG_COMX_PROTO_PPP Cisco-HDLC and synchronous PPP protocol driver for all MultiGate boards. Say Y if you want to use either protocol on your MultiGate boards. If you want to compile this as a module, say M and read - Documentation/modules.txt. The module will be called + . The module will be called comx-proto-ppp.o. -MultiGate LAPB protocol support +Support for LAPB protocol on MultiGate boards CONFIG_COMX_PROTO_LAPB - LAPB protocol driver for all MultiGate boards. Say Y if you + LAPB protocol driver for all MultiGate boards. Say Y if you want to use this protocol on your MultiGate boards. If you want to compile this as a module, say M and read - Documentation/modules.txt. The module will be called + . The module will be called comx-proto-lapb.o. -MultiGate Frame Relay protocol support +Support for Frame Relay on MultiGate boards CONFIG_COMX_PROTO_FR - Frame Relay protocol driver for all MultiGate boards. Say Y if you + Frame Relay protocol driver for all MultiGate boards. Say Y if you want to use this protocol on your MultiGate boards. If you want to compile this as a module, say M and read - Documentation/modules.txt. The module will be called + . The module will be called comx-proto-fr.o. -Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL) +Cyclom 2X(tm) multiprotocol cards CONFIG_CYCLADES_SYNC - Cyclom 2X from Cyclades Corporation (http://www.cyclades.com and - http://www.cyclades.com.br) is an intelligent multiprotocol WAN + Cyclom 2X from Cyclades Corporation ( and + 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 @@ -8719,10 +9771,11 @@ 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 ). + wanconfig tarball in + (with minor changes + to make it compile with the current wanrouter include files; efforts + are being made to use the original package available at + ). Feel free to contact me or the cycsyn-devel mailing list at acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for @@ -8732,12 +9785,12 @@ 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. + modules read . 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. + 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). @@ -8747,41 +9800,69 @@ Say Y to this option if your Linux box contains a WAN card supported by this driver and you are planning to connect the box to a WAN ( = Wide Area Network). You will need supporting software from - http://hq.pm.waw.pl/hdlc/. + . Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame Relay, synchronous Point-to-Point Protocol (PPP) and X.25. If unsure, say N here. -Synchronous Point-to-Point Protocol (PPP) +Raw HDLC support +CONFIG_HDLC_RAW + Say Y to this option if you want generic HDLC driver to support + raw HDLC over WAN (Wide Area Network) connections. + + If unsure, say N here. + +Cisco HDLC support +CONFIG_HDLC_CISCO + Say Y to this option if you want generic HDLC driver to support + Cisco HDLC over WAN (Wide Area Network) connections. + + If unsure, say N here. + +Frame-Relay HDLC support +CONFIG_HDLC_FR + Say Y to this option if you want generic HDLC driver to support + Frame-Relay protocol over WAN (Wide Area Network) connections. + + If unsure, say N here. + +Frame-Relay bridging support +CONFIG_HDLC_FR_BRIDGE + Say Y to this option if you want generic HDLC driver to support + bridging LAN frames over Frame-Relay links. + + If unsure, say N here. + +Synchronous Point-to-Point Protocol (PPP) support CONFIG_HDLC_PPP Say Y to this option if you want generic HDLC driver to support PPP over WAN (Wide Area Network) connections. If unsure, say N here. -CCITT X.25 protocol +CCITT X.25 over HDLC support CONFIG_HDLC_X25 Say Y to this option if you want generic HDLC driver to support X.25 protocol over WAN (Wide Area Network) connections. If unsure, say N here. -SDL RISCom/N2 driver +SDL RISCom/N2 support CONFIG_N2 This driver is for RISCom/N2 single or dual channel ISA cards - made by SDL Communications Inc. If you have such a card, - say Y here and see http://hq.pm.waw.pl/pub/hdlc/ + made by SDL Communications Inc. If you have such a card, + say Y here and see . Note that N2csu and N2dds cards are not supported by this driver. If unsure, say N here. -Moxa C101 driver +Moxa C101 support CONFIG_C101 This driver is for C101 SuperSync ISA cards made by Moxa Technologies Co., Ltd. If you have such a card, - say Y here and see http://hq.pm.waw.pl/pub/hdlc/ + say Y here and see If unsure, say N here. @@ -8803,21 +9884,21 @@ 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://www.linuxdoc.org/docs.html#howto . You will then also have + . 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 + kernel: saying N will just cause the configurator to skip all the questions about Ethernet network cards. If unsure, say N. 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://www.linuxdoc.org/docs.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 + kernel: saying N will just cause the configurator 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. @@ -8825,32 +9906,32 @@ CONFIG_WD80x3 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called wd.o. If you want to compile it as a + module, say M here and read as well + as . 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://www.linuxdoc.org/docs.html#howto . + available from . 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. + The module will be called smc-mca.o. If you want to compile it as a + module, say M here and read as well + as . 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://www.linuxdoc.org/docs.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 @@ -8860,44 +9941,44 @@ 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. + The module will be called smc-ultra.o. If you want to compile it as + a module, say M here and read as + well as . 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://www.linuxdoc.org/docs.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. + The module will be called smc-ultra32.o. If you want to compile it + as a module, say M here and read as + well as . -SMC 9194 Support +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 + 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://www.linuxdoc.org/docs.html#howto . + and the Ethernet-HOWTO, + available from . 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. + 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 as well + as . -PCI NE2000 support +PCI NE2000 and clones 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://www.linuxdoc.org/docs.html#howto . + . This driver also works for the following NE2000 clone cards: RealTek RTL-8029 Winbond 89C940 Compex RL2000 KTI ET32P2 @@ -8906,64 +9987,64 @@ 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. + The module will be called ne2k-pci.o. If you want to compile it as + a module, say M here and read as + well as . 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://www.linuxdoc.org/docs.html#howto . + available from . Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause this configure script to skip all + kernel: saying N will just cause the configurator 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) +NI5010 support CONFIG_NI5010 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Note that this is still + . 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. + The module will be called ni5010.o. If you want to compile it as a + module, say M here and read as well + as . NI5210 support CONFIG_NI52 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called ni52.o. If you want to compile it as a + module, say M here and read as well + as . NI6510 support CONFIG_NI65 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called ni65.o. If you want to compile it as a + module, say M here and read as well + as . RealTek RTL-8139C+ 10/100 PCI Fast Ethernet Adapter support CONFIG_8139CP This is a driver for the Fast Ethernet PCI network cards based on the RTL8139C+ chips. If you have one of those, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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), @@ -8974,21 +10055,23 @@ CONFIG_8139TOO This is a driver for the Fast Ethernet PCI network cards based on the RTL8139 chips. If you have one of those, say Y and read - Documentation/networking/8139too.txt as well as the Ethernet-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . + as well as the + Ethernet-HOWTO, available from + . 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 8139too.o. + say M here and read . This is + recommended. The module will be called 8139too.o. Use PIO instead of MMIO CONFIG_8139TOO_PIO This instructs the driver to use programmed I/O ports (PIO) instead - of PCI shared memory (MMIO). This can possibly solve some problems in - case your mainboard has memory consistency issues. If unsure, say N. + of PCI shared memory (MMIO). This can possibly solve some problems + in case your mainboard has memory consistency issues. If unsure, + say N. -Support for automatic channel equalization (EXPERIMENTAL) +Support for automatic channel equalization CONFIG_8139TOO_TUNE_TWISTER This implements a function which might come in handy in case you are using low quality on long cabling. It tries to match the transceiver @@ -8998,40 +10081,40 @@ Support for older RTL-8129/8130 boards CONFIG_8139TOO_8129 This enables support for the older and uncommon RTL-8129 and - RTL-8130 chips, which support MII via an external transceiver, instead - of an internal one. Disabling this option will save some memory - by making the code size smaller. If unsure, say Y. + RTL-8130 chips, which support MII via an external transceiver, + instead of an internal one. Disabling this option will save some + memory by making the code size smaller. If unsure, say Y. -SiS 900 PCI Fast Ethernet Adapter support +SiS 900/7016 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 + SiS 630 and SiS 540 chipsets. If you have one of those, say Y and read the Ethernet-HOWTO, available at - http://www.linuxdoc.org/docs.html#howto . Please read - Documentation/networking/sis900.txt and comments at the beginning of - drivers/net/sis900.c for more information. + . Please read + and comments at the + beginning of for more information. This driver also supports AMD 79C901 HomePNA so that you can use your phone line as a 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. + say M here and read . This is + recommended. The module will be called sis900.o. Packet Engines Yellowfin Gigabit-NIC / Symbios 53c885 support CONFIG_YELLOWFIN Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is used by the Beowulf Linux cluster project. See - http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html for more + 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. + say M here and read . This is + recommended. The module will be called yellowfin.o. General Instruments Surfboard 1000 CONFIG_NET_SB1000 @@ -9044,29 +10127,29 @@ 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 + 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. -Adaptec Starfire support (EXPERIMENTAL) +Adaptec Starfire support CONFIG_ADAPTEC_STARFIRE Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network adapter. The DuraLAN chip is used on the 64 bit PCI boards from Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip 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. This is recommended. - The module will be called starfire.o. - + say M here and read . This is + recommended. The module will be called starfire.o. + Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support CONFIG_ACENIC Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear @@ -9078,16 +10161,16 @@ 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. + say M here and read . This is + recommended. The module will be called acenic.o. -Omit support for older Tigon I based AceNICs +Omit support for old 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 + 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. @@ -9107,148 +10190,170 @@ The driver also supports the following adapters from Allied Telesyn: - AT2970... - The dual link adapters support a link-failover feature. - Read Documentation/networking/sk98lin.txt for information about + The dual link adapters support a link-failover feature. Read + for information about optional driver parameters. Questions concerning this driver may be addressed to: linux@syskonnect.de 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 sk98lin.o. + say M here and read . This is + recommended. The module will be called sk98lin.o. + +Sun GEM support +CONFIG_SUNGEM + Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also + . MyriCOM Gigabit Ethernet support CONFIG_MYRI_SBUS - This driver supports MyriCOM Sbus gigabit ethernet cards. + This driver supports MyriCOM Sbus gigabit Ethernet cards. 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 myri_sbus.o. + say M here and read . This is + recommended. The module will be called myri_sbus.o. D-Link 2000-based Gigabit Ethernet support CONFIG_DL2K This driver supports D-Link 2000-based gigabit ethernet cards, which includes - D-Link DGE-550T Gigabit Ethernet Adapter. - D-Link DL2000-based Gigabit Ethernet Adapter. + D-Link DGE-550T Gigabit Ethernet Adapter. + D-Link DL2000-based Gigabit Ethernet Adapter. 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 dl2k.o. + say M here and read . This is + recommended. The module will be called dl2k.o. 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://www.linuxdoc.org/docs.html#howto . Some LinkSys cards are + . 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. + say M here and read . This is + recommended. The module will be called lance.o. SGI IOC3 Ethernet CONFIG_SGI_IOC3_ETH If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . + +National Semiconductor DP83902AV support +CONFIG_STNIC + Support for cards based on the National Semiconductor DP83902AV + ST-NIC Serial Network Interface Controller for Twisted Pair. This + is a 10Mbit/sec Ethernet controller. Product overview and specs at + . + +CompactFlash Connection Area +CONFIG_CF_AREA5 + If your board has "Directly Connected" CompactFlash, You should + select the area where your CF is connected to. + + - "Area5" if CompactFlash is connected to Area 5 (0x14000000) + - "Area6" if it is connected to Area 6 (0x18000000) + + "Area6" will work for most boards. For ADX, select "Area5". 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://www.linuxdoc.org/docs.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 + kernel: saying N will just cause the configurator 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 +3c501 "EtherLink" support CONFIG_EL1 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Also, consider buying a + . 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 + 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. + The module will be called 3c501.o. If you want to compile it as a + module, say M here and read as well + as . -3c503 support +3c503 "EtherLink II" support CONFIG_EL2 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called 3c503.o. If you want to compile it as a + module, say M here and read as well + as . -3c505 support +3c505 "EtherLink Plus" 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://www.linuxdoc.org/docs.html#howto . + . If you have a card of + this type, say Y and read the Ethernet-HOWTO, available from + . 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. + say M here and read as well as + . The module will be + called 3c505.o. -3c507 support (EXPERIMENTAL) +3c507 (EtherLink 16) support CONFIG_EL16 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called 3c507.o. If you want to compile it as a + module, say M here and read as well + as . -3c523 support +3c523 "EtherlinkMC" support CONFIG_ELMC If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called 3c523.o. If you want to compile it as a + module, say M here and read as well + as . -3c527 support +3c527 "EtherLink/MC 32" support CONFIG_ELMC_II If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called 3c527.o. If you want to compile it as a + module, say M here and read as well + as . -3c509/3c579 support +3c509/3c529 (MCA)/3c579 "EtherLink III" 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://www.linuxdoc.org/docs.html#howto . + from . 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 @@ -9256,23 +10361,23 @@ 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. + say M here and read as well as + . The module will be + called 3c509.o. 3c515 ISA Fast EtherLink CONFIG_3C515 If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet network card, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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 - 3c515.o. + say M here and read as well as + . The module will be + called 3c515.o. -3c59x/3c90x/3c575_Cardbus series "Vortex/Boomerang/Cyclone" support +3c590/3c900 series (592/595/597) "Vortex/Boomerang/Cyclone" support CONFIG_VORTEX This option enables driver support for a large number of 10mbps and 10/100mbps EISA, PCI and PCMCIA 3Com network cards: @@ -9283,15 +10388,16 @@ "Tornado" (3c905) PCI "Hurricane" (3c555/3cSOHO) PCI - If you have such a card, say Y and read the Ethernet-HOWTO, available - from http://www.linuxdoc.org/docs.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 have such a card, say Y and read the Ethernet-HOWTO, + available from . More + specific information is in + and in the comments at + the beginning of . 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. + say M here and read as well as + . Other ISA cards CONFIG_NET_ISA @@ -9299,19 +10405,20 @@ 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://www.linuxdoc.org/docs.html#howto . + available from . 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 + kernel: saying N will just cause the configurator 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. + (arguably) beautiful poetry in + . 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 @@ -9319,26 +10426,14 @@ support" below. You might also want to have a look at the Ethernet-HOWTO, available - from http://www.linuxdoc.org/docs.html#howto (even though ARCnet + from (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. + The module will be called arcnet.o. If you want to compile it as a + module, say M here and read as well + as . Enable old ARCNet packet format (RFC 1051) CONFIG_ARCNET_1051 @@ -9350,33 +10445,48 @@ 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 + documentation in for more information about using arc0e and arc0s. +Enable standard ARCNet packet format (RFC 1201) +CONFIG_ARCNET_1201 + This allows you to use RFC1201 with your ARCnet card via the virtual + arc0 device. You need to say Y here to communicate with + industry-standard RFC1201 implementations, like the arcether.com + packet driver or most DOS/Windows ODI drivers. Please read the + ARCnet documentation in + for more information about using arc0. + +Enable raw mode packet interface +CONFIG_ARCNET_RAW + ARCnet "raw mode" packet encapsulation, no soft headers. Unlikely + to work unless talking to a copy of the same Linux arcnet driver, + but perhaps marginally faster in that case. + 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. + 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. + The module will be called com90xx.o. If you want to compile it as a + module, say M here and read as well + as . 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. + 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. + The module will be called com90io.o. If you want to compile it as a + module, say M here and read as well + as . ARCnet COM90xx (RIM I) chipset driver CONFIG_ARCNET_RIM_I @@ -9387,197 +10497,198 @@ 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. + want). The module will be called arc-rimi.o. If you want to compile + it as a module, say M here and read + as well as . 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. + 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. + The module will be called com20020.o. If you want to compile it as + a module, say M here and read as + well as . 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://www.linuxdoc.org/docs.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. + The module will be called e2100.o. If you want to compile it as a + module, say M here and read as well + as . -CS89x0 support +CS89x0 support (Daynaport CS and LC cards) 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://www.linuxdoc.org/docs.html#howto as well as - Documentation/networking/cs89x0.txt. + as well as + . 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. + say M here and read as well as + . The module will be + called cs89x.o. -DEPCA support +DEPCA, DE10x, DE200, DE201, DE202, DE422 support CONFIG_DEPCA If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto as well as - drivers/net/depca.c. + as well as + . 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 + say M here and read as well as + . The module will be + called depca.o. -EtherWorks 3 support +EtherWORKS 3 (DE203, DE204, DE205) 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://www.linuxdoc.org/docs.html#howto . + in the kernel source as + well as the Ethernet-HOWTO, available from + . 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. + say M here and read as well as + . The module will be + called ewrk3.o. SEEQ8005 support CONFIG_SEEQ8005 - This is a driver for the SEEQ 8005 network (Ethernet) card. If this + This is a driver for the SEEQ 8005 network (Ethernet) card. If this is for you, read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + say M here and read as well as + . 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://www.linuxdoc.org/docs.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. + as well as + . 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://www.linuxdoc.org/docs.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. + The module will be called fmv18x.o. If you want to compile it as a + module, say M here and read as well + as . -EtherExpress PRO support +EtherExpressPro support/EtherExpress 10 (i82595) support CONFIG_EEXPRESS_PRO If you have a network (Ethernet) card of this type, say Y. This - driver supports intel i82595{FX,TX} based boards. Note however + driver supports intel i82595{FX,TX} based boards. Note however that the EtherExpress PRO/100 Ethernet card has its own separate - driver. Please read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + driver. Please read the Ethernet-HOWTO, available from + . 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. + The module will be called eepro.o. If you want to compile it as a + module, say M here and read as well + as . -EtherExpress support +EtherExpress 16 support CONFIG_EEXPRESS If you have an EtherExpress16 network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Note that the Intel + . 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. + say M here and read as well as + . The module will be + called eexpress.o. Packet Engines Hamachi GNIC-II support CONFIG_HAMACHI If you have a Gigabit Ethernet card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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 - hamachi.o. + say M here and read as well as + . The module will be + called hamachi.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://www.linuxdoc.org/docs.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. + The module will be called hp-plus.o. If you want to compile it as a + module, say M here and read as well + as . 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://www.linuxdoc.org/docs.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. + The module will be called hp.o. If you want to compile it as a + module, say M here and read as well + as . 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://www.linuxdoc.org/docs.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. + say M here and read as well as + . 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://www.linuxdoc.org/docs.html#howto . Many Ethernet cards + . 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 @@ -9588,74 +10699,76 @@ 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. + The module will be called ne.o. If you want to compile it as a + module, say M here and read as well + as . -National Semiconductor DP83810 series PCI Ethernet support +National Semiconductor DP8381x series PCI Ethernet support CONFIG_NATSEMI This driver is for the National Semiconductor DP83810 series, - including the 83815 chip. - More specific information and updates are available from - http://www.scyld.com/network/natsemi.html + which is used in cards from PureData, NetGear, Linksys + and others, including the 83815 chip. + More specific information and updates are available from + . 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://www.linuxdoc.org/docs.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://www.linuxdoc.org/docs.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. + The module will be called ne2.o. If you want to compile it as a + module, say M here and read as well + as . 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 + 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. + 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. + The module is called sk_mca.o. If you want to compile it as a + module, say M here and read as well + as . IBM LAN Adapter/A support CONFIG_IBMLANA - This is a Micro Channel ethernet adapter. You need to set CONFIG_MCA - to use this driver. It is both available as an in-kernel driver and - 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. If you plan to use more than - one network card under linux, read the Multiple-Ethernet-mini-HOWTO, - available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The only - currently supported card is the IBM LAN Adapter/A for Ethernet. It will - both support 16K and 32K memory windows, however a 32K window gives - a better security against packet losses. Usage of multiple boards with - this driver should be possible, but has not been tested up to now due - to lack of hardware. + This is a Micro Channel Ethernet adapter. You need to set + CONFIG_MCA to use this driver. It is both available as an in-kernel + driver and 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 + as well as . + If you plan to use more than one network card under linux, read the + Multiple-Ethernet-mini-HOWTO, available from + . The only + currently supported card is the IBM LAN Adapter/A for Ethernet. It + will both support 16K and 32K memory windows, however a 32K window + gives a better security against packet losses. Usage of multiple + boards with this driver should be possible, but has not been tested + up to now due to lack of hardware. EISA, VLB, PCI and on board controllers CONFIG_NET_PCI 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://www.linuxdoc.org/docs.html#howto . + available from . Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause this configure script to skip all + kernel: saying N will just cause the configurator 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. @@ -9664,98 +10777,100 @@ CONFIG_PCNET32 If you have a PCnet32 or PCnetPCI based network (Ethernet) card, answer Y here and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called pcnet32.o. If you want to compile it as a + module, say M here and read as well + as . 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://www.linuxdoc.org/docs.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. + The module will be called ac3200.o. If you want to compile it as a + module, say M here and read as well + as . -Mylex EISA LNE390A/LNE390B support (EXPERIMENTAL) +Mylex EISA LNE390A/LNE390B support CONFIG_LNE390 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called lne390.o. If you want to compile it as a + module, say M here and read as well + as . Novell/Eagle/Microdyne NE3210 EISA support CONFIG_NE3210 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Note that this driver + . 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. + The module will be called ne3210.o. If you want to compile it as a + module, say M here and read as well + as . 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://www.linuxdoc.org/docs.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. + say M here and read as well as + . 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 + 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://www.linuxdoc.org/docs.html#howto . More specific - information is contained in Documentation/networking/de4x5.txt. + . More specific + information is contained in + . 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. + The module will be called de4x5.o. If you want to compile it as a + module, say M here and read as well + as . DECchip Tulip (dc21x4x) PCI support CONFIG_TULIP 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 + 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 + cards, above. However, most people with a network card of this type will say Y here.) Do read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . More specific - information is contained in Documentation/networking/tulip.txt. + . More specific + information is contained in + . 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. + The module will be called tulip.o. If you want to compile it as a + module, say M here and read as well + as . -New Tulip bus configuration (EXPERIMENTAL) -CONFIG_TULIP_MWI +New Tulip bus configuration +CONFIG_TULIP_MWI This configures your Tulip card specifically for the card and system cache line size type you are using. @@ -9763,34 +10878,34 @@ If unsure, say N. -Digi Intl. RightSwitch support +Digi Intl. RightSwitch SE-X 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 + models. If you have a network card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . More specific - information is contained in Documentation/networking/dgrs.txt. + . More specific + information is contained in . 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. + The module will be called dgrs.o. If you want to compile it as a + module, say M here and read as well + as . -EtherExpress PRO/100 support +EtherExpress Pro/100 support CONFIG_EEPRO100 If you have an Intel EtherExpress PRO/100 PCI network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called eepro100.o. If you want to compile it as + a module, say M here and read as + well as . -Enable Power Management (EXPERIMENTAL) +Enable Power Management CONFIG_EEPRO100_PM Many Intel EtherExpress PRO/100 PCI network cards are capable of providing power management capabilities. To make use of these @@ -9802,34 +10917,40 @@ It is recommended to say N here. -ICL EtherTeam 16i/32 support (EXPERIMENTAL) +Myson MTD-8xx PCI Ethernet support +CONFIG_FEALNX + Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet + cards. Specifications and data at + . + +ICL EtherTeam 16i/32 support CONFIG_ETH16I If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called eth16i.o. If you want to compile it as a + module, say M here and read as well + as . -TI ThunderLAN support (EXPERIMENTAL) +TI ThunderLAN support 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://www.linuxdoc.org/docs.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. + Compaq NetFlex and Olicom cards. Please read the file + 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. + The module will be called tlan.o. If you want to compile it as a + module, say M here and read as well + as . Please email feedback to torben.mathiasen@compaq.com. @@ -9840,131 +10961,164 @@ 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. + The module will be called via-rhine.o. If you want to compile it as + a module, say M here and read as + well as . -PCI DM9102(A)/DM9132/DM9801 support +Davicom DM910x/DM980x support CONFIG_DM9102 This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from - Davicom ( http://www.davicom.com.tw ). If you have such a network - (Ethernet) card, say Y. Some information is contained in the file - Documentation/networking/dmfe.txt. - + Davicom (). If you have such a network + (Ethernet) card, say Y. Some information is contained in the file + . + 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. + The module will be called dmfe.o. If you want to compile it as a + module, say M here and read as well + as . -Racal-Interlan EISA ES3210 support (EXPERIMENTAL) +Racal-Interlan EISA ES3210 support CONFIG_ES3210 If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module will be called es3210.o. If you want to compile it as a + module, say M here and read as well + as . SMC EtherPower II CONFIG_EPIC100 This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC, which is based on the SMC83c17x (EPIC/100). More specific information and updates are available from - http://www.scyld.com/network/epic100.html + . -SGI Seeq ethernet controller support +DEC LANCE Ethernet controller support +CONFIG_DECLANCE + This driver is for the series of Ethernet controllers produced by + DEC (now Compaq) based on the AMD Lance chipset, including the + DEPCA series. (This chipset is better known via the NE2100 cards.) + +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. -Sundance "Alta" PCI Ethernet support +Sundance Alta PCI Ethernet support CONFIG_SUNDANCE This driver is for the Sundance "Alta" chip. More specific information and updates are available from - http://www.scyld.com/network/sundance.html + . + +Sun3/Sun3x on-board LANCE support +CONFIG_SUN3LANCE + Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80) + featured an AMD Lance 10Mbit Ethernet controller on board; say Y + here to compile in the Linux driver for this and enable Ethernet. + General Linux information on the Sun 3 and 3x series (now + discontinued) is at + . + + If you're not building a kernel for a Sun 3, say N. + +Sun3 on-board Intel 82586 support +CONFIG_SUN3_82586 + This driver enables support for the on-board Intel 82586 based + Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note + that this driver does not support 82586-based adapters on additional + VME boards. Winbond W89c840 PCI Ethernet support CONFIG_WINBOND_840 This driver is for the Winbond W89c840 chip. It also works with the TX9882 chip on the Compex RL100-ATX board. More specific information and updates are available from - http://www.scyld.com/network/drivers.html + . -Zenith Z-Note support (EXPERIMENTAL) +Zenith Z-Note support 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://www.linuxdoc.org/docs.html#howto . + . + +Philips SAA9730 Ethernet support +CONFIG_LAN_SAA9730 + The SAA9730 is a combined multimedia and peripheral controller used + in thin clients, Internet access terminals, and diskless + workstations. + See . 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://www.linuxdoc.org/docs.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. + ) 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 + kernel: saying N will just cause the configurator 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://www.linuxdoc.org/docs.html#howto , if you - want to use this. If you intend to use this driver, you should have + port. Read as well as the Ethernet-HOWTO, + available from , 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. 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 atp.o. + whenever you want), say M here and read + . The module will be called atp.o. 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 + port. Read as well as the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , if you want to use + , 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. + whenever you want), say M here and read + . 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 + port. Read as well as the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , if you want to use + , 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. + whenever you want), say M here and read + . The module will be called de620.o. Token Ring driver support @@ -9975,41 +11129,41 @@ 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://www.linuxdoc.org/docs.html#howto . Most people can + from . 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://www.linuxdoc.org/docs.html#howto . + available from . Warning: this driver will almost definitely fail if more than one - active Token Ring card is present. + 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. + module, say M here and read . IBM Olympic chipset PCI adapter support CONFIG_IBMOL - This is support for all non-Lanstreamer IBM PCI Token Ring Cards. + 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://www.linuxdoc.org/docs.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 olympic.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + as a module, say M here and read . - Also read the file Documentation/networking/olympic.txt or check the + Also read or check the Linux Token Ring Project site for the latest information at - http://www.linuxtr.net . + . IBM Lanstreamer chipset PCI adapter support CONFIG_IBMLS @@ -10017,12 +11171,12 @@ If you have such an adapter, say Y and read the Token-Ring mini-HOWTO available via FTP (user:anonymous) from - ftp://metalab.unc/edu/pub/Linux/docs/HOWTO. + . This driver is also available as a modules ( = code which can be inserted in and removed from the running kernel whenever you want). The modules will be called lanstreamer.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + as a module, say M here and read . Generic TMS380 Token Ring ISA/PCI/MCA/EISA adapter support CONFIG_TMS380TR @@ -10037,15 +11191,15 @@ If you have such an adapter and would like to use it, say Y and read the Token-Ring mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + . - Also read the file Documentation/networking/tms380tr.txt or - check http://www.auk.cx/tms380tr/ . + Also read the file or + check . 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 tms380tr.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + as a module, say M here and read . Generic TMS380 PCI support CONFIG_TMSPCI @@ -10060,19 +11214,31 @@ This driver is available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called tmspci.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + as a module, say M here and read . + +Generic TMS380 ISA support +CONFIG_TMSISA + This tms380 module supports generic TMS380-based ISA cards. + + These cards are known to work: + - SysKonnect TR4/16 ISA (SK-4190) + + This driver is available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tmsisa.o. If you want to compile it + as a module, say M here and read . Madge Smart 16/4 PCI Mk2 support CONFIG_ABYSS - This tms380 module supports the Madge Smart 16/4 PCI Mk2 + This tms380 module supports the Madge Smart 16/4 PCI Mk2 cards (51-02). This driver is available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called abyss.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + as a module, say M here and read . -Madge Smart 16/4 Ringode MicroChannel +Madge Smart 16/4 Ringnode MicroChannel CONFIG_MADGEMC This tms380 module supports the Madge Smart 16/4 MC16 and MC32 MicroChannel adapters. @@ -10080,9 +11246,9 @@ This driver is available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called madgemc.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + as a module, say M here and read . -SMC ISA TokenRing adapter support +SMC ISA/MCA Token Ring adapter support CONFIG_SMCTR This is support for the ISA and MCA SMC Token Ring cards, specifically SMC TokenCard Elite (8115T) and SMC TokenCard Elite/A @@ -10090,13 +11256,13 @@ 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://www.linuxdoc.org/docs.html#howto and the file - Documentation/networking/smctr.txt. + and the file + . 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 smctr.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + as a module, say M here and read . Sun Happy Meal 10/100baseT support CONFIG_HAPPYMEAL @@ -10108,60 +11274,62 @@ This support is also available as a module called sunhme.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. + here and read . Sun Lance support CONFIG_SUNLANCE This driver supports the "le" interface present on all 32-bit Sparc - systems, on some older Ultra systems and as an Sbus option. + systems, on some older Ultra systems and as an Sbus option. These + cards are based on the AMD Lance chipset, which is better known + via the NE2100 cards. This support is also available as a module called sunlance.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. + here and read . -Sun BigMAC 10/100baseT support (EXPERIMENTAL) +Sun BigMAC 10/100baseT support CONFIG_SUNBMAC This driver supports the "be" interface available as an Sbus option. - This is Sun's older 100baseT ethernet device. + This is Sun's older 100baseT Ethernet device. This support is also available as a module called sunbmac.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. + here and read . Sun QuadEthernet support CONFIG_SUNQE - This driver supports the "qe" 10baseT ethernet device, available as + This driver supports the "qe" 10baseT Ethernet device, available as an Sbus option. Note that this is not the same as Quad FastEthernet "qfe" which is supported by the Happy Meal driver instead. This support is also available as a module called sunqe.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. + here and read . -Traffic Shaper (EXPERIMENTAL) +Traffic Shaper 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. + these virtual devices. See + 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 + program, available from 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. + The module will be called shaper.o. If you want to compile it as a + module, say M here and read . If + unsure, say N. FDDI driver support CONFIG_FDDI @@ -10196,8 +11364,8 @@ - Netelligent 100 FDDI DAS UTP - Netelligent 100 FDDI SAS UTP - Netelligent 100 FDDI SAS Fibre MIC - - Read Documentation/networking/skfp.txt for information about + + Read for information about the driver. Questions concerning this driver can be addressed to: @@ -10205,10 +11373,10 @@ 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 skfp.o. + say M here and read . This is + recommended. The module will be called skfp.o. -HIgh Performance Parallel Interface support (EXPERIMENTAL) +HIgh Performance Parallel Interface (HIPPI) support CONFIG_HIPPI HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI @@ -10218,16 +11386,16 @@ 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. + The module will be called rrunner.o. If you want to compile it as a + module, say M here and read . If + unsure, say N. Use large TX/RX rings CONFIG_ROADRUNNER_LARGE_RINGS @@ -10237,80 +11405,92 @@ kernel code or by user space programs. Say Y here only if you have the memory. -Acorn Ether1 card +Acorn Ether1 support 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 +Acorn/ANT Ether3 support 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 +I-Cubed EtherH support 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 +EBSA-110 Ethernet interface (AM79C961A) 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 +Support Thumb instructions +CONFIG_ARM_THUMB + Say Y if you want to have kernel support for ARM Thumb instructions, + fault handlers, and system calls. + + The Thumb instruction set is a compressed form of the standard ARM + instruction set resulting in smaller binaries at the expense of + slightly less efficient code. + + If you don't know what this all is, saying Y is a safe choice. + +Support CD-ROM 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://www.linuxdoc.org/docs.html#howto . + If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y + here, otherwise N. Read the CD-ROM-HOWTO, available from + . 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 + kernel: saying N will just cause the configurator to skip all + the questions about these CD-ROM drives. If you are unsure what you have, say Y and find out whether you have one of the following - drives. + drives. - For each of these drivers, a file Documentation/cdrom/ + For each of these drivers, a file Documentation/cdrom/{driver_name} 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. + file drivers/cdrom/{driver_name}.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 + All these CD-ROM 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. + read . - If you want to use any of these CDROM drivers, you also have to - answer Y or M to "ISO 9660 CDROM file system support" below (this + If you want to use any of these CD-ROM drivers, you also have to + answer Y or M to "ISO 9660 CD-ROM file system support" below (this answer will get "defaulted" for you if you enable any of the Linux - CDROM drivers). + CD-ROM drivers). -Sony CDU31A/CDU33A CDROM support +Sony CDU31A/CDU33A CD-ROM 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. + These CD-ROM drives have a spring-pop-out caddyless drawer, and a + rectangular green LED centered beneath it. NOTE: these CD-ROM + 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 or fill + in your parameters into . Try "man + bootparam" or see the documentation of your boot loader (lilo or + loadlin) about how to pass options to the kernel. - If you say Y here, you should also say Y or M to "ISO 9660 CDROM + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM file system support" below, because that's the file system used on - CDROMs. + CD-ROMs. 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. + The module will be called cdu31a.o. If you want to compile it as a + module, say M here and read . -Standard Mitsumi [no XA/Multisession] CDROM support +Standard Mitsumi [no XA/Multisession] CD-ROM 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. + IDE/ATAPI models). Please also the file + . 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. @@ -10318,184 +11498,201 @@ (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 + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM file system support" below, because that's the file system used on - CDROMs. + CD-ROMs. 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. + module, say M here and read . 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"). + said M to "Standard Mitsumi CD-ROM 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"). + if you said M to "Standard Mitsumi CD-ROM support"). -Mitsumi [XA/MultiSession] support +Mitsumi [XA/MultiSession] CD-ROM 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 + FX-001 or FX-001D CD-ROM 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 + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM file system support" below, because that's the file system used on - CDROMs. + CD-ROMs. 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. + module, say M here and read . -Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support +Matsushita/Panasonic/Creative, Longshine, TEAC CD-ROM 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. + Sound Blaster interface. Please read the file + . 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 + Longshine LCS-7260, the "IBM External ISA CD-ROM" (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 + 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 + 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 + none of the supported drives gets found. Once your drive got found, + you should enter the reported parameters into + and set "DISTRIBUTION 0" there. + + This driver can support up to four CD-ROM controller cards, and each + card can support up to four CD-ROM 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 + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM file system support" below, because that's the file system used on - CDROMs. + CD-ROMs. 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. + The module will be called sbpcd.o. If you want to compile it as a + module, say M here and read . -Matsushita/Panasonic, ... second CDROM controller support +Matsushita/Panasonic, ... second CD-ROM 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 + Say Y here only if you have two CD-ROM 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 - include/linux/sbpcd.h before compiling the new kernel. Read - the file Documentation/cdrom/sbpcd. + before compiling the new kernel. Read + the file . + +Matsushita/Panasonic, ... third CD-ROM controller support +CONFIG_SBPCD3 + Say Y here only if you have three CD-ROM controller cards of this + type (usually only if you have more than six drives). You should + enter the parameters for the second, third and fourth interface card + into before compiling the new kernel. + Read the file . + +Matsushita/Panasonic, ... fourth CD-ROM controller support +CONFIG_SBPCD4 + Say Y here only if you have four CD-ROM controller cards of this + type (usually only if you have more than eight drives). You should + enter the parameters for the second, third and fourth interface card + into before compiling the new kernel. + Read the file . -Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support +Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CD-ROM 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. + CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCD-ROM CR520 or + CR540 CD-ROM drive. This driver -- just like all these CD-ROM + drivers -- is NOT for CD-ROM drives with IDE/ATAPI interfaces, such + as Aztech CDA269-031SE. Please read the file + . - If you say Y here, you should also say Y or M to "ISO 9660 CDROM + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM file system support" below, because that's the file system used on - CDROMs. + CD-ROMs. 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. + The module will be called aztcd.o. If you want to compile it as a + module, say M here and read . -Sony CDU535 CDROM support +Sony CDU535 CD-ROM 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. + This is the driver for the older Sony CDU-535 and CDU-531 CD-ROM + drives. Please read the file . - If you say Y here, you should also say Y or M to "ISO 9660 CDROM + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM file system support" below, because that's the file system used on - CDROMs. + CD-ROMs. 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. + a module, say M here and read . -Goldstar R420 CDROM support +Goldstar R420 CD-ROM support CONFIG_GSCD - If this is your CDROM drive, say Y here. As described in the file - Documentation/cdrom/gscd, you might have to change a setting - in the file drivers/cdrom/gscd.h before compiling the - kernel. Please read the file Documentation/cdrom/gscd. + If this is your CD-ROM drive, say Y here. As described in the file + , you might have to change a setting + in the file before compiling the + kernel. Please read the file . - If you say Y here, you should also say Y or M to "ISO 9660 CDROM + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM file system support" below, because that's the file system used on - CDROMs. + CD-ROMs. 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. + The module will be called gscd.o. If you want to compile it as a + module, say M here and read . -Philips/LMS CM206 CDROM support +Philips/LMS CM206 CD-ROM support CONFIG_CM206 - If you have a Philips/LMS CDROM drive cm206 in combination with a + If you have a Philips/LMS CD-ROM 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 + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM file system support" below, because that's the file system used on - CDROMs. + CD-ROMs. 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. + module, say M here and read . -Optics Storage DOLPHIN 8000AT CDROM support +Optics Storage DOLPHIN 8000AT CD-ROM 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. + Optics Storage 8001 drive; use the IDE-ATAPI CD-ROM driver for that + one. Please read the file . - If you say Y here, you should also say Y or M to "ISO 9660 CDROM + If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM file system support" below, because that's the file system used on - CDROMs. + CD-ROMs. 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. + module, say M here and read . -Sanyo CDR-H94A CDROM support +Sanyo CDR-H94A CD-ROM 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 file system support" below, because that's the - file system used on CDROMs. + If this is your CD-ROM drive, say Y here and read the file + . You should then also say Y or M to + "ISO 9660 CD-ROM file system support" below, because that's the + file system used on CD-ROMs. 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. + module, say M here and read . ISP16/MAD16/Mozart soft configurable cdrom interface support CONFIG_ISP16_CDI @@ -10503,12 +11700,17 @@ 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. + card. Read 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. + module, say M here and read . + +iSeries Virtual I/O CD Support +CONFIG_VIOCD + If you are running Linux on an IBM iSeries system and you want to + read a CD drive owned by OS/400, say Y here. Quota support CONFIG_QUOTA @@ -10516,13 +11718,13 @@ usage (also called disk quotas). Currently, it works only for the ext2 file system. You need additional software in order to use quota support; for details, read the Quota mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . Probably the quota + . Probably the quota support is only useful for multi user systems. If unsure, say N. Memory Technology Device (MTD) support CONFIG_MTD Memory Technology Devices are flash, RAM and similar chips, often - used for solid state filesystems on embedded devices. This option + used for solid state file systems on embedded devices. This option will provide the generic support for MTD drivers to register themselves with the kernel and for potential users of MTD devices to enumerate the devices which are present and obtain a handle on @@ -10548,18 +11750,17 @@ RedBoot partition table parsing CONFIG_MTD_REDBOOT_PARTS RedBoot is a ROM monitor and bootloader which deals with multiple - 'images' in flash devices by putting a table in the last erase - block of the device, similar to a partition table, which gives - the offsets, lengths and names of all the images stored in the - flash. + 'images' in flash devices by putting a table in the last erase block + of the device, similar to a partition table, which gives the + offsets, lengths and names of all the images stored in the flash. If you need code which can detect and parse this table, and register MTD 'partitions' corresponding to each image in the table, enable - this option. + this option. You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The - SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for + for your particular device. It won't happen automatically. The + SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for example. Compaq bootldr partition table parsing @@ -10567,11 +11768,11 @@ The Compaq bootldr deals with multiple 'images' in flash devices by putting a table in one of the first erase blocks of the device, similar to a partition table, which gives the offsets, lengths and - names of all the images stored in the flash. + names of all the images stored in the flash. If you need code which can detect and parse this table, and register MTD 'partitions' corresponding to each image in the table, enable - this option. + this option. You will still need the parsing functions to be called by the driver for your particular device. It won't happen automatically. The @@ -10582,21 +11783,20 @@ CONFIG_MTD_AFS_PARTS The ARM Firmware Suite allows the user to divide flash devices into multiple 'images'. Each such image has a header containing its name - and offset/size etc. + and offset/size etc. - If you need code which can detect and parse these tables, and register - MTD 'partitions' corresponding to each image detected, enable - this option. + If you need code which can detect and parse these tables, and + register MTD 'partitions' corresponding to each image detected, + enable this option. You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The + for your particular device. It won't happen automatically. The 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. -MTD debugging verbosity +MTD debugging verbosity (0 = quiet, 3 = noisy) CONFIG_MTD_DEBUG_VERBOSE Determines the verbosity level of the MTD debugging messages. - Direct chardevice access to MTD devices CONFIG_MTD_CHAR This provides a character device for each MTD device present in @@ -10608,8 +11808,8 @@ CONFIG_MTD_BLOCK Although most flash chips have an erase size too large to be useful as block devices, it is possible to use MTD devices which are based - on RAM chips in this manner. This block device is a user of MTD devices - performing that function. + on RAM chips in this manner. This block device is a user of MTD + devices performing that function. At the moment, it is also required for the Journalling Flash File System(s) to obtain a handle on the MTD device when it's mounted @@ -10618,7 +11818,7 @@ Later, it may be extended to perform read/erase/modify/write cycles on flash chips to emulate a smaller block size. Needless to say, - this is very unsafe, but could be useful for filesystems which are + this is very unsafe, but could be useful for file systems which are almost never written to. You do not need this option for use with the DiskOnChip devices. For @@ -10626,9 +11826,9 @@ Readonly block device access to MTD devices CONFIG_MTD_BLOCK_RO - This allows you to mount read-only filesystems (such as cramfs) from - an MTD device, without the overhead (and danger) of the caching - driver. + This allows you to mount read-only file systems (such as cramfs) + from an MTD device, without the overhead (and danger) of the caching + driver. You do not need this option for use with the DiskOnChip devices. For those, enable NFTL support (CONFIG_NFTL) instead. @@ -10637,8 +11837,8 @@ CONFIG_FTL This provides support for the original Flash Translation Layer which is part of the PCMCIA specification. It uses a kind of pseudo- - filesystem on a flash device to emulate a block device with 512-byte - sectors, on top of which you put a 'normal' filesystem. + file system on a flash device to emulate a block device with + 512-byte sectors, on top of which you put a 'normal' file system. You may find that the algorithms used in this code are patented unless you live in the Free World where software patents aren't @@ -10651,8 +11851,8 @@ CONFIG_NFTL This provides support for the NAND Flash Translation Layer which is used on M-Systems' DiskOnChip devices. It uses a kind of pseudo- - filesystem on a flash device to emulate a block device with 512-byte - sectors, on top of which you put a 'normal' filesystem. + file system on a flash device to emulate a block device with + 512-byte sectors, on top of which you put a 'normal' file system. You may find that the algorithms used in this code are patented unless you live in the Free World where software patents aren't @@ -10663,9 +11863,10 @@ Write support for NFTL (EXPERIMENTAL) CONFIG_NFTL_RW - If you're lucky, this will actually work. Don't whinge if it doesn't. - Send mail to the MTD mailing list if - you want to help to make it more reliable. + If you're lucky, this will actually work. Don't whinge if it + doesn't. Send mail to the MTD mailing list + if you want to help to make it more + reliable. Common Flash Interface (CFI) support CONFIG_MTD_CFI @@ -10673,7 +11874,7 @@ AMD and other flash manufactures that provides a universal method for probing the capabilities of flash devices. If you wish to support any device that is CFI-compliant, you need to enable this - option. Visit (http://www.amd.com/products/nvd/overview/cfi.html) + option. Visit for more information on CFI. CFI Advanced configuration options @@ -10724,6 +11925,7 @@ If your flash chips are interleaved in fours - i.e. you have four flash chips addressed by each bus cycle, then say 'Y'. +# Choice: mtd_swap_data Flash cmd/query data swapping CONFIG_MTD_CFI_NOSWAP This option defines the way in which the CPU attempts to arrange @@ -10732,7 +11934,7 @@ enabled, means that the CPU will not do any swapping; the chips are expected to be wired to the CPU in 'host-endian' form. Specific arrangements are possible with the BIG_ENDIAN_BYTE and - LITTLE_ENDIAN_BYTE, if the bytes are reversed. + LITTLE_ENDIAN_BYTE, if the bytes are reversed. If you have a LART, on which the data (and address) lines were connected in a fashion which ensured that the nets were as short @@ -10741,14 +11943,14 @@ Yes, there really exists something sicker than PDP-endian :) -CFI support for Intel/Sharp Extended Commands +CFI support for Intel/Sharp Extended Command Set chips CONFIG_MTD_CFI_INTELEXT The Common Flash Interface defines a number of different command sets which a CFI-compliant chip may claim to implement. This code provides support for one of those command sets, used on Intel StrataFlash and other parts. -CFI support for AMD/Fujitsu Standard Commands +CFI support for AMD/Fujitsu Standard Command Set chips CONFIG_MTD_CFI_AMDSTD The Common Flash Interface defines a number of different command sets which a CFI-compliant chip may claim to implement. This code @@ -10785,26 +11987,36 @@ This option enables basic support for ROM chips accessed through a bus mapping driver. +JEDEC device support CONFIG_MTD_JEDEC - Enable older older JEDEC flash interface devices for self programming - flash. It is commonly used in older AMD chips. It is only called - JEDEC because the JEDEC association (http://www.jedec.org/) - distributes the identification codes for the chips. WARNING!!!! This - code does not compile and is incomplete as are the specific JEDEC - devices drivers. + Enable older older JEDEC flash interface devices for self + programming flash. It is commonly used in older AMD chips. It is + only called JEDEC because the JEDEC association + distributes the identification codes for the + chips. WARNING!!!! This code does not compile and is incomplete as + are the specific JEDEC devices drivers. CFI Flash device mapped on StrongARM SA11x0 CONFIG_MTD_SA1100 - This enables access to the flash chips on most platforms based on the - SA1100 and SA1110, including the Assabet and the Compaq iPAQ. If you - have such a board, say 'Y'. + This enables access to the flash chips on most platforms based on + the SA1100 and SA1110, including the Assabet and the Compaq iPAQ. + If you have such a board, say 'Y'. +Support for Compaq bootldr partition tables on SA11x0 CONFIG_MTD_SA1100_REDBOOT_PARTITIONS Enabling this option will cause the kernel to look for a RedBoot FIS (Flash Image System) table in the last erase block of the flash chips detected. If you are using RedBoot on your SA11x0-based board and want Linux to present 'partitions' matching the images which - RedBoot has listed, say 'Y'. + RedBoot has listed, say 'Y'. + +Support for Compaq bootldr partition tables on SA11x0 +CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS + Enabling this option will cause the kernel to look for a Compaq + bootldr partition table on the flash chips detected. If you are + using the Compaq bootldr on your SA11x0-based board and want Linux + to present 'partitions' matching the images which the bootldr has + listed, say 'Y'. Flash chip mapping in physical memory CONFIG_MTD_PHYSMAP @@ -10830,6 +12042,7 @@ map which should hopefully be in the documentation for your board. +Buswidth of flash in bytes CONFIG_MTD_PHYSMAP_BUSWIDTH This is the total width of the data bus of the flash devices in octets. For example, if you have a data bus width of 32 @@ -10847,7 +12060,7 @@ CONFIG_MTD_NORA If you had to ask, you don't have one. Say 'N'. -Flash chip mapping on PNC2000 +Flash chip mapping on Photron PNC-2000 CONFIG_MTD_PNC2000 PNC-2000 is the name of Network Camera product from PHOTRON Ltd. in Japan. It uses CFI-compliant flash. @@ -10858,7 +12071,7 @@ a strange sparse mapping. This 'mapping' driver supports that arrangement, allowing the CFI probe and command set driver code to communicate with the chips on the RPXLite board. More at - (http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm). + . Flash chip mapping on AMD SC520 CDP board CONFIG_MTD_SC520CDP @@ -10866,47 +12079,67 @@ Dual-in-line JEDEC chip. This 'mapping' driver supports that arrangement, implementing three MTD devices. -Flash chip mapping on Arcom Control Systems' SBC-MediaGX -CONFIG_MTD_SBC_MEDIAGX +Flash chip mapping on Arcom Control Systems SBC-MediaGX +CONFIG_MTD_SBC_GXX This provides a driver for the on-board flash of Arcom Control - Systems' SBC-MediaGX development board. By default the flash - is split into 3 partitions which are accessed as separate MTD - devices. This board utilizes Intel StrataFlash. More info at - (http://www.arcomcontrols.com/products/icp/pc104/processors/). + Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX. + By default the flash is split into 3 partitions which are accessed + as separate MTD devices. This board utilizes Intel StrataFlash. + More info at + . + +CFI Flash device mapped on D-Box2 +CONFIG_MTD_DBOX2 + This enables access routines for the flash chips on the Nokia/Sagem + D-Box 2 board. If you have one of these boards and would like to use + the flash chips on it, say 'Y'. + +CFI Flash device mapped on the XScale IQ80310 board +CONFIG_MTD_IQ80310 + This enables access routines for the flash chips on the Intel XScale + IQ80310 evaluation board. If you have one of these boards and would + like to use the flash chips on it, say 'Y'. + +CFI Flash device mapped on AMD NetSc520 +CONFIG_MTD_NETSC520 + This enables access routines for the flash chips on the AMD NetSc520 + demonstration board. If you have one of these boards and would like + to use the flash chips on it, say 'Y'. -Flash chip mapping on Arcom Control Systems' ELAN-104NC +Flash chip mapping on Arcom Control Systems ELAN-104NC CONFIG_MTD_ELAN_104NC This provides a driver for the on-board flash of the Arcom Control System's ELAN-104NC development board. By default the flash is split into 3 partitions which are accessed as separate MTD devices. This board utilizes Intel StrataFlash. More info at - (http://www.arcomcontrols.com/products/icp/pc104/processors/). + . Flash chip mapping on Compaq iPAQ/Bitsy CONFIG_MTD_BITSY This provides a driver for the on-board flash found in Compaq's iPAQ Palm PC and their research prototype the Itsy. iPAQ info at - (http://www5.compaq.com/products/handhelds/pocketpc/) and the - Itsy (http://www.research.digital.com/wrl/projects/Itsy/index.html). + and the + Itsy . Flash chip mapping on Compaq iPAQ/Bitsy CONFIG_MTD_DC21285 This provides a driver for the flash accessed using Intel's 21285 bridge used with Intel's StrongARM processors. More info at - (http://developer.intel.com/design/bridge/quicklist/dsc-21285.htm). + . Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board CONFIG_MTD_CSTM_MIPS_IXX - This provides a mapping driver for the Integrated Tecnology - Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference - Board. It provides the necessary addressing, length, buswidth, vpp code - and addition setup of the flash device for these boards. In addition, - this mapping driver can be used for other boards via setting of the - CONFIG_MTD_CSTM_MIPS_IXX_START/LEN/BUSWIDTH parameters. This mapping - will provide one mtd device using one partition. The start address can - be offset from the beginning of flash and the len can be less than the - total flash device size to allow a window into the flash. Both CFI and - JEDEC probes are called. + This provides a mapping driver for the Integrated Tecnology Express, + Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference + Board. It provides the necessary addressing, length, buswidth, vpp + code and addition setup of the flash device for these boards. In + addition, this mapping driver can be used for other boards via + setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/LEN/BUSWIDTH + parameters. This mapping will provide one mtd device using one + partition. The start address can be offset from the beginning of + flash and the len can be less than the total flash device size to + allow a window into the flash. Both CFI and JEDEC probes are + called. Physical start location of flash mapping CONFIG_MTD_CSTM_MIPS_IXX_START @@ -10920,7 +12153,7 @@ This is the total length that the MTD driver will use for the flash chips on your particular board. Refer to the memory map which should hopefully be in the documentation for your - board. + board. Physical bus width of flash mapping CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH @@ -10934,26 +12167,26 @@ to get on with their job of driving the flash chips without having to know about the paging. If you have one of these boards, you probably want to enable this mapping driver. More info is at - (http://www.itc.hu/). + . Flash chip mapping on Octagon 5066 SBC CONFIG_MTD_OCTAGON This provides a 'mapping' driver which supports the way in which the flash chips are connected in the Octagon-5066 Single Board Computer. More information on the board is available at - (http://www.octagonsystems.com/Products/5066/5066.html). + . Flash chip mapping on Tempustech VMAX SBC301 CONFIG_MTD_VMAX This provides a 'mapping' driver which supports the way in which the flash chips are connected in the Tempustech VMAX SBC301 Single Board Computer. More information on the board is available at - (http://www.tempustech.com/tt301.htm). + . Support for NAND flash devices CONFIG_MTD_NAND This enables support for accessing all type of NAND flash - devices. + devices. Support for software ECC algorithm CONFIG_MTD_NAND_ECC @@ -10983,96 +12216,102 @@ M-Systems Disk-On-Chip 2000 and Millennium support CONFIG_MTD_DOC2000 This provides an MTD device driver for the M-Systems DiskOnChip - 2000 and Millennium devices. Originally designed for the DiskOnChip - 2000, it also now includes support for the DiskOnChip Millennium. + 2000 and Millennium devices. Originally designed for the DiskOnChip + 2000, it also now includes support for the DiskOnChip Millennium. If you have problems with this driver and the DiskOnChip Millennium, you may wish to try the alternative Millennium driver below. To use the alternative driver, you will need to undefine DOC_SINGLE_DRIVER - in the drivers/mtd/devices/docprobe.c source code. + in the source code. If you use this device, you probably also want to enable the NFTL - 'NAND Flash Translation Layer' option below, which is used to emulate - a block device by using a kind of filesystem on the flash chips. + 'NAND Flash Translation Layer' option below, which is used to + emulate a block device by using a kind of file system on the flash + chips. Alternative Disk-On-Chip Millennium support CONFIG_MTD_DOC2001 This provides an alternative MTD device driver for the M-Systems - DiskOnChip Millennium devices. Use this if you have problems with - the combined DiskOnChip 2000 and Millennium driver above. To get + DiskOnChip Millennium devices. Use this if you have problems with + the combined DiskOnChip 2000 and Millennium driver above. To get the DiskOnChip probe code to load and use this driver instead of the other one, you will need to undefine DOC_SINGLE_DRIVER near - the beginning of drivers/mtd/devices/docprobe.c + the beginning of . If you use this device, you probably also want to enable the NFTL - 'NAND Flash Translation Layer' option below, which is used to emulate - a block device by using a kind of filesystem on the flash chips. + 'NAND Flash Translation Layer' option below, which is used to + emulate a block device by using a kind of file system on the flash + chips. Probe for DiskOnChip devices CONFIG_MTD_DOCPROBE - This isn't a real config option, it's derived. + This isn't a real config option, it's derived. Advanced detection options for DiskOnChip CONFIG_MTD_DOCPROBE_ADVANCED This option allows you to specify nonstandard address at which to - probe for a DiskOnChip, or to change the detection options. You're - unlikely to need any of this unless you're using LinuxBIOS. Say 'N'. + probe for a DiskOnChip, or to change the detection options. You + are unlikely to need any of this unless you are using LinuxBIOS. + Say 'N'. -Probe for 0x55 0xAA BIOS Extension Signature. +Probe for 0x55 0xAA BIOS Extension Signature CONFIG_MTD_DOCPROBE_55AA - Check for the 0x55 0xAA signature of a DiskOnChip, and do not continue - with probing if it is absent. The signature will always be present for - a DiskOnChip 2000 or a normal DiskOnChip Millennium. Only if you have - overwritten the first block of a DiskOnChip Millennium will it be - absent. Enable this option if you are using LinuxBIOS or if you need - to recover a DiskOnChip Millennium on which you have managed to wipe - the first block. + Check for the 0x55 0xAA signature of a DiskOnChip, and do not + continue with probing if it is absent. The signature will always be + present for a DiskOnChip 2000 or a normal DiskOnChip Millennium. + Only if you have overwritten the first block of a DiskOnChip + Millennium will it be absent. Enable this option if you are using + LinuxBIOS or if you need to recover a DiskOnChip Millennium on which + you have managed to wipe the first block. Physical address of DiskOnChip CONFIG_MTD_DOCPROBE_ADDRESS - By default, the probe for DiskOnChip devices will look for a DiskOnChip - at every multiple of 0x2000 between 0xC8000 and 0xEE000. This option - allows you to specify a single address at which to probe for the device, - which is useful if you have other devices in that range which get upset - when they're probed. + By default, the probe for DiskOnChip devices will look for a + DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. + This option allows you to specify a single address at which to probe + for the device, which is useful if you have other devices in that + range which get upset when they are probed. - (Note that on PowerPC, the normal probe will only check at 0xE4000000.) + (Note that on PowerPC, the normal probe will only check at + 0xE4000000.) - Normally, you should leave this set to zero, to allow the probe at the - normal addresses. + Normally, you should leave this set to zero, to allow the probe at + the normal addresses. Probe high addresses CONFIG_MTD_DOCPROBE_HIGH - By default, the probe for DiskOnChip devices will look for a DiskOnChip - at every multiple of 0x2000 between 0xC8000 and 0xEE000. This option - changes to make it probe between 0xFFFC8000 and 0xFFFEE000. Unless - you're using LinuxBIOS, this is unlikely to be useful to you. Say 'N'. + By default, the probe for DiskOnChip devices will look for a + DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. + This option changes to make it probe between 0xFFFC8000 and + 0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be + useful to you. Say 'N'. Ramix PMC551 PCI Mezzanine ram card support CONFIG_MTD_PMC551 This provides a MTD device driver for the Ramix PMC551 RAM PCI card - from Ramix Inc. (http://www.ramix.com/products/memory/pmc551.html). + from Ramix Inc. . These devices come in memory configurations from 32M - 1G. If you have one, you probably want to enable this. - If this driver is compiled as a module you get the ability to select the - size of the aperture window pointing into the devices memory. What this - means is that if you have a 1G card, normally the kernel will use a 1G - memory map as it's view of the device. As a module, you can select a - 1M window into the memory and the driver will "slide" the window around - the PMC551's memory. This was particularly useful on the 2.2 kernels - on PPC architectures as there was limited kernel space to deal with. + If this driver is compiled as a module you get the ability to select + the size of the aperture window pointing into the devices memory. + What this means is that if you have a 1G card, normally the kernel + will use a 1G memory map as its view of the device. As a module, + you can select a 1M window into the memory and the driver will + "slide" the window around the PMC551's memory. This was + particularly useful on the 2.2 kernels on PPC architectures as there + was limited kernel space to deal with. PMC551 256M DRAM Bugfix CONFIG_MTD_PMC551_BUGFIX - Some of Ramix's PMC551 boards with 256M configurations have invalid column - and row mux values. This option will fix them, but will break other memory - configurations. If unsure say N. + Some of Ramix's PMC551 boards with 256M configurations have invalid + column and row mux values. This option will fix them, but will + break other memory configurations. If unsure say N. PMC551 Debugging CONFIG_MTD_PMC551_DEBUG - This option makes the PMC551 more verbose during it's operation and is only - really usefull if you are developing on this driver or suspect a possible - hardware or driver bug. If unsure say N. + This option makes the PMC551 more verbose during its operation and + is only really useful if you are developing on this driver or + suspect a possible hardware or driver bug. If unsure say N. Use extra onboard system memory as MTD device CONFIG_MTD_SLRAM @@ -11083,24 +12322,24 @@ Debugging RAM test driver CONFIG_MTD_MTDRAM This enables a test MTD device driver which uses vmalloc() to - provide storage. You probably want to say 'N' unless you're + provide storage. You probably want to say 'N' unless you're testing stuff. -MTDRAM erase block size in KiB +MTDRAM erase block size in KB CONFIG_MTDRAM_ERASE_SIZE This allows you to configure the size of the erase blocks in the - device emulated by the MTDRAM driver. If the MTDRAM driver is built + device emulated by the MTDRAM driver. If the MTDRAM driver is built as a module, it is also possible to specify this as a parameter when loading the module. -MTDRAM device size in KiB +MTDRAM device size in KB CONFIG_MTDRAM_TOTAL_SIZE This allows you to configure the total size of the MTD device - emulated by the MTDRAM driver. If the MTDRAM driver is built + emulated by the MTDRAM driver. If the MTDRAM driver is built as a module, it is also possible to specify this as a parameter when loading the module. -SRAM absolute position +SRAM Hexadecimal Absolute position or 0 CONFIG_MTDRAM_ABS_POS If you have system RAM accessible by the CPU but not used by Linux in normal operation, you can give the physical address at which the @@ -11110,34 +12349,40 @@ Flash chip mapping on the Flaga Digital Module CONFIG_MTD_CFI_FLAGADM - Mapping for the Flaga digital module. If you don´t have one, ignore this - setting. + Mapping for the Flaga digital module. If you don´t have one, ignore + this setting. + +Momenco Ocelot boot flash device +CONFIG_MTD_OCELOT + This enables access routines for the boot flash device and for the + NVRAM on the Momenco Ocelot board. If you have one of these boards + and would like access to either of these, say 'Y'. -Support for USB +USB (Universal Serial Bus) support CONFIG_USB Universal Serial Bus (USB) is a specification for a serial bus subsystem 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 + 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 leaves and the inner - nodes are special USB devices called hubs. Many newer PC's have USB + 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 use 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 to the operating system) and then choose from - among the drivers for USB peripherals. You may want to check out the - information provided in Documentation/usb/ and especially the links - given in Documentation/usb/usb-help.txt. + 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 to the operating system) and then choose + from among the drivers for USB peripherals. You may want to check + out the information provided in and + especially the links given in . 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. + The module will be called usbcore.o. If you want to compile it as a + module, say M here and read . USB verbose debug messages CONFIG_USB_DEBUG @@ -11160,14 +12405,14 @@ USB long timeout CONFIG_USB_LONG_TIMEOUT This option makes the standard time out a bit longer. Basically, - some devices are just slow to respond, so this makes usb more + some devices are just slow to respond, so this makes usb more patient. There should be no harm in selecting this, but it is needed for some MGE Ellipse UPSes. If you have an MGE Ellipse UPS, or you see timeouts in HID transactions, say Y; otherwise say N. -UHCI (intel PIIX4, VIA, ...) support +UHCI (Intel PIIX4, VIA, ...) 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 @@ -11179,15 +12424,15 @@ 133). Currently there exist two drivers for UHCI host controllers: this - one and the so-called JE driver, which you can get from + one and the so-called JE driver, which you can get from "UHCI alternate (JE) support", below. You need only one. 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. + module, say M here and read . -UHCI (intel PIIX4, VIA, ...) alternate (JE) support? +UHCI (Intel PIIX4, VIA, ...) alternate (JE) support CONFIG_USB_UHCI_ALT The Universal Host Controller Interface is a standard by Intel for accessing the USB hardware in the PC (which is also called the USB @@ -11205,11 +12450,7 @@ 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 uhci.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. - -UHCI unlink optimizations (EXPERIMENTAL) -CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE - This option currently does nothing. You may say Y or N. + module, say M here and read . OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support CONFIG_USB_OHCI @@ -11221,12 +12462,12 @@ -- like SiS (aktual 610, 610 and so on) or ALi (ALi IV, ALi V, Aladdin Pro..) -- conform to this standard. - You may want to read the file Documentation/usb/ohci.txt. + You may want to read . 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. + as a module, say M here and read . USB Human Interface Device (full HID) support CONFIG_USB_HID @@ -11234,14 +12475,14 @@ mice, joysticks, graphic tablets, or any other HID based devices to your computer via USB. You can't use this driver and the HIDBP (Boot Protocol) keyboard and mouse drivers at the same time. - More information is available: Documentation/input/input.txt. + More information is available: . 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 hid.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . /dev/usb/hiddev raw HID device support CONFIG_USB_HIDDEV @@ -11266,7 +12507,7 @@ 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 usbkbd.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . If unsure, say N. @@ -11279,41 +12520,41 @@ 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 usbmouse.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read . If unsure, say N. Wacom Intuos/Graphire tablet support CONFIG_USB_WACOM Say Y here if you want to use the USB version of the Wacom Intuos - or Graphire tablet. Make sure to say Y to "Mouse support" + or Graphire tablet. Make sure to say Y to "Mouse support" (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" (CONFIG_INPUT_EVDEV) 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 wacom.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called wacom.o. If you want to compile it as a + module, say M here and read . -Logitech WingMan Force joystick support -CONFIG_USB_WMFORCE - Say Y here if you want to use the Logitech WingMan Force with Linux - on the USB port. No force-feedback support yet, but other than that - it should work like a normal joystick. +Aiptek 8000U tablet support +CONFIG_USB_AIPTEK + Say Y here if you want to use the USB version of the Aiptek 8000U + tablet. Make sure to say Y to "Event interface support" + (CONFIG_INPUT_EVDEV) 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 wmforce.o. If you want to compile it as a + The module will be called aiptek.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. Use input layer for ADB devices CONFIG_INPUT_ADBHID Say Y here if you want to have ADB (Apple Desktop Bus) HID devices - such as keyboards, mice, joysticks, or graphic tablets handled by the - input layer. If you say Y here, make sure to say Y to the + such as keyboards, mice, joysticks, or graphic tablets handled by + the input layer. If you say Y here, make sure to say Y to the corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV), - "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface support" - (CONFIG_INPUT_EVDEV) as well. + "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface + support" (CONFIG_INPUT_EVDEV) as well. If you say N here, you still have the option of using the old ADB keyboard and mouse drivers. @@ -11333,12 +12574,13 @@ Keyboard support CONFIG_INPUT_KEYBDEV Say Y here if you want your USB HID keyboard (or an ADB keyboard - handled by the input layer) to be able to serve as a system keyboard. + handled by the input layer) to be able to serve as a system + keyboard. 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 keybdev.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called keybdev.o. If you want to compile it as a + module, say M here and read . Mouse support CONFIG_INPUT_MOUSEDEV @@ -11347,13 +12589,13 @@ /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated ImPS/2 mouse. That way, all user space programs will be able to use your mouse. - + If unsure, 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 mousedev.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read . Horizontal screen resolution CONFIG_INPUT_MOUSEDEV_SCREEN_X @@ -11372,71 +12614,81 @@ Joystick support CONFIG_INPUT_JOYDEV Say Y here if you want your USB HID joystick or gamepad to be - accessible as char device 13:0+ - /dev/input/jsX device. + accessible as char device 13:0+ - /dev/input/jsX device. 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 joydev.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . Event interface support CONFIG_INPUT_EVDEV - Say Y here if you want your USB or ADB HID device events be accessible - under char device 13:64+ - /dev/input/eventX in a generic way. - This is the future ... + Say Y here if you want your USB or ADB HID device events be + accessible under char device 13:64+ - /dev/input/eventX in a generic + way. This is the future ... USB Scanner support CONFIG_USB_SCANNER Say Y here if you want to connect a USB scanner to your computer's - USB port. Please read Documentation/usb/scanner.txt and - Documentation/usb/scanner-hp-sane.txt for more information. + USB port. Please read and + 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 scanner.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read . + +HP 5300C scanner support +CONFIG_USB_HP5300 + Say Y here if you want to connect a HP5300C scanner 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 hp5300.o. If you want to compile it as + a module, say M here and read . USB Audio support CONFIG_USB_AUDIO - Say Y here if you want to connect UAB audio equipment such as + Say Y here if you want to connect USB audio equipment such as 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. + module, say M here and read . USB Modem (CDC ACM) support CONFIG_USB_ACM This driver supports USB modems and ISDN adapters which support the Communication Device Class Abstract Control Model interface. - Please read Documentation/usb/acm.txt for details. + Please read for details. 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. + module, say M here and read . -USB Serial converter support +USB serial converter support CONFIG_USB_SERIAL Say Y here if you have a USB device that provides normal serial ports, or acts like a serial device, and you want to connect it to your USB bus. - Please read Documentation/usb/usb-serial.txt for more information - on the specifics of the different devices that are supported, and - on how to use them. - + Please read for more + information on the specifics of the different devices that are + supported, and on how to use them. + 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 usbserial.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + The module will be called usbserial.o. If you want to compile it + as a module, say M here and read . USB Generic Serial Driver CONFIG_USB_SERIAL_GENERIC - Say Y here if you want to use the generic USB serial driver. Please - read Documentation/usb/usb-serial.txt for more information on using - this driver. It is recommended that the "USB Serial converter + Say Y here if you want to use the generic USB serial driver. Please + read for more information on + using this driver. It is recommended that the "USB Serial converter support" be compiled as a module for this driver to be used properly. @@ -11447,20 +12699,20 @@ 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 whiteheat.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called whiteheat.o. If you want to compile it as + a module, say M here and read . USB Handspring Visor Driver CONFIG_USB_SERIAL_VISOR - Say Y here if you want to connect to your HandSpring Visor, Palm m500 - or m505 through its USB docking station. - See http://usbvisor.sourceforge.net for more information on using this + Say Y here if you want to connect to your HandSpring Visor, Palm + m500 or m505 through its USB docking station. See + for more information on using this driver. 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 visor.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . USB Belkin and Paracom Single Port Serial Driver CONFIG_USB_SERIAL_BELKIN @@ -11471,20 +12723,20 @@ 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 belkin_sa.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read . USB FTDI Single Port Serial Driver CONFIG_USB_SERIAL_FTDI_SIO Say Y here if you want to use a FTDI SIO single port USB to serial converter device. The implementation I have is called the USC-1000. - See http://reality.sgi.com/bryder_wellington/ftdi_sio for more + See for more information on this driver and the device. 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 ftdi_sio.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called ftdi_sio.o. If you want to compile it as + a module, say M here and read . USB Keyspan PDA Single Port Serial Driver CONFIG_USB_SERIAL_KEYSPAN_PDA @@ -11494,8 +12746,8 @@ 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 keyspan_pda.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + The module will be called keyspan_pda.o. If you want to compile it + as a module, say M here and read . USB Xircom / Entregra Single Port Serial Driver CONFIG_USB_SERIAL_XIRCOM @@ -11513,14 +12765,14 @@ Say Y here if you want to use Keyspan USB to serial converter devices. This driver makes use of Keyspan's official firmware and was developed with their support. You must also include - firmware to support your particular device(s). + firmware to support your particular device(s). + + See for more information. - See http://misc.nu/hugh/keyspan.html 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 keyspan.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . USB Keyspan USA-28 Firmware CONFIG_USB_SERIAL_KEYSPAN_USA28 @@ -11566,8 +12818,8 @@ 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 omninet.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called omninet.o. If you want to compile it as a + module, say M here and read . USB Digi International AccelePort USB Serial Driver CONFIG_USB_SERIAL_DIGI_ACCELEPORT @@ -11581,33 +12833,34 @@ 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 digi_acceleport.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called digi_acceleport.o. If you want to compile + it as a module, say M here and read + . USB Empeg empeg-car Mark I/II Driver CONFIG_USB_SERIAL_EMPEG Say Y here if you want to connect to your Empeg empeg-car Mark I/II mp3 player via USB. The driver uses a single ttyUSB{0,1,2,...} - device node. See Documentation/usb/usb-serial.txt for more + device node. See for more tidbits of 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 empeg.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . USB MCT Single Port Serial Driver CONFIG_USB_SERIAL_MCT_U232 Say Y here if you want to use a USB Serial single port adapter from Magic Control Technology Corp. (U232 is one of the model numbers). - + This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB BAY devices. 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 mct_u232.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read . USB Prolific 2303 Single Port Serial Driver CONFIG_USB_SERIAL_PL2303 @@ -11617,19 +12870,19 @@ 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 pl2303.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read . USB REINER SCT cyberJack pinpad/e-com chipcard reader CONFIG_USB_SERIAL_CYBERJACK Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard reader. This is an interface to ISO 7816 compatible contactbased chipcards, e.g. GSM SIMs. - + 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 cyberjack.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. - + a module, say M here and read . + If unsure, say N. USB Edgeport Serial Driver @@ -11655,8 +12908,8 @@ 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 io_edgeport.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + The module will be called io_edgeport.o. If you want to compile it + as a module, say M here and read . USB Serial Converter verbose debug CONFIG_USB_SERIAL_DEBUG @@ -11671,57 +12924,85 @@ 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. + module, say M here and read . USB IBM (Xirlink) C-It Camera support CONFIG_USB_IBMCAM Say Y here if you want to connect a IBM "C-It" camera, also known as - "Xirlink PC Camera" to your computer's USB port. For more - information, read Documentation/usb/ibmcam.txt. + "Xirlink PC Camera" to your computer's USB port. For more + information, read . This driver uses the Video For Linux API. You must enable (Y or M in config) Video For Linux (under Character Devices) to use this driver. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . 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 ibmcam.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. This camera - has several configuration options which can be specified when you - load the module. Read Documentation/usb/ibmcam.txt to learn more. + The module will be called ibmcam.o. If you want to compile it as a + module, say M here and read . This + camera has several configuration options which can be specified when + you load the module. Read to + learn more. USB OV511 Camera support CONFIG_USB_OV511 Say Y here if you want to connect this type of camera to your - computer's USB port. See Documentation/usb/ov511.txt for more + computer's USB port. See for more information and for a list of supported cameras. - + This driver uses the Video For Linux API. You must say Y or M to "Video For Linux" (under Character Devices) to use this driver. Information on this API and pointers to "v4l" programs may be found - on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml . + on the WWW at . 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 ov511.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . + +USB Communication Class Ethernet driver +CONFIG_USB_CDCETHER + This driver supports devices conforming to the Communication Device + Class Ethernet Control Model. This is used in some cable modems. + For more details on the specification, get the Communication Device + Class specification from . + + This driver should work with the following devices: + * Ericsson PipeRider (all variants) + * Motorola (DM100 and SB4100) + * Broadcom Cable Modem (reference design) + * Toshiba PCX1100U and possibly other cable modems + + The device creates a network device (ethX, where X depends on what + other networking devices you have in use), as for a normal PCI + or ISA based ethernet network card. + + 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 CDCEther.o. If you want to compile it as + a module, say M here and read . + +NetChip 1080-based USB Host-to-Host Link +CONFIG_USB_NET1080 + The NetChip 1080 is a USB 1.1 host controller. NetChip has a web + site with technical information at . Philips webcam support CONFIG_USB_PWC Say Y or M here if you want to use one of these Philips USB webcams: - PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or - the Askey VC010. The PCA635, PCVC665 and PCVC720 are not - supported by this driver and never will be. - - This driver has an optional plugin, which is distributed as a - binary module only. It contains code that allow you to use - higher resolutions and framerates but may not be distributed - as source. But even without this plugin you can these cams - for most applications. + PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or + the Askey VC010. The PCA635, PCVC665 and PCVC720 are not supported + by this driver and never will be. + + This driver has an optional plugin, which is distributed as a binary + module only. It contains code that allow you to use higher + resolutions and framerates but may not be distributed as source. + But even without this plugin you can these cams for most + applications. - See Documentation/usb/philips.txt for more information and + See for more information and installation instructions. The built-in microphone is enabled by selecting USB Audio support. @@ -11729,29 +13010,12 @@ This driver uses the Video For Linux API. You must say Y or M to "Video For Linux" (under Character Devices) to use this driver. Information on this API and pointers to "v4l" programs may be found - on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml . - - 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 pwc.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. - - -USB SE401 Camera support -CONFIG_USB_SE401 - Say Y here if you want to connect this type of camera to your - computer's USB port. See Documentation/usb/se401.txt for more - information and for a list of supported cameras. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Multimedia Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml . + on the WWW at . 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 se401.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called pwc.o. If you want to compile it as a + module, say M here and read . Pegasus/Pegasus II based USB-Ethernet device support CONFIG_USB_PEGASUS @@ -11765,8 +13029,9 @@ 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 pegasus.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . +USB KLSI KL5USB101-based Ethernet device support ' CONFIG_USB_KAWETH Say Y here if you want to use one of the following 10Mbps only USB Ethernet adapters based on the KLSI KL5KUSB101B chipset: @@ -11783,7 +13048,7 @@ Kingston Technology USB Ethernet Adapter Linksys USB10T Mobility USB-Ethernet Adapter - NetGear EA-101 + NetGear EA-101 Peracom Enet and Enet2 Portsmith Express Ethernet Adapter Shark Pocket Adapter @@ -11815,62 +13080,39 @@ CATC NetMate II smartBridges smartNIC + This driver makes the adapter appear as a normal Ethernet interface, + typically on eth0, if it is the only ethernet device, or perhaps on + eth1, if you have a PCI or ISA ethernet card installed. + 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 catc.o. If you want to compile it as a module, say M here and read . -USB Communication Class Ethernet driver -CONFIG_USB_CDCETHER - This driver supports devices conforming to the Communication Device - Class Ethernet Control Model. This is used in some cable modems. - For more details on the specification, get the Communication Device - Class specification from . - - This driver should work with the following devices: - * Ericsson PipeRider (all variants) - * Motorola (DM100 and SB4100) - * Broadcom Cable Modem (reference design) - * Toshiba PCX1100U and possibly other cable modems - - The device creates a network device (ethX, where X depends on what - other networking devices you have in use), as for a normal PCI - or ISA based ethernet network card. - - 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 CDCEther.o. If you want to compile it as - a module, say M here and read . - -NetChip 1080-based USB Host-to-Host Link -CONFIG_USB_NET1080 - The NetChip 1080 is a USB 1.1 host controller. NetChip has a web - site with technical information at http://www.netchip.com/ . - 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 Documentation/usb/dc2xx.txt for more - information; some non-Kodak cameras may also work with this - driver, given application support (such as www.gPhoto.org). + Say Y here if you want to connect this type of still camera to your + computer's USB port. See for + more information; some non-Kodak cameras may also work with this + driver, given application support (such as ). 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. + module, say M here and read . -USB Mustek MDC800 Digital Camera Support +USB Mustek MDC800 Digital Camera support CONFIG_USB_MDC800 Say Y here if you want to connect this type of still camera to your computer's USB port. This driver can be used with gphoto 0.4.3 - and higher (look at http://www.gphoto.org ). + and higher (look at ). To use it create a device node with "mknod /dev/mustek c 180 32" and configure it in your software. 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 mdc800.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . USB Mass Storage support CONFIG_USB_STORAGE @@ -11880,7 +13122,7 @@ 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-storage.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + as a module, say M here and read . USB Mass Storage verbose debug CONFIG_USB_STORAGE_DEBUG @@ -11907,7 +13149,7 @@ Technologies USS-720 chip. These cables are plugged into your USB port and 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 @@ -11927,29 +13169,33 @@ 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. - + module, say M here and read . + USB device file system CONFIG_USB_DEVICEFS - If you say Y here (and to "/proc file system support" below), you - will get a file /proc/bus/usb/devices which lists the devices - currently connected to your USB busses, a file /proc/bus/usb/drivers - which lists the USB kernel client drivers currently loaded, and for - every connected device a file named "/proc/bus/usb/xxx/yyy", where - xxx is the bus number and yyy the device number; the latter files - can be used by user space programs to talk directly to the device. - These files are "virtual", meaning they are generated on the fly - and not stored on the hard drive. - - For the format of the /proc/bus/usb/ files, please read - Documentation/usb/proc_usb_info.txt. + If you say Y here (and to "/proc file system support" in the "File + systems section, above), you will get a file /proc/bus/usb/devices + which lists the devices currently connected to your USB bus or + busses, a file /proc/bus/usb/drivers which lists the USB kernel + client drivers currently loaded, and for every connected device a + file named "/proc/bus/usb/xxx/yyy", where xxx is the bus number and + yyy the device number; the latter files can be used by user space + programs to talk directly to the device. These files are "virtual", + meaning they are generated on the fly and not stored on the hard + drive. + + You may need to mount the usbdevfs file system to see the files, use + mount -t usbdevfs none /proc/bus/usb + + For the format of the various /proc/bus/usb/ files, please read + . Please note that this code is completely unrelated to devfs, the "/dev file system support". Most users want to say Y here. -USB Bandwidth allocation +Enforce USB bandwidth allocation CONFIG_USB_BANDWIDTH If you say Y here, the USB subsystem enforces USB bandwidth allocation and will prevent some device opens from succeeding @@ -11963,23 +13209,25 @@ DABUSB driver CONFIG_USB_DABUSB A Digital Audio Broadcasting (DAB) Receiver for USB and Linux - brought to you by the DAB-Team (http://dab.in.tum.de). This driver - can be taken as an example for URB-based bulk, control, and + brought to you by the DAB-Team (). This + driver can be taken as an example for URB-based bulk, control, and isochronous transactions. URB's are explained in - Documentation/usb/URB.txt. + . 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 dabusb.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The module will be called dabusb.o. If you want to compile it as a + module, say M here and read . Host-to-Host USB networking CONFIG_USB_USBNET This driver supports network links over USB with USB "Network" or "data transfer" cables, often used to network laptops to PCs. - Such cables have chips from suppliers such as NetChip and Prolific. - Intelligent USB devices could also use this approach to provide - Internet access, using standard USB cabling. + Such cables have chips from suppliers such as Belkin/eTEK, GeneSys + (GeneLink), NetChip and Prolific. Intelligent USB devices could also + use this approach to provide Internet access, using standard USB + cabling. You can find these chips also on some motherboards with + USB PC2PC support. These links will have names like "usb0", "usb1", etc. They act like two-node Ethernets, so you can use 802.1d Ethernet Bridging @@ -11990,16 +13238,32 @@ The module will be called usbnet.o. If you want to compile it as a module, say M here and read . +Freecom USB/ATAPI Bridge support +CONFIG_USB_STORAGE_FREECOM + Support for the Freecom USB to IDE/ATAPI adaptor. + Freecom has a web page at . + +Microtech CompactFlash/SmartMedia reader +CONFIG_USB_STORAGE_DPCM + Say Y here to support the Microtech ZiO! CompactFlash/SmartMedia + reader, details at . + This driver treats the flash card as a removable storage device. + +Sandisk SDDR-09 SmartMedia reader support +CONFIG_USB_STORAGE_SDDR09 + Say Y here to include additional code to support the Sandisk SDDR-09 + SmartMedia reader in the USB Mass Storage driver. + USB Diamond Rio500 support CONFIG_USB_RIO500 Say Y here if you want to connect a USB Rio500 mp3 player to your - computer's USB port. Please read Documentation/usb/rio.txt + computer's USB port. Please read 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 rio500.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read . D-Link DSB-R100 FM radio support CONFIG_USB_DSBR @@ -12012,18 +13276,256 @@ (Y or M in config) Video For Linux (under Character Devices) to use this driver. Information on this API and pointers to "v4l" programs may be found on the WWW at - http://roadrunner.swansea.uk.linux.org/v4l.shtml . + . 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 dsbr100.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . + +Always do synchronous disk IO for UBD +CONFIG_BLK_DEV_UBD_SYNC + The User-Mode Linux port includes a driver called UBD which will let + you access arbitrary files on the host computer as block devices. + Writes to such a block device are not immediately written to the + host's disk; this may cause problems if, for example, the User-Mode + Linux 'Virtual Machine' uses a journalling file system and the host + computer crashes. + + Synchronous operation (i.e. always writing data to the host's disk + immediately) is configurable on a per-UBD basis by using a special + kernel command line option. Alternatively, you can say Y here to + turn on synchronous operation by default for all block. + + If you're running a journalling file system (like reiserfs, for + example) in your virtual machine, you will want to say Y here. If + you care for the safety of the data in your virtual machine, Y is a + wise choice too. In all other cases (for example, if you're just + playing around with User-Mode Linux) you can choose N. + +Enable ptrace proxy +CONFIG_PT_PROXY + This option enables a debugging interface which allows gdb to debug + the kernel without needing to actually attach to kernel threads. + If you want to do kernel debugging, say Y here; otherwise say N. + +Management console +CONFIG_MCONSOLE + The user mode linux management console is a low-level interface to + the kernel, somewhat like the i386 SysRq interface. Since there is + a full-blown operating system running under every user mode linux + instance, there is much greater flexibility possible than with the + SysRq mechanism. + + If you answer 'Y' to this option, to use this feature, you need the + mconsole client (called uml_mconsole) which is present in CVS in + 2.4.5-9um and later (path /tools/mconsole), and is also in the + distribution RPM package in 2.4.6 and later. + + It is safe to say 'Y' here. + +Enable kernel debugging symbols +CONFIG_DEBUGSYM + When this is enabled, the User-Mode Linux binary will include + debugging symbols. This enlarges the binary by a few megabytes, + but aids in tracking down kernel problems in UML. It is required + if you intend to do any kernel development. + + If you're truly short on disk space or don't expect to report any + bugs back to the UML developers, say N, otherwise say Y. + +Enable gcov support +CONFIG_GCOV + This option allows developers to retrieve coverage data from a UML + session. + + See for more + details. + + If you're involved in UML kernel development and want to use gcov, + say Y. If you're unsure, say N. + +Enable gprof support +CONFIG_GPROF + This allows profiling of a User-Mode Linux kernel with the gprof + utility. + + See for more + details. + + If you're involved in UML kernel development and want to use gprof, + say Y. If you're unsure, say N. + +Host filesystem +CONFIG_HOSTFS + While the User-Mode Linux port uses its own root file system for + booting and normal file access, this module lets the UML user + access files stored on the host. It does not require any + network connection between the Host and UML. An example use of + this might be: + + mount none /tmp/fromhost -t hostfs -o /tmp/umlshare + + where /tmp/fromhost is an empty directory inside UML and + /tmp/umlshare is a directory on the host with files the UML user + wishes to access. + + For more information, see + . + + If you'd like to be able to work with files stored on the host, + say Y or M here; otherwise say N. + +Example IO Memory driver +CONFIG_MMAPPER + The User-Mode Linux port can provide support for IO Memory + emulation with this option. This allows a host file to be + specified as an I/O region on the kernel command line. That file + will be mapped into UML's kernel address space where a driver can + locate it and do whatever it wants with the memory, including + providing an interface to it for UML processes to use. + + For more information, see + . + + If you'd like to be able to provide a simulated IO port space for + User-Mode Linux processes, say Y. If unsure, say N. + +Virtual Serial Line +CONFIG_SSL + The User-Mode Linux environment allows you to create virtual serial + lines on the UML that are usually made to show up on the host as + ttys or ptys. + + See for more + information and command line examples of how to use this facility. + + Unless you have a specific reason for disabling this, say Y. + +Virtual network device +CONFIG_UML_NET + While the User-Mode port cannot directly talk to any physical + hardware devices, this choice and the following transport options + provide one or more virtual network devices through which the UML + kernels can talk to each other, the host, and with the host's help, + machines on the outside world. + + For more information, including explations of the networking and + sample configurations, see + . + + If you'd like to be able to enable networking in the User-Mode + linux environment, say Y; otherwise say N. Note that you must + enable at least one of the following transport options to actually + make use of UML networking. + +Daemon transport +CONFIG_UML_NET_DAEMON + This User-Mode Linux network transport allows one or more running + UMLs on a single host to communicate with each other, but not to + the host. + + To use this form of networking, you'll need to run the UML + networking daemon on the host. + + For more information, see + That site + has examples of the UML command line to use to enable Daemon + networking. + + If you'd like to set up a network with other UMLs on a single host, + say Y. If you need a network between UMLs on multiple physical + hosts, choose the Multicast Transport. To set up a network with + the host and/or other IP machines, say Y to the Ethertap or Slip + transports. You'll need at least one of them, but may choose + more than one without conflict. If you don't need UML networking, + say N. + +Ethertap transport +CONFIG_UML_NET_ETHERTAP + The Ethertap User-Mode Linux network transport allows a single + running UML to exchange packets with its host over one of the + host's Ethertap devices, such as /dev/tap0. Additional running + UMLs can use additional Ethertap devices, one per running UML. + While the UML believes its on a (multi-device, broadcast) virtual + Ethernet network, it's in fact communicating over a point-to-point + link with the host. + + To use this, your host kernel must have support for Ethertap + devices. Also, if your host kernel is 2.4.x, it must have + CONFIG_NETLINK_DEV configured as Y or M. + + For more information, see + That site + has examples of the UML command line to use to enable Ethertap + networking. + + If you'd like to set up an IP network with the host and/or the + outside world, say Y to this, the Daemon Transport and/or the + Slip Transport. You'll need at least one of them, but may choose + more than one without conflict. If you don't need UML networking, + say N. + +TUN/TAP transport +CONFIG_UML_NET_TUNTAP + The UML TUN/TAP network transport allows a UML instance to exchange + packets with the host over a TUN/TAP device. This option will only + work with a 2.4 host, unless you've applied the TUN/TAP patch to + your 2.2 host kernel. + + To use this transport, your host kernel must have support for TUN/TAP + devices, either built-in or as a module. + +Multicast transport +CONFIG_UML_NET_MCAST + This Multicast User-Mode Linux network transport allows multiple + UMLs (even ones running on different host machines!) to talk to + each other over a virtual ethernet network. However, it requires + at least one UML with one of the other transports to act as a + bridge if any of them need to be able to talk to their hosts or any + other IP machines. + + To use this, your host kernel(s) must support IP Multicasting. + + For more information, see + That site + has examples of the UML command line to use to enable Multicast + networking, and notes about the security of this approach. + + If you need UMLs on multiple physical hosts to communicate as if + they shared an Ethernet network, say Y. If you need to communicate + with other IP machines, make sure you select one of the other + transports (possibly in addition to Multicast; they're not + exclusive). If you don't need to network UMLs say N to each of + the transports. + +SLIP transport +CONFIG_UML_NET_SLIP + The Slip User-Mode Linux network transport allows a running UML to + network with its host over a point-to-point link. Unlike Ethertap, + which can carry any Ethernet frame (and hence even non-IP packets), + the Slip transport can only carry IP packets. + + To use this, your host must support Slip devices. + + For more information, see + . That site + has examples of the UML command line to use to enable Slip + networking, and details of a few quirks with it. + + The Ethertap Transport is preferred over Slip because of its + limitation. If you prefer Slip, however, say Y here. Otherwise + choose the Multicast transport (to network multiple UMLs on + multiple hosts), Ethertap (to network with the host and the + outside world), and/or the Daemon transport (to network multiple + UMLs on a single host). You may choose more than one without + conflict. If you don't need UML networking, say N. Microtek USB scanner support CONFIG_USB_MICROTEK Say Y here if you want support for the Microtek X6USB and possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L. - Support for anything but the X6 is experimetal. + Support for anything but the X6 is experimental. Please report failures and successes. The scanner will appear as a scsi generic device to the rest of the system. Scsi support is required for this driver to compile @@ -12040,14 +13542,14 @@ CONFIG_USB_BLUETOOTH Say Y here if you want to connect a USB Bluetooth device to your computer's USB port. You will need the Bluetooth stack (available - at http://developer.axis.com/software/index.shtml) to fully use + at to fully use the device. 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 bluetooth.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. - + The module will be called bluetooth.o. If you want to compile it as + a module, say M here and read . + Minix fs support CONFIG_MINIX_FS Minix is a simple operating system used in many classes about OS's. @@ -12056,58 +13558,75 @@ but has been superseded by the second extended file system ext2fs. You don't want to use the minix file system 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. + 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 file system of your root partition - (the one containing the directory /) cannot be compiled as a module. + say M here and read . The module + will be called minix.o. Note that the file system of your root + partition (the one containing the directory /) cannot be compiled as + a module. Reiserfs support CONFIG_REISERFS_FS - Stores not just filenames but the files themselves in a balanced tree. Uses journaling. - Balanced trees are more efficient than traditional - filesystem architectural foundations. + Balanced trees are more efficient than traditional file system + architectural foundations. - In general, ReiserFS is as fast as ext2, but is very efficient - with large directories and small files. Additional patches are - needed for NFS and quotas, please see www.reiserfs.org for - links. + In general, ReiserFS is as fast as ext2, but is very efficient with + large directories and small files. Additional patches are needed + for NFS and quotas, please see for links. It is more easily extended to have features currently found in - database and keyword search systems than block allocation based - filesystems are. The next version will be so extended, and will - support plugins consistent with our motto ``It takes more than a - license to make source code open.'' + database and keyword search systems than block allocation based file + systems are. The next version will be so extended, and will support + plugins consistent with our motto ``It takes more than a license to + make source code open.'' - Read www.reiserfs.org to learn more about reiserfs. + Read to learn more about reiserfs. Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com. If you like it, you can pay us to add new features to it that you need, buy a support contract, or pay us to port it to another OS. -Enable Reiserfs consistency checks +Enable extra Reiserfs consistency checks CONFIG_REISERFS_CHECK - If you set this to yes, then ReiserFS will perform every check it - can possibly imagine of its internal consistency throughout its + If you set this to Y, then ReiserFS will perform every check it can + possibly imagine of its internal consistency throughout its operation. It will also go substantially slower. More than once we have forgotten that this was on, and then gone despondent over the latest benchmarks.:-) Use of this option allows our team to go all out in checking for consistency when debugging without fear of its effect on end users. If you are on the verge of sending in a bug - report, say yes and you might get a useful error message. Almost - everyone should say no. + report, say Y and you might get a useful error message. Almost + everyone should say N. + +Publish some reiserfs-specific info under /proc/fs/reiserfs +CONFIG_REISERFS_PROC_INFO + Create under /proc/fs/reiserfs hierarchy of files, displaying + various ReiserFS statistics and internal data on the expense of + making your kernel or module slightly larger (+8 KB). This also + increases amount of kernel memory required for each mount. Almost + everyone but ReiserFS developers and people fine-tuning reiserfs or + tracing problems should say N. + +Publish some reiserfs-specific info under /proc/fs/reiserfs +CONFIG_REISERFS_PROC_INFO + Create under /proc/fs/reiserfs hierarchy of files, displaying + various ReiserFS statistics and internal data on the expense of + making your kernel or module slightly larger (+8K). This also increases + amount of kernel memory required for each mount. Almost everyone + but ReiserFS developers and people fine-tuning reiserfs or tracing + problems should say NO. Second extended fs support CONFIG_EXT2_FS This is the de facto standard Linux file system (method to organize - files on a storage device) for hard disks. + 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 file system. The @@ -12125,70 +13644,151 @@ by about 44 KB. The Ext2fs-Undeletion mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto , gives information about + , gives information about how to retrieve deleted files on ext2fs file systems. To change the behavior of ext2 file systems, you can use the tune2fs utility ("man tune2fs"). To modify attributes of files and directories on ext2 file systems, 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 + ) and from within Windows NT using the ext2nt command line tool package from - ftp://metalab.unc.edu/pub/Linux/utils/dos . Explore2fs is a + . 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 file system as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read . The + module will be called ext2.o. Be aware however that the file system + 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. + +Ext3 journaling file system support (EXPERIMENTAL) +CONFIG_EXT3_FS + This is the journaling version of the Second extended file system + (often called ext3), the de facto standard Linux file system + (method to organize files on a storage device) for hard disks. + + The journaling code included in this driver means you do not have + to run e2fsck (file system checker) on your file systems after a + crash. The journal keeps track of any changes that were being made + at the time the system crashed, and can ensure that your file system + is consistent without the need for a lengthy check. + + Other than adding the journal to the file system, the on-disk format + of ext3 is identical to ext2. It is possible to freely switch + between using the ext3 driver and the ext2 driver, as long as the + file system has been cleanly unmounted, or e2fsck is run on the file + system. + + To add a journal on an existing ext2 file system or change the + behavior of ext3 file systems, you can use the tune2fs utility ("man + tune2fs"). To modify attributes of files and directories on ext3 + file systems, use chattr ("man chattr"). You need to be using + e2fsprogs version 1.20 or later in order to create ext3 journals + (available at ). If you want to compile this file system 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 file system 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. + want), say M here and read . The + module will be called ext3.o. Be aware however that the file system + of your root partition (the one containing the directory /) cannot + be compiled as a module, and so this may be dangerous. + +Journal Block Device support (JBD for ext3) (EXPERIMENTAL) +CONFIG_JBD + This is a generic journaling layer for block devices. It is + currently used by the ext3 file system, but it could also be used to + add journal support to other file systems or block devices such as + RAID or LVM. + + If you are using the ext3 file system, you need to say Y here. If + you are not using ext3 then you will probably want to say N. + + If you want to compile this device as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called jbd.o. If you are compiling ext3 into the kernel, + you cannot compile this code as a module. + +JBD (ext3) debugging support +CONFIG_JBD_DEBUG + If you are using the ext3 journaled file system (or potentially any + other file system/device using JBD), this option allows you to + enable debugging output while the system is running, in order to + help track down any problems you are having. By default the + debugging output will be turned off. + + If you select Y here, then you will be able to turn on debugging + with "echo N > /proc/sys/fs/jbd-debug", where N is a number between + 1 and 5, the higher the number, the more debugging output is + generated. To turn debugging off again, do + "echo 0 > /proc/sys/fs/jbd-debug". + +Buffer Head tracing (DEBUG) +CONFIG_BUFFER_DEBUG + If you are a kernel developer working with file systems or in the + block device layer, this buffer head tracing may help you to track + down bugs in your code. This enables some debugging macros + (BUFFER_TRACE, etc.) which allow you to track the state of a buffer + through various layers of code. The debugging code is used + primarily by ext3 and JBD code. -BFS file system support (EXPERIMENTAL) + Because this option adds considerably to the size of each buffer, + most people will want to say N here. + +BFS file system support CONFIG_BFS_FS Boot File System (BFS) is a file system used under SCO UnixWare to allow the bootloader access to the kernel image and other important - files during the boot process. It is usually mounted under /stand + files during the boot process. It is usually mounted under /stand and corresponds to the slice marked as "STAND" in the UnixWare - partition. You should say Y if you want to read or write - the files on your /stand slice from within Linux. You then also - need to say Y to "UnixWare slices support", below. More information - about the BFS file system is contained in the file - Documentation/filesystems/bfs.txt. + partition. You should say Y if you want to read or write the files + on your /stand slice from within Linux. You then also need to say Y + to "UnixWare slices support", below. More information about the BFS + file system is contained in the file + . If you don't know what this is about, 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 file system of your root partition (the - one containing the directory /) cannot be compiled as a module. + say M here and read . The module + will be called bfs.o. Note that the file system of your root + partition (the one containing the directory /) cannot be compiled as + a module. Compressed ROM file system support CONFIG_CRAMFS Saying Y here includes support for CramFs (Compressed ROM File - System). Cramfs is designed to be a simple, small, and compressed - file system for ROM based embedded systems. CramFs is read-only, + System). CramFs is designed to be a simple, small, and compressed + file system for ROM based embedded systems. CramFs is read-only, limited to 256MB file systems (with 16MB files), and doesn't support 16/32 bits uid/gid, hard links and timestamps. - - See Documentation/filesystems/cramfs.txt and fs/cramfs/README - for further information. + + See and + for further 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 cramfs.o. Note that the root file system (the one containing - the directory /) cannot be compiled as a module. + say M here and read . The module + will be called cramfs.o. Note that the root file system (the one + containing the directory /) cannot be compiled as a module. If unsure, say N. - + +CMS file system support +CONFIG_CMS_FS + Read only support for CMS minidisk file systems found on IBM + mainframe systems. Only the basic format is supported so far. If + you don't know what CMS is you probably don't want to know any more. + Virtual memory file system support CONFIG_TMPFS Tmpfs is a file system which keeps all files in virtual memory. @@ -12200,8 +13800,8 @@ Everything is "virtual" in the sense that no files will be created on your hard drive; if you reboot, everything in tmpfs will be lost. - - You should mount the filesystem somewhere to be able to use + + You should mount the file system somewhere to be able to use POSIX shared memory. Adding the following line to /etc/fstab should take care of things: @@ -12211,10 +13811,10 @@ if necessary (/dev/shm is automagically created if you use devfs). You can set limits for the number of blocks and inodes used by the - filesystem with the mount options "size", "nr_blocks" and + file system with the mount options "size", "nr_blocks" and "nr_inodes". These parameters accept a suffix k, m or g for kilo, mega and giga and can be changed on remount. - + The initial permissions of the root directory can be set with the mount option "mode". @@ -12223,40 +13823,40 @@ Ramfs is a file system which keeps all files in RAM. It allows read and write access. - It is more of an programming example than a useable filesystem. If + It is more of an programming example than a useable file system. If you need a file system which lives in RAM with limit checking use tmpfs. 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 ramfs.o. + say M here and read . The module + will be called ramfs.o. -ISO 9660 CDROM file system support +ISO 9660 CD-ROM file system support CONFIG_ISO9660_FS - This is the standard file system used on CDROMs. It was previously + This is the standard file system used on CD-ROMs. It was previously known as "High Sierra File System" and is called "hsfs" on other - Unix systems. The so-called Rock-Ridge extensions which allow for + 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 + driver. If you have a CD-ROM 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://www.linuxdoc.org/docs.html#howto ), thereby enlarging - your kernel by about 27 KB; otherwise say N. + and the CD-ROM-HOWTO, + available from ), 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. + say M here and read . The module + will be called isofs.o. -Microsoft Joliet CDROM extensions +Microsoft Joliet CD-ROM extensions CONFIG_JOLIET - Joliet is a Microsoft extension for the ISO 9660 CDROM file system + Joliet is a Microsoft extension for the ISO 9660 CD-ROM file system 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. + for more information). Say Y here if you + want to be able to read Joliet CD-ROMs under Linux. Transparent decompression extension CONFIG_ZISOFS @@ -12267,21 +13867,21 @@ necessary to create such a filesystem. Say Y here if you want to be able to read such compressed CD-ROMs. -UDF File System support (read only) +UDF file system support (read-only) CONFIG_UDF_FS - This is the new file system used on some CDROMs and DVDs. Say Y if + This is the new file system used on some CD-ROMs and DVDs. 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. This UDF file system support is read-only. If you want to write to UDF file systems on some media, you need to say Y to "UDF read-write support" below in addition. Please read - Documentation/filesystems/udf.txt. + . This file system 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. @@ -12315,23 +13915,23 @@ Linux box, say Y here, mount the floppy under Linux with an MSDOS file system and use GNU tar's M option. GNU tar is a program available for Unix and DOS ("man tar" or "info tar"). - + It is now also becoming possible to read and write compressed FAT - file systems; read Documentation/filesystems/fat_cvf.txt for + file systems; read 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 file systems into - the kernel -- they will have to be modules as well. The file system - 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 file system. + want), say M here and read . 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 file + systems into the kernel -- they will have to be modules as well. + The file system 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 file system. MSDOS fs support CONFIG_MSDOS_FS @@ -12339,8 +13939,8 @@ 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://www.linuxdoc.org/docs.html#howto , or try dmsdosfs in - ftp://metalab.unc.edu/pub/Linux/system/filesystems/dosfs . If you + , or try dmsdosfs in + . 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 @@ -12359,32 +13959,33 @@ answer Y. This will only work if you said Y to "DOS 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. + whenever you want), say M here and read + . The module will be called msdos.o. VFAT (Windows-95) fs support CONFIG_VFAT_FS This option provides support for normal Windows file systems with - long filenames. That includes non-compressed FAT-based file systems + long filenames. That includes non-compressed FAT-based file systems used by Windows 95, Windows 98, Windows NT 4.0, and the Unix programs from the mtools package. You cannot use the VFAT file system 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). + "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 "DOS FAT fs support" above. Please read - the file Documentation/filesystems/vfat.txt for details. If unsure, - say Y. + works if you said Y to the "DOS FAT fs support" above. Please read + the file 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. + say M here and read . The module + will be called vfat.o. -UMSDOS: Unix-like file system on top of standard MSDOS fs +Unix-like file system on top of standard MSDOS fs 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 @@ -12392,34 +13993,25 @@ 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 + 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 soft-links 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. + MSDOS floppies. You will need a program called umssync in order to + make use of UMSDOS; read + . To get utilities for initializing/checking UMSDOS file system, or latest patches and/or information, visit the UMSDOS home page at - http://www.voyager.hr/~mnalis/umsdos/ . + . This option enlarges your kernel by about 28 KB and it only works if you said Y to both "DOS 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 file system of your root partition - (the one containing the directory /) cannot be a module, so saying M - could be dangerous. If unsure, say N. - -PReP residual data support -CONFIG_PREP_RESIDUAL - Some PReP systems have residual data passed to the kernel by the - firmware. This allows detection of memory size, devices present and - other useful pieces of information. Sometimes this information is not - present or incorrect. - - Unless you expect to boot on a PReP system, there is not need to select - yes. + 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 . The + module will be called umsdos.o. Note that the file system of your + root partition (the one containing the directory /) cannot be a + module, so saying M could be dangerous. If unsure, say N. /proc file system support CONFIG_PROC_FS @@ -12427,7 +14019,7 @@ 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. + 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 @@ -12443,13 +14035,23 @@ /proc" or the equivalent line in /etc/fstab does the job. The /proc file system is explained in the file - Documentation/filesystems/proc.txt and on the proc(5) manpage ("man - 5 proc"). + 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. -/dev file system support (EXPERIMENTAL) +Support for PReP Residual Data +CONFIG_PREP_RESIDUAL + Some PReP systems have residual data passed to the kernel by the + firmware. This allows detection of memory size, devices present and + other useful pieces of information. Sometimes this information is + not present or incorrect. + + Unless you expect to boot on a PReP system, there is not need to + select Y. + +/dev file system support CONFIG_DEVFS_FS This is support for devfs, a virtual file system (like /proc) which provides the file system interface to device drivers, normally found @@ -12460,12 +14062,12 @@ /dev directory using the mknod command (or MAKEDEV script) anymore. This is work in progress. If you want to use this, you *must* read - the material in Documentation/filesystems/devfs/, especially the - file README there. + the material in , especially + the file README there. If unsure, say N. -Enable automatic mounting at boot +Automatically mount devfs at boot time CONFIG_DEVFS_MOUNT This option appears if you have CONFIG_DEVFS_FS enabled. Setting this to 'Y' will make the kernel automatically mount devfs onto /dev @@ -12478,8 +14080,9 @@ CONFIG_DEVFS_DEBUG If you say Y here, then the /dev file system code will generate debugging messages. See the file - Documentation/filesystems/devfs/boot-options for more details. - + for more + details. + If unsure, say N. NFS file system support @@ -12493,35 +14096,35 @@ programs nfsd and mountd (but does not need to have NFS file system support enabled in its kernel). NFS is explained in the Network Administrator's Guide, available from - http://www.linuxdoc.org/docs.html#guide , on its man page: "man + , 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 file system; see "Coda file system 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 option would enlarge your kernel by about 27 KB. This file system 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. + say M here and read . If you are configuring a diskless machine which will mount its root - file system over NFS at boot time, say Y here and to "IP: kernel - level autoconfiguration" above and to "Root file system on NFS" + file system over NFS at boot time, say Y here and to "Kernel + level IP 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. -Provide NFSv3 client support (EXPERIMENTAL) +Provide NFSv3 client support CONFIG_NFS_V3 Say Y here if you want your NFS client to be able to speak the newer - version 3 of the NFS protocol. - + version 3 of the NFS protocol. + If unsure, say N. Root file system on NFS @@ -12529,12 +14132,12 @@ If you want your Linux box to mount its whole root file system (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 + say Y. Read for details. It is + likely that in this case, you also want to say Y to "Kernel level IP autoconfiguration" so that your box can discover its network address at boot time. - - Most people say N here. + + Most people say N here. NFS server support CONFIG_NFSD @@ -12547,20 +14150,21 @@ faster. In either case, you will need support software; the respective - locations are given in the file Documentation/Changes in the NFS - section. + locations are given in the file in the + NFS section. If you say Y here, you will get support for version 2 of the NFS protocol (NFSv2). If you also want NFSv3, say Y to the next question as well. Please read the NFS-HOWTO, available from - http://www.linuxdoc.org/docs.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. + The module is called nfsd.o. If you want to compile it as a module, + say M here and read . If unsure, + say N. Provide NFSv3 server support CONFIG_NFSD_V3 @@ -12572,7 +14176,8 @@ If you are a developer and want to work on fixing problems with NFS server over TCP support, say Y here. If unsure, say N. - Some problems can be found by looking for FIXME in net/sunrpc/svcsock.c + Some problems can be found by looking for FIXME in + . OS/2 HPFS file system support CONFIG_HPFS_FS @@ -12582,29 +14187,13 @@ write files to an OS/2 HPFS partition on 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 file system 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. - -FreeVxFS file system support (VERITAS VxFS(TM) compatible) -CONFIG_VXFS_FS - FreeVxFS is a filesystem driver that support the VERITAS VxFS(TM) - filesystem format. VERITAS VxFS(TM) is the standard filesystem - of SCO UnixWare (and possibly others) and optionally available - for Sunsoft Solaris, HP-UX and many other operating systems. - Currently only readonly access is supported. - - NOTE: the filesystem type as used by mount(1), mount(2) and fstab(5) - is 'vxfs' as it describes the filesystem format, not the - actual driver. - - This file system 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 freevxfs.o. If you want to compile it as a module, - say M here and read Documentation/modules.txt. If unsure, say N. + The module is called hpfs.o. If you want to compile it as a module, + say M here and read . If unsure, + say N. NTFS file system support (read-only) CONFIG_NTFS_FS @@ -12637,94 +14226,98 @@ If unsure, say N. -System V, Version 7, Xenix and Coherent filesystem support +System V/Xenix/V7/Coherent file system support CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel machines, and Version 7 was used on the DEC PDP-11. Saying Y here would allow you to read from their floppies and hard disk - partitions. If you also want to write to these media, say Y to - "SYSV file system write support" below. + 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 linux-abi which is a - a set of kernel modules that lets you run SCO, Xenix, Wyse, UnixWare, - Dell Unix and System V programs under Linux. It's available via FTP - (user: ftp) from ftp://ftp.openlinux.org/pub/people/hch/linux-abi). + a set of kernel modules that lets you run SCO, Xenix, Wyse, + UnixWare, Dell Unix and System V programs under Linux. It is + available via FTP (user: ftp) from + ). NOTE: that will work only for binaries from Intel-based systems; PDP ones will have to wait until somebody ports Linux to -11 ;-) If you only intend to mount files from some other Unix over the network using NFS, you don't need the System V file system support - (but you need NFS file system support obviously). + (but you need NFS file system 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 + 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 file system in Documentation/filesystems/sysv-fs.txt. + the System V file system in + . 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. + say M here and read . The module + will be called sysv.o. If you haven't heard about all of this before, it's safe to say N. Amiga FFS file system support CONFIG_AFFS_FS The Fast File System (FFS) is the common file system used on hard - disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20). Say Y + 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 + 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. + PCs and workstations. Read + and . With this driver you can also mount disk files used by Bernd - Schmidt's Un*X Amiga Emulator (http://www.freiburg.linux.de/~uae/ ). + Schmidt's Un*X Amiga Emulator + (). If you want to do this, you will also need to say Y or M to "Loop device support", above. This file system 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. + The module is called affs.o. If you want to compile it as a module, + say M here and read . If unsure, + say N. -Apple Macintosh file system support (EXPERIMENTAL) +Apple Macintosh file system support 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. + Please read to learn about the available mount + options. This file system 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 + 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 file system support CONFIG_ROMFS_FS This is a very small read-only file system 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. + other read-only media as well. Read + for details. This file system 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 + 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. Note that the file system of your root - partition (the one containing the directory /) cannot be a module. + . Note that the file system of your + root partition (the one containing the directory /) cannot be a + module. If you don't know whether you need it, then you don't need it: answer N. -QNX4 file system support (read only) (EXPERIMENTAL) +QNX4 file system support (read only) CONFIG_QNX4FS_FS This is the file system used by the operating system QNX 4. Say Y if you intend to mount QNX hard disks or floppies. Unless you say Y to @@ -12735,7 +14328,7 @@ 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 you don't know whether you need it, then you don't need it: answer N. @@ -12752,8 +14345,8 @@ automounter (amd), which is a pure user space daemon. To use the automounter you need the user-space tools from the autofs - package; you can find the location in Documentation/Changes. You - also want to answer Y to "NFS file system support", below. + package; you can find the location in . + You also want to answer Y to "NFS file system support", below. If you want to use the newer version of the automounter with more features, say N here and say Y to "Kernel automounter v4 support", @@ -12761,13 +14354,13 @@ 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. + say M here and read . 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. -Kernel automounter v4 support +Kernel automounter version 4 support (also supports v3) CONFIG_AUTOFS4_FS The automounter is a tool to automatically mount remote file systems on demand. This implementation is partially kernel-based to reduce @@ -12775,46 +14368,70 @@ 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/testing-v4 ; you also + ; you also want to answer Y to "NFS file system 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 autofs4.o. You will need to add "alias autofs autofs4" to - your modules configuration file. + say M here and read . The module + will be called autofs4.o. You will need to add "alias autofs + autofs4" to your modules configuration file. If you are not a part of a fairly large, distributed network or don't have a laptop which needs to dynamically reconfigure to the local network, you probably do not need an automounter, and can say N here. -EFS file system support (read-only) (EXPERIMENTAL) +EFS file system support (read-only) CONFIG_EFS_FS - EFS is an older file system used for non-ISO9660 CDROMs and hard + EFS is an older file system used for non-ISO9660 CD-ROMs and hard disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer uses the XFS file system 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/ . + about EFS see its home page at . If you want to compile the EFS file system 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. + whenever you want), say M here and read + . The module will be called efs.o. -Support for the Journalling Flash Filesystem +Journalling Flash File System (JFFS) support CONFIG_JFFS_FS JFFS is the Journaling Flash File System developed by Axis Communications in Sweden, aimed at providing a crash/powerdown-safe - filesystem for disk-less embedded devices. Further information is - available at (http://developer.axis.com/software/jffs/). + file system for disk-less embedded devices. Further information is + available at (). -JFFS debugging verbosity +JFFS debugging verbosity (0 = quiet, 3 = noisy) CONFIG_JFFS_FS_VERBOSE Determines the verbosity level of the JFFS debugging messages. +Journalling Flash File System v2 (JFFS2) support +CONFIG_JFFS2_FS + JFFS2 is the second generation of the Journalling Flash File System + for use on diskless embedded devices. It provides improved wear + levelling, compression and support for hard links. You cannot use + this on normal block devices, only on 'MTD' devices. + + Further information should be made available soon at + . + +JFFS2 debugging verbosity (0 = quiet, 2 = noisy) +CONFIG_JFFS2_FS_DEBUG + This controls the amount of debugging messages produced by the JFFS2 + code. Set it to zero for use in production systems. For evaluation, + testing and debugging, it's advisable to set it to one. This will + enable a few assertions and will print debugging messages at the + KERN_DEBUG loglevel, where they won't normally be visible. Level 2 + is unlikely to be useful - it enables extra debugging in certain + areas which at one point needed debugging, but when the bugs were + located and fixed, the detailed messages were relegated to level 2. + + If reporting bugs, please try to have available a full dump of the + messages at debug level 1 while the misbehaviour was occurring. + UFS file system support (read-only) CONFIG_UFS_FS BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD, @@ -12823,11 +14440,11 @@ this file system 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 file system write support", below. Please read the - file Documentation/filesystems/ufs.txt for more information. + file 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 file system support (but - you need NFS file system support obviously). + you need NFS file system support obviously). Note that this option is generally not needed for floppies, since a good portable way to transport files and directories between unixes @@ -12836,12 +14453,12 @@ 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. + recode ("info recode") for this purpose. If you want to compile the UFS file system 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. + whenever you want), say M here and read + . The module will be called ufs.o. If you haven't heard about all of this before, it's safe to say N. @@ -12857,11 +14474,38 @@ 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. + kernel: saying N will just cause the configurator to skip all + the questions about foreign partitioning schemes. If unsure, say N. +Acorn partition support +CONFIG_ACORN_PARTITION + Support hard disks partitioned under Acorn operating systems. + +Native filecore partition support +CONFIG_ACORN_PARTITION_ADFS + The Acorn Disc Filing System is the standard file system 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 support disk partitions created under ADFS. + +PowerTec partition support +CONFIG_ACORN_PARTITION_POWERTEC + Support reading partition tables created on Acorn machines using + the PowerTec SCSI drive. + +RISCiX partition support +CONFIG_ACORN_PARTITION_RISCIX + Once upon a time, there was a native Unix port for the Acorn series + of machines called RISCiX. If you say 'Y' here, Linux will be able + to read disks partitioned under RISCiX. + +ICS partition support +CONFIG_ACORN_PARTITION_ICS + Say Y here if you would like to use hard disks under Linux which + were partitioned using the ICS interface on Acorn machines. + Alpha OSF partition support CONFIG_OSF_PARTITION Say Y here if you would like to use hard disks under Linux which @@ -12884,10 +14528,11 @@ mirrored, striped or RAID volumes, all without the need for rebooting. - Normal partitions are now called Basic Disks under Windows 2000 and XP. + Normal partitions are now called Basic Disks under Windows 2000 and + XP. Technical documentation to accompany this driver is available from: - + . If unsure, say N. @@ -12904,6 +14549,16 @@ Say Y here if you would like to use hard disks under Linux which were partitioned on an x86 PC (not necessarily by DOS). +Amiga partition table support +CONFIG_AMIGA_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned under AmigaOS. + +Atari partition table support +CONFIG_ATARI_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned under the Atari OS. + BSD disklabel (FreeBSD partition tables) support CONFIG_BSD_DISKLABEL FreeBSD uses its own hard disk partition scheme on your PC. It @@ -12921,7 +14576,7 @@ Say Y here if you want to mount and use Minix 2.0.0/2.0.2 subpartitions. -Sun partition tables support +Sun partition table 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 @@ -12947,13 +14602,19 @@ Say Y here if you would like to be able to read the hard disk partition table format used by SGI machines. -Ultrix partition support +Ultrix partition table support CONFIG_ULTRIX_PARTITION Say Y here if you would like to be able to read the hard disk partition table format used by DEC (now Compaq) Ultrix machines. Otherwise, say N. -ADFS file system support (EXPERIMENTAL) +IBM disk label and partition support +CONFIG_IBM_PARTITION + Say Y here if you would like to be able to read the hard disk + partition table format used by IBM DASD disks operating under CMS. + Otherwise, say N. + +ADFS file system support CONFIG_ADFS_FS The Acorn Disc Filing System is the standard file system of the RiscOS operating system which runs on Acorn's ARM-based Risc PC @@ -12964,12 +14625,12 @@ 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. + 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. @@ -12989,17 +14650,55 @@ 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. + 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. Please read Documentation/Changes for more information about - the Unix98 pty devices. + API. Please read for more information + about the Unix98 pty devices. Note that the experimental "/dev file system support" (CONFIG_DEVFS_FS) is a more general facility. -UnixWare slices support (EXPERIMENTAL) +# This is for Linus's tree +FreeVxFS file system support (VERITAS VxFS(TM) compatible) +CONFIG_VXFS_FS + FreeVxFS is a file system driver that support the VERITAS VxFS(TM) + file system format. VERITAS VxFS(TM) is the standard file system + of SCO UnixWare (and possibly others) and optionally available + for Sunsoft Solaris, HP-UX and many other operating systems. + Currently only readonly access is supported. + + NOTE: the file system type as used by mount(1), mount(2) and + fstab(5) is 'vxfs' as it describes the file system format, not + the actual driver. + + This file system 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 freevxfs.o. If you want to compile it as a + module, say M here and read . If + unsure, say N. + +# This is for Alan's tree. Note the name difference. +FreeVxFS file system support (VERITAS VxFS(TM) compatible) +CONFIG_FREEVXFS_FS + FreeVxFS is a file system driver that support the VERITAS VxFS(TM) + file system format. VERITAS VxFS(TM) is the standard file system + of SCO UnixWare (and possibly others) and optionally available + for Sunsoft Solaris, HP-UX and many other operating systems. + Currently only readonly access is supported. + + NOTE: the file system type as used by mount(1), mount(2) and + fstab(5) is 'vxfs' as it describes the filesystem format, not + the actual driver. + + This file system 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 freevxfs.o. If you want to compile it as a + module, say M here and read . If + unsure, say N. + +UnixWare slices support CONFIG_UNIXWARE_DISKLABEL Like some systems, UnixWare uses its own slice table inside a partition (VTOC - Virtual Table of Contents). Its format is @@ -13013,7 +14712,7 @@ 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"). + preferably "info tar"). If you don't know what all this is about, say N. @@ -13021,29 +14720,29 @@ 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 + files and printers over local networks. Saying Y here allows you to mount their file systems (often called "shares" in this context) and - access them just like any other Unix directory. Currently, this + 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://www.linuxdoc.org/docs.html#howto . + transport protocol, and not NetBEUI. For details, read + and the SMB-HOWTO, + available from . 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. + ) 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 . + Macs is on the WWW at . 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. + want), say M here and read . The + module will be called smbfs.o. Most people say N, however. -use nls by default +Use a default NLS CONFIG_SMB_NLS_DEFAULT Enabling this will make smbfs use nls translations by default. You need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls @@ -13055,7 +14754,7 @@ smbmount from samba 2.2.0 or later supports this. -nls support setting +Default Remote NLS Option CONFIG_SMB_NLS_REMOTE This setting allows you to specify a default value for which codepage the server uses. If this field is left blank no @@ -13072,72 +14771,85 @@ Coda is an advanced network file system, similar to NFS in that it enables you to mount file systems 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. + 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. they need no - kernel support. Please read Documentation/filesystems/coda.txt and - check out the Coda home page http://www.coda.cs.cmu.edu . + *client*. You will need user level code as well, both for the + client and server. Servers are currently user level, i.e. they need + no kernel support. Please read + and check out the Coda + home page . 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. + whenever you want), say M here and read + . The module will be called coda.o. + +InterMezzo file system support (experimental, replicating fs) +CONFIG_INTERMEZZO_FS + InterMezzo is a networked file system with disconnected operation + and kernel level write back caching. It is most often used for + replicating potentially large trees or keeping laptop/desktop copies + in sync. + + If you say Y or M your kernel or module will provide InterMezzo + support. You will also need a file server daemon, which you can get + from . NCP file system 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://www.linuxdoc.org/docs.html#howto . + 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 + in the kernel source and + the IPX-HOWTO from . 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 . + Macs is on the WWW at . 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. + say M here and read . 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 + 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 + 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. + 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 +Use NFS namespace if 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 + 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 +Use LONG (OS/2) namespace if 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 + 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 @@ -13146,7 +14858,7 @@ the OS2/LONG namespace and created under DOS or on a volume using DOS namespace will be converted to lowercase characters. 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. @@ -13158,25 +14870,7 @@ 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 authentication support -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 +Use 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 @@ -13194,21 +14888,24 @@ To use the new attributes, it is recommended to use the flags '-f 600 -d 755' on the ncpmount command line. -nls default codepage +Default NLS Option CONFIG_NLS_DEFAULT - The default NLS used when mounting file system. Currently, the valid - values are: + The default NLS used when mounting file system. Note, that this is + the NLS used by your console, not the NLS used by a specific file + system (if different) to store data (filenames) on a disk. + Currently, the valid values are: big5, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861, cp862, cp863, cp864, cp865, cp866, cp869, cp874, cp932, cp936, - cp949, cp950, euc-jp, euc-kr, gb2312, iso8859-1, iso8859-2, iso8859-3, - iso8859-4, iso8859-5, iso8859-6, iso8859-7, iso8859-8, iso8859-9, - iso8859-14, iso8859-15, koi8-r, sjis - If you specify a wrong value, it will use the built-in NLS; compatible - with iso8859-1. + cp949, cp950, cp1251, cp1255, euc-jp, euc-kr, gb2312, iso8859-1, + iso8859-2, iso8859-3, iso8859-4, iso8859-5, iso8859-6, iso8859-7, + iso8859-8, iso8859-9, iso8859-13, iso8859-14, iso8859-15, + koi8-r, koi8-ru, koi8-u, sjis, tis-620, utf8. + If you specify a wrong value, it will use the built-in NLS; + compatible with iso8859-1. If unsure, specify it as "iso8859-1". -nls codepage 437 +Codepage 437 (United States, Canada) CONFIG_NLS_CODEPAGE_437 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored @@ -13219,7 +14916,7 @@ 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 +Codepage 737 (Greek) CONFIG_NLS_CODEPAGE_737 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored @@ -13230,7 +14927,7 @@ say Y here if you want to include the DOS codepage that is used for Greek. If unsure, say N. -nls codepage 775 +Codepage 775 (Baltic Rim) CONFIG_NLS_CODEPAGE_775 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored @@ -13239,9 +14936,10 @@ 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. + for the Baltic Rim Languages (Latvian and Lithuanian). If unsure, + say N. -nls codepage 850 +Codepage 850 (Europe) CONFIG_NLS_CODEPAGE_850 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13252,11 +14950,11 @@ 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. + languages that are not part of the US codepage 437. If unsure, say Y. -nls codepage 852 +Codepage 852 (Central/Eastern Europe) CONFIG_NLS_CODEPAGE_852 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13270,7 +14968,7 @@ Finnish, Hungarian, Irish, German, Polish, Romanian, Serbian (Latin transcription), Slovak, Slovenian, and Sorbian. -nls codepage 855 +Codepage 855 (Cyrillic) CONFIG_NLS_CODEPAGE_855 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13280,7 +14978,7 @@ 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 +Codepage 857 (Turkish) CONFIG_NLS_CODEPAGE_857 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13290,7 +14988,7 @@ 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 +Codepage 860 (Portuguese) CONFIG_NLS_CODEPAGE_860 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13300,7 +14998,7 @@ 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 +Codepage 861 (Icelandic) CONFIG_NLS_CODEPAGE_861 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13310,7 +15008,7 @@ 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 +Codepage 862 (Hebrew) CONFIG_NLS_CODEPAGE_862 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13320,7 +15018,7 @@ 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 +Codepage 863 (Canadian French) CONFIG_NLS_CODEPAGE_863 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13331,7 +15029,7 @@ say Y here if you want to include the DOS codepage for Canadian French. -nls codepage 864 +Codepage 864 (Arabic) CONFIG_NLS_CODEPAGE_864 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13341,7 +15039,7 @@ 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 +Codepage 865 (Norwegian, Danish) CONFIG_NLS_CODEPAGE_865 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13352,7 +15050,7 @@ say Y here if you want to include the DOS codepage for the Nordic European countries. -nls codepage 866 +Codepage 866 (Cyrillic/Russian) CONFIG_NLS_CODEPAGE_866 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13363,7 +15061,7 @@ say Y here if you want to include the DOS codepage for Cyrillic/Russian. -nls codepage 869 +Codepage 869 (Greek) CONFIG_NLS_CODEPAGE_869 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13373,7 +15071,7 @@ only, not to the file contents. You can include several codepages; say Y here if you want to include the DOS codepage for Greek. -nls codepage 874 +Thai charset (CP874, TIS-620) CONFIG_NLS_CODEPAGE_874 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13383,7 +15081,18 @@ 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 codepage 932 +Windows CP1251 (Bulgarian, Belarusian) +CONFIG_NLS_CODEPAGE_1251 + The Microsoft FAT file system 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 Russian and + Bulgarian and Belarusian. + +Japanese charsets (Shift-JIS, EUC-JP) CONFIG_NLS_CODEPAGE_932 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13393,9 +15102,9 @@ only, not to the file contents. You can include several codepages; say Y here if you want to include the DOS codepage for Shift-JIS or EUC-JP. To use EUC-JP, you can use 'euc-jp' as mount option or - NLS Default value during kernel configuration , instead of 'cp932' + NLS Default value during kernel configuration, instead of 'cp932'. -nls codepage 936 +Simplified Chinese charset (CP936, GB2312) CONFIG_NLS_CODEPAGE_936 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13406,7 +15115,7 @@ say Y here if you want to include the DOS codepage for Simplified Chinese(GBK). -nls codepage 949 +Korean charset (CP949, EUC-KR) CONFIG_NLS_CODEPAGE_949 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13416,7 +15125,7 @@ only, not to the file contents. You can include several codepages; say Y here if you want to include the DOS codepage for UHC. -nls codepage 950 +Traditional Chinese charset (Big5) CONFIG_NLS_CODEPAGE_950 The Microsoft FAT file system family can deal with filenames in native language character sets. These character sets are stored in @@ -13427,10 +15136,10 @@ say Y here if you want to include the DOS codepage for Traditional Chinese(Big5). -nls iso8859-1 +NLS ISO 8859-1 (Latin 1; Western European Languages) CONFIG_NLS_ISO8859_1 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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, @@ -13438,101 +15147,110 @@ Galician, Irish, Icelandic, Italian, Norwegian, Portuguese, Spanish, and Swedish. It is also the default for the US. If unsure, say Y. -nls iso8859-2 +NLS ISO 8859-2 (Latin 2; Slavic/Central European Languages) CONFIG_NLS_ISO8859_2 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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 +NLS ISO 8859-3 (Latin 3; Esperanto, Galician, Maltese, Turkish) CONFIG_NLS_ISO8859_3 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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 +NLS ISO 8859-4 (Latin 4; old Baltic charset) CONFIG_NLS_ISO8859_4 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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. + Lithuanian. It is an incomplete predecessor of Latin 7. -nls iso8859-5 +NLS ISO 8859-5 (Cyrillic) CONFIG_NLS_ISO8859_5 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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, + character set with which you can type Bulgarian, Belarusian, Macedonian, Russian, Serbian, and Ukrainian. Note that the charset KOI8-R is preferred in Russia. -nls iso8859-6 +NLS ISO 8859-6 (Arabic) CONFIG_NLS_ISO8859_6 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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 +NLS ISO 8859-7 (Modern Greek) CONFIG_NLS_ISO8859_7 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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 +Hebrew charsets (ISO-8859-8, CP1255) CONFIG_NLS_ISO8859_8 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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 +NLS ISO 8859-9 (Latin 5; Turkish) CONFIG_NLS_ISO8859_9 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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 +NLS ISO 8859-10 (Latin 6; Nordic) CONFIG_NLS_ISO8859_10 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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-13 (Latin 7; Baltic) +CONFIG_NLS_ISO8859_13 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 7 character + set, which supports modern Baltic languages including Latvian + and Lithuanian. + 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 file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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 (aka Cymraeg) - (and Manx Gaelic) hat were missing in Latin 1. - http://linux.speech.cymru.org/ has further information. + (and Manx Gaelic) that were missing in Latin 1. + has further information. -nls iso8859-15 +NLS ISO 8859-15 (Latin 9; Western European languages with Euro) CONFIG_NLS_ISO8859_15 If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs 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, @@ -13541,17 +15259,33 @@ 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. + support for French and Finnish, and adds the new Euro character. + If unsure, say Y. -nls koi8-r +NLS KOI8-R (Russian) CONFIG_NLS_KOI8_R If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs + from the Microsoft FAT file system family or from JOLIET CD-ROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the preferred Russian character set. +NLS KOI8-U/RU (Ukrainian, Belarusian) +CONFIG_NLS_KOI8_U + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the preferred Ukrainian + (koi8-u) and Belarusian (koi8-ru) character sets. + +NLS UTF8 +CONFIG_NLS_UTF8 + If you want to display filenames with native language characters + from the Microsoft FAT file system family or from JOLIET CD-ROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the UTF-8 encoding of + the Unicode/ISO9646 universal character set. + Virtual terminal CONFIG_VT If you say Y here, you will get support for terminal devices with @@ -13599,38 +15333,236 @@ If unsure, say Y. -Support for PowerMac keyboard -CONFIG_MAC_KEYBOARD +STI console +CONFIG_STI_CONSOLE + The STI console is the builtin display/keyboard on HP-PARISC + machines. Say Y here to build support for it into your kernel. + The alternative is to use your primary serial port as a console. + +Use MDIO for PHY configuration +CONFIG_USE_MDIO + On some boards the hardware configuration of the ethernet PHY can be + used without any software interaction over the MDIO interface, so + all MII code can be omitted. Say N here if unsure or if you don't + need link status reports. + +860T FEC Ethernet +CONFIG_FEC_ENET + Enable Ethernet support via the Fast Ethernet Controller (FCC) on + the Motorola MPC8260. + +Ethernet on FCC1 +CONFIG_FCC1_ENET + Use MPC8260 fast Ethernet controller 1 to drive Ethernet (default). + +Ethernet on FCC2 +CONFIG_FCC2_ENET + Use MPC8260 fast Ethernet controller 2 to drive Ethernet. + +Ethernet on FCC3 +CONFIG_FCC3_ENET + Use MPC8260 fast Ethernet controller 3 to drive Ethernet. + +CPM SCC Ethernet +CONFIG_SCC_ENET + Enable Ethernet support via the Motorola MPC8xx serial + commmunications controller. + +Ethernet on SCC1 +CONFIG_SCC1_ENET + Use MPC8xx serial communications controller 1 to drive Ethernet + (default). + +Ethernet on SCC2 +CONFIG_SCC2_ENET + Use MPC8xx serial communications controller 2 to drive Ethernet. + +Ethernet on SCC3 +CONFIG_SCC3_ENET + Use MPC8xx serial communications controller 3 to drive Ethernet. + +Use Big CPM Ethernet Buffers +CONFIG_ENET_BIG_BUFFERS + Allocate large buffers for MPC8xx Etherenet. Increases throughput + and decreases the likelihood of dropped packets, but costs memory. + +Apple Desktop Bus (ADB) support +CONFIG_ADB + Apple Desktop Bus (ADB) support is for support of devices which + are connected to an ADB port. ADB devices tend to have 4 pins. + If you have an Apple Macintosh prior to the iMac, or a + "Blue and White G3", you probably want to say Y here. Otherwise + say N. + +Support for CUDA based PowerMacs +CONFIG_ADB_CUDA + This provides support for CUDA based Power Macintosh systems. This + includes most OldWorld PowerMacs, the first generation iMacs, the + Blue&White G3 and the Yikes G4 (PCI Graphics). All later models + should use CONFIG_ADB_PMU instead. + + If unsure say Y. + +Support for PMU-based PowerMacs +CONFIG_ADB_PMU + On the PowerBook 3400 and 2400, the PMU is a 6805 microprocessor + core whose primary function is to control battery charging and + system power. The PMU also controls the ADB (Apple Desktop Bus) + which connects to the keyboard and mouse, as well as the + non-volatile RAM and the RTC (real time clock) chip. Say Y to + enable support for this device; you should do so if your machine + is one of these PowerBooks. + +Include MacIO ADB driver +CONFIG_ADB_MACIO + Say Y here to include direct support for the ADB controller in the + Hydra chip used on PowerPC Macintoshes of the CHRP type. (The Hydra + also includes a MESH II SCSI controller, DBDMA controller, VIA chip, + OpenPIC controller and two RS422/Geoports.) + +Support for ADB keyboard (old driver) +CONFIG_ADB_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 +HIL keyboard support +CONFIG_HIL + The "Human Interface Loop" is a older, 8-channel USB-like controller + used in Hewlette Packard PA-RISC based machines. There are a few + cases where it is seen on PC/MAC architectures as well, usually also + manufactured by HP. This driver is based off MACH and BSD drivers, + and implements support for a keyboard attached to the HIL port. + Full support for the USB-like functions and non-keyboard channels of + the HIL is not provided for in this driver. There are vestiges of + mouse support in the driver, but it is probably not working. The + necessary hardware documentation to fully support the HIL controller + and interface it to the linux-input API is lacking. + + Enable this option if you intend to use a HIL keyboard. + +Include IOP (IIfx/Quadra 9x0) ADB driver +CONFIG_ADB_IOP + The I/O Processor (IOP) is an Apple custom IC designed to provide + intelligent support for I/O controllers. It is described at + to enable direct + support for it, say 'Y' here. + +Mac II style Apple Desktop Bus support +CONFIG_ADB_MACII + Say Y here if want your kernel to support Macintosh systems that use + the Mac II style ADB. This includes the II, IIx, IIcx, SE/30, IIci, + Quadra 610, Quadra 650, Quadra 700, Quadra 800, Centris 610 and + Centris 650. + +Mac IIsi style Apple Desktop Bus support +CONFIG_ADB_MACIISI + Say Y here if want your kernel to support Macintosh systems that use + the Mac IIsi style ADB. This includes the IIsi, IIvi, IIvx, Classic + II, LC, LC II, LC III, Performa 460, and the Performa 600. + +Apple 68K PowerBook Power Management and Desktop Bus support +CONFIG_ADB_PMU68K + Say Y here if want your kernel to support the m68k based Powerbooks. + This includes the PowerBook 140, PowerBook 145, PowerBook 150, + PowerBook 160, PowerBook 165, PowerBook 165c, PowerBook 170, + PowerBook 180, PowerBook, 180c, PowerBook 190cs, PowerBook 520, + PowerBook Duo 210, PowerBook Duo 230, PowerBook Duo 250, + PowerBook Duo 270c, PowerBook Duo 280 and PowerBook Duo 280c. + +Macintosh IIfx/Quadra 900/Quadra 950 floppy support +CONFIG_BLK_DEV_SWIM_IOP + Say Y here to support the SWIM (Super Woz Integrated Machine) IOP + floppy controller on the Macintosh IIfx and Quadra 900/950. + +Macintosh NS8390 based Ethernet support +CONFIG_MAC8390 + If you want to include a driver to support Nubus or LC-PDS + Ethernet cards using an NS8390 chipset or its equivalent, say Y + and read the Ethernet-HOWTO, available from + . + +Macintosh CS89x0 based Ethernet support +CONFIG_MAC89x0 + Support for CS89x0 chipset based Ethernet cards. If you have a + Nubus or LC-PDS network (Ethernet) card of this type, say Y and + read the Ethernet-HOWTO, available from + . + + 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 as well as + . This module will + be called mac89x0.o. + +Macintosh onboard AMD 79C940 MACE based Ethernet support +CONFIG_MACMACE + Support for the onboard AMD 79C940 MACE Ethernet controller used in + the 660AV and 840AV Macintosh. If you have one of these Macintoshes + say Y and read the Ethernet-HOWTO, available from + . + +Macintosh SONIC based Ethernet support (onboard, NuBus, LC, CS) +CONFIG_MACSONIC + Support for NatSemi SONIC based Ethernet devices. This includes + the onboard Ethernet in many Quadras as well as some LC-PDS, + a few Nubus and all known Comm Slot Ethernet cards. If you have + one of these say Y and read the Ethernet-HOWTO, available from + . + + 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 as well as + . This module will + be called macsonic.o. + +Macintosh NCR5380 SCSI support +CONFIG_MAC_SCSI + This is the NCR 5380 SCSI controller included on most of the 68030 + based Macintoshes. If you have one of these say Y and read the + SCSI-HOWTO, available from + . + +Macintosh NCR53c9[46] SCSI support +CONFIG_SCSI_MAC_ESP + This is the NCR 53c9x SCSI controller found on most of the 68040 + based Macintoshes. If you have one of these say Y and read the + SCSI-HOWTO, available from + . + + 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 mac_esp.o. If you want to compile it as + a module, say M here and read . + +Standard/generic (8250/16550 and compatible UARTs) 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.) + 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. + . 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 + 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. - + 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 + 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, @@ -13671,7 +15603,8 @@ 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. + . The module will be called + rocket.o. Digiboard Intelligent async support CONFIG_DIGIEPCA @@ -13681,14 +15614,14 @@ 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. + 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. + . The module will be called epca.o. Digiboard PC/Xx Support CONFIG_DIGI @@ -13696,10 +15629,10 @@ 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. + Y here and read the file . 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. + . The module will be called pcxx.o. SDL RISCom/8 card support CONFIG_RISCOM8 @@ -13707,7 +15640,7 @@ 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. + say Y here and read the file . Also it's possible to say M here and compile this driver as kernel loadable module; the module will be called riscom8.o. @@ -13715,37 +15648,50 @@ 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 and + controllers with the exception of the MicroChannel controllers and 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. + 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 . 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. + say M here and read . 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 + 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. + . 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. + The Specialix IO8+ 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 + for more information. + +Specialix RIO system support +CONFIG_RIO + This is a driver for the Specialix RIO, a smart serial card which + drives an outboard box that can support up to 128 ports. Product + information is at . + There are both ISA and PCI versions. + +Support really old RIO/PCI cards +CONFIG_RIO_OLDPCI + Older RIO PCI cards need some initialization-time configuration to + determine the IRQ and some control addresses. If you have a RIO and + this doesn't seem to work, try setting this to Y. Cyclades async mux support CONFIG_CYCLADES @@ -13753,19 +15699,19 @@ 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. + say M here and read . 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) +Cyclades-Z interrupt mode operation 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 @@ -13775,47 +15721,47 @@ status of the Cyclades-Z ports. The default op mode is polling. If unsure, say N. -Stallion multiport serial support +Stallion multiport serial support CONFIG_STALDRV - Stallion cards give you many serial ports. You would need something + 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. + 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 in + this case. If you have never heard about all this, it's safe to + say N. -Stallion EasyIO or EC8/32 support +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. + card, then this is for you; say Y. Make sure to read + . 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. + say M here and read . 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 + read . 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). + 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 + The module will be called synclink.o. If you want to do that, say M here. Synchronous HDLC line discipline support @@ -13831,7 +15777,7 @@ 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. + Please read the file 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). @@ -13839,14 +15785,14 @@ 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. + This is a driver which supports Hayes ESP serial ports. Both single + port cards and multiport cards are supported. Make sure to read + . 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. + and read . The module will be + called esp.o. If unsure, say N. Moxa Intellio support CONFIG_MOXA_INTELLIO @@ -13866,13 +15812,14 @@ The module will be called mxser.o. If you want to do that, say M here. -Multi-Tech multiport card support (EXPERIMENTAL) +Multi-Tech multiport card support 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 + 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 + the running kernel whenever you want). Please read + . The module will be called + isicom.o. Unix98 PTY support CONFIG_UNIX98_PTYS @@ -13882,7 +15829,7 @@ 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, @@ -13898,8 +15845,8 @@ 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. + Read the instructions in pertaining to + pseudo terminals. It's safe to say N. Maximum number of Unix98 PTYs in use (0-2048) CONFIG_UNIX98_PTY_COUNT @@ -13916,23 +15863,23 @@ 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://www.linuxdoc.org/docs.html#howto . + printer has 9 or 25 holes ["female"], then it's serial), say Y. + Also read the Printing-HOWTO, available from + . 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 + 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. + read and + . 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" + 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 syntax of the - "lp" command line option can be found in drivers/char/lp.c. + how to pass options to the kernel at boot time.) The syntax of the + "lp" command line option can be found in . If you have more than 8 printers, you need to increase the LP_NO macro in lp.c and the PARPORT_MAX macro in parport.h. @@ -13949,7 +15896,7 @@ By defining CONSOLE_LP_STRICT to 0 (at your own risk) you can make the kernel continue when this happens, but it'll lose the kernel messages. - + If unsure, say N. Support for user-space parallel port device drivers @@ -13963,74 +15910,206 @@ 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. + This support is also available as a module. If you want to compile + it as a module, say M here and read + . The module will be called + ppdev.o. If unsure, say N. +Cobalt Networks support +CONFIG_COBALT + Support for Cobalt Networks x86-based servers. + +Gen III (3000 series) system support +CONFIG_COBALT_GEN_III + This option enables support for the 3000 series of Cobalt Networks + systems. This includes the RaQ 3, RaQ 4, and Qube 3 product lines. + + This platform uses an AMD K6-2 processor, an ALI M1541/1533 chipset, + an optional NCR 53c875 SCSI controller, and two Intel 82559ER or + National Semiconductor DP83815 NICs. + + Getting this option wrong will likely result in a kernel that does + not boot. Selecting support for more than 1 system series will add + bloat to your kernel, but will not cause anything bad to happen. + + If you have a Cobalt Networks System, but aren't sure what kind, + say Y here. + +Gen V (5000 series) system support +CONFIG_COBALT_GEN_V + This option enables support for the 5000 series of Cobalt Networks + systems. This includes the RaQ XTR product line. + + This platform uses Intel Pentium III Coppermine FCPGA CPUs, the + ServerWorks LE chipset (with registered ECC DIMMs only!), two + HighPoint HPT370 IDE controllers, and two National Semiconductor + DP83815 NICs. + + Getting this option wrong will likely result in a kernel that does + not boot. Selecting support for more than 1 system series will add + bloat to your kernel, but will not cause anything bad to happen. + + If you have a Cobalt Networks System, but aren't sure what kind, + say Y here. + +Create legacy /proc files +CONFIG_COBALT_OLDPROC + This option forces some Cobalt Networks drivers to support legacy + files in /proc. Older versions of these drivers exported files + directly in /proc, as opposed to the newer /proc/cobalt. If you say + N to this option, the old filenames will no longer be exported. + Regardless of your selection here, files in /proc/cobalt will be + exported. Of course, you have to include support for /proc fs, too. + + It is safe to say Y here. + +Front panel LCD support +CONFIG_COBALT_LCD + This enables support for the Cobalt Networks front panel. This is + for the LCD panel and buttons. The primary method for connection is + via the parallel port (IO base 0x370), but newer systems use an + I2C bus. + + If you have a Cobalt Networks system, you should say Y here. + +Software controlled LED support +CONFIG_COBALT_LED + This enables support for the software-controlled LEDs on Cobalt + Networks systems. This includes the fault light and front panel + LEDs on the RaQ XTR, the lightbar on the Qube 3, and others. + + If you have a Cobalt Networks system, you should say Y here. + +Silicon serial number support +CONFIG_COBALT_SERNUM + This enables support for the on-board serial number on Cobalt + Networks systems. This is a universally-unique 64-bit serial + number. Some systems use a Dallas DS2401 chip, others have an I2C + based EEPROM. + + If you select Y here, the files /proc/cobalt/hostid and + /proc/cobalt/serialnumber will be created. The hostid file contains + a 32 bit integer generated from the serial number, in binary form. + The serialnumber file contains the hexadecimal representation of the + serial number, in ASCII. + + If you have a Cobalt Networks system, you should say Y here. + +Chipset watchdog timer support +CONFIG_COBALT_WDT + This enables support for the watchdog timer built into Cobalt + chipsets. The timer wakes up periodically, to make find out if + system has hung, or disabled interrupts too long. The result of + detecting a hang is a hard reboot. + + If you have a Cobalt Networks system, you should say Y here. + +Thermal sensor support +CONFIG_COBALT_THERMAL + This enables support for the thermal sensor(s) built into Cobalt + Networks systems. This driver exports /proc/cobalt/thermal_sensors. + + If you have a Cobalt Networks system, you should say Y here. + +Fan tachometer support +CONFIG_COBALT_FANS + This enables support for the fan tachometers built into some Cobalt + Networks systems. This driver exports /proc/cobalt/faninfo. Some + Cobalt software depends on this feature, and enabling it does not + cause any risks. + + If you have a Cobalt Networks system, you should say Y here, unless + you are absolutely sure. + +Disk drive ruler support +CONFIG_COBALT_RULER + This enables support for the cobalt hard drive ruler, found on some + Cobalt systems, including the RaQ XTR. This is the device that + enables swapping of drives. It is not needed for basic disk + operation. Enabling this on a system with no ruler will have no + adverse effects. + + If you have a Cobalt Networks system, you should say Y here, + unless you are absolutely sure. + I2C support CONFIG_I2C I2C (pronounce: I-square-C) is a slow serial bus protocol used in - many micro controller applications and developed by Philips. SMBus, - or System Management Bus is a subset of the I2C protocol. More - information is contained in the directory Documentation/i2c/, + many micro controller applications and developed by Philips. SMBus, + or System Management Bus is a subset of the I2C protocol. More + information is contained in the directory , especially in the file called "summary" there. Both I2C and SMBus are supported here. You will need this for - hardware sensors support, and also for Video for Linux support. + hardware sensors support, and also for Video For Linux support. Specifically, if you want to use a BT848 based frame grabber/overlay boards under Linux, say Y here and also to "I2C bit-banging interfaces", below. If you want I2C support, you should say Y here and also to the - specific driver for your bus adapter(s) below. If you say Y to + specific driver for your bus adapter(s) below. If you say Y to "/proc file system" below, you will then get a /proc interface which - is documented in Documentation/i2c/proc-interface. + is documented in . - This I2C support is also available as a module. If you want to + This I2C 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 i2c-core.o. + . + The module will be called i2c-core.o. + +UltraSPARC-III bootbus i2c controller driver +CONFIG_BBC_I2C + The BBC devices on the UltraSPARC III have two I2C controllers. The + first I2C controller connects mainly to configuration PROMs (NVRAM, + CPU configuration, DIMM types, etc.). The second I2C controller + connects to environmental control devices such as fans and + temperature sensors. The second controller also connects to the + smartcard reader, if present. Say Y to enable support for these. I2C bit-banging interfaces CONFIG_I2C_ALGOBIT This allows you to use a range of I2C adapters called bit-banging - adapters. Say Y if you own an I2C adapter belonging to this class + adapters. Say Y if you own an I2C adapter belonging to this class and then say Y to the specific driver for you adapter below. - 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 i2c-algo-bit.o. + This support is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-algo-bit.o. Philips style parallel port adapter CONFIG_I2C_PHILIPSPAR - This supports parallel-port I2C adapters made by Philips. Say Y if + This supports parallel-port I2C adapters made by Philips. Say Y if you own such an adapter. - This driver 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 i2c-philips-par.o. + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-philips-par.o. Note that if you want support for different parallel port devices, life will be much easier if you compile them all as modules. ELV adapter CONFIG_I2C_ELV - This supports parallel-port I2C adapters called ELV. Say Y if you + This supports parallel-port I2C adapters called ELV. Say Y if you own such an adapter. - This driver 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 i2c-elv.o. + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-elv.o. Velleman K9000 adapter CONFIG_I2C_VELLEMAN - This supports the Velleman K9000 parallel-port I2C adapter. Say Y if - you own such an adapter. + This supports the Velleman K9000 parallel-port I2C adapter. Say Y + if you own such an adapter. - This driver 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 i2c-velleman.o. + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-velleman.o. I2C PCF 8584 interfaces CONFIG_I2C_ALGOPCF @@ -14038,29 +16117,41 @@ Say Y if you own an I2C adapter belonging to this class and then say Y to the specific driver for you adapter below. - 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 i2c-algo-pcf.o. + This support is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-algo-pcf.o. Elektor ISA card CONFIG_I2C_ELEKTOR - This supports the PCF8584 ISA bus I2C adapter. Say Y if you own such - an adapter. + This supports the PCF8584 ISA bus I2C adapter. Say Y if you own + such an adapter. - This driver 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 i2c-elektor.o. + This driver is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-elektor.o. I2C device interface CONFIG_I2C_CHARDEV Say Y here to use i2c-* device files, usually found in the /dev - directory on your system. They make it possible to have user-space - programs use the I2C bus. Information on how to do this is contained - in the file Documentation/i2c/dev-interface. + directory on your system. They make it possible to have user-space + programs use the I2C bus. Information on how to do this is + contained in the file . + + This code is also available as a module. If you want to compile + it as a module, say M here and read + . + The module will be called i2c-dev.o. + +I2C /proc support +CONFIG_I2C_PROC + This provides support for i2c device entries in the /proc filesystem. + The entries will be found in /proc/sys/dev/sensors. This code 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 i2c-dev.o. + it as a module, say M here and read . + The module will be called i2c-proc.o. Bus Mouse Support CONFIG_BUSMOUSE @@ -14069,11 +16160,11 @@ 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://www.linuxdoc.org/docs.html#howto , and say Y here. + , 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. + 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 @@ -14082,7 +16173,7 @@ 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. + module, say M here and read . Mouse Support (not serial and bus mice) CONFIG_MOUSE @@ -14092,30 +16183,30 @@ 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://www.linuxdoc.org/docs.html#howto . This HOWTO contains + . 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. + 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 + kernel: saying N will just cause the configurator 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 + 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://www.linuxdoc.org/docs.html#howto . + you don't need this option. You want to read the Busmouse-HOWTO, + available from . 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. + say M here and read . 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 @@ -14129,12 +16220,12 @@ Although PS/2 mice are not technically bus mice, they are explained in detail in the Busmouse-HOWTO, available from - http://www.linuxdoc.org/docs.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 + ) solves this problem, or you can get the "mconv2" utility from the same location. C&T 82C710 mouse port support (as on TI Travelmate) @@ -14142,25 +16233,25 @@ 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://www.linuxdoc.org/docs.html#howto . + . PC110 digitizer pad support CONFIG_PC110_PAD - This drives the digitizer pad on the IBM PC110 palmtop. It can turn + 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. + say M here and read . 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://www.linuxdoc.org/docs.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 @@ -14169,41 +16260,33 @@ 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 support -CONFIG_ADB - Apple Desktop Bus (ADB) support is for support of devices which - are connected to an ADB port. ADB devices tend to have 4 pins. - If you have an Apple Macintosh prior to the iMac, or a - "Blue and White G3", you probably want to say Y here. Otherwise - say N. + say M here and read . 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://www.linuxdoc.org/docs.html#howto . + is common on Macintoshes. You may want to read the Busmouse-HOWTO, + available from . 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. + say M here and read . 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 + 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 + "Microsoft busmouse support" above if you have one of those. Read the Busmouse-HOWTO, available from - http://www.linuxdoc.org/docs.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. + say M here and read . 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. @@ -14213,29 +16296,34 @@ 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 + and read . The module will be called tpqic02.o. +iSeries Virtual Tape Support +CONFIG_VIOTAPE + If you are running Linux on an iSeries system and you want Linux + to read and/or write a tape drive owned by OS/400, say Y here. + 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. + header file (), 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. + 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. + 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 @@ -14243,56 +16331,57 @@ 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. + 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. + please read the file . 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. + module, say M here and read . 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 + information. There is a web page with more recent documentation at + . 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. + documentation, FAQ). Note that the file system interface has + changed quite a bit compared to previous versions of ftape. Please + read . -The file system interface for ftape +VFS 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 + 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. + running kernel whenever you want). In this case you should read + . 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 + 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 + Despite its name, zftape does NOT use compression by default. The + file contains a short description of + the most important changes in the file system interface compared to + previous versions of ftape. The ftape home page + contains further information. IMPORTANT NOTE: zftape can read archives created by previous @@ -14331,7 +16420,7 @@ wastes 32 KB of memory. Please note that this memory cannot be swapped out. -Procfs entry for ftape +Enable procfs status report (+2kb) 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 @@ -14348,6 +16437,7 @@ interface. Accessing `/proc/ftape' while the module is unloaded will result in a kernel Oops. This cannot be fixed from inside ftape. +# Choice: ftdebug Controlling the amount of debugging output of ftape CONFIG_FT_NORMAL_DEBUG This option controls the amount of debugging output the ftape driver @@ -14369,9 +16459,22 @@ printed to the console but only makes it possible to produce "Excessive" debugging output. - Please read Documentation/ftape.txt for a short description + Please read for a short description how to control the amount of debugging output. +Excessive +CONFIG_FT_FULL_DEBUG + Extremely verbose output for driver debugging purposes. + +Reduced +CONFIG_FT_NO_TRACE + Reduced tape driver debugging output. + +None +CONFIG_FT_NO_TRACE_AT_ALL + Suppress all debugging output from the tape drive. + +# Choice: ftcontroller The floppy drive controller for ftape CONFIG_FT_STD_FDC Only change this setting if you have a special controller. If you @@ -14407,13 +16510,13 @@ 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 + Please read also the file 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 +IO base for 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: @@ -14435,9 +16538,9 @@ "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. + Please read also the file 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 @@ -14461,9 +16564,9 @@ "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. + Please read also the file 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 @@ -14487,9 +16590,9 @@ "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. + Please read also the file 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 @@ -14521,10 +16624,16 @@ introduced in XFree86 4.0. If you say Y here, you need to select the module that's right for your graphics card from the list below. These modules provide support for synchronization, security, and - DMA transfers. Please see http://dri.sourceforge.net for more + DMA transfers. Please see for more details. You should also select and configure AGP (/dev/agpgart) support. +Build drivers for new (XFree 4.1) DRM +CONFIG_DRM_NEW + If you set this option, the new DRM version needed by XFree86 4.1 + will be used. Otherwise, the old DRM version will be used, + appropriate for XFree86 4.0. + 3dfx Banshee/Voodoo3+ CONFIG_DRM_TDFX Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), @@ -14541,19 +16650,69 @@ is selected, the module will be called r128.o. AGP support for this card is strongly suggested (unless you have a PCI version). +ATI Radeon +CONFIG_DRM_RADEON + Choose this option if you have an ATI Radeon graphics card. There + are both PCI and AGP versions. You don't need to choose this to + run the Radeon in plain VGA mode. There is a product page at + . + If M is selected, the module will be called radeon.o. + Intel I810 CONFIG_DRM_I810 Choose this option if you have an Intel I810 graphics card. If M is selected, the module will be called i810.o. AGP support is required for this driver to work. -Matrox g200/g400 +Matrox G200/G400/G450 CONFIG_DRM_MGA - Choose this option if you have a Matrox g200 or g400 graphics card. If M - is selected, the module will be called mga.o. AGP support is required + Choose this option if you have a Matrox G200, G400 or G450 graphics + card. If M is selected, the module will be called mga.o. AGP + support is required for this driver to work. + +3dfx Banshee/Voodoo3+ +CONFIG_DRM40_TDFX + Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), + graphics card. If M is selected, the module will be called tdfx.o. + +3dlabs GMX 2000 +CONFIG_DRM40_GAMMA + Choose this option if you have a 3dlabs GMX 2000 graphics card. + If M is selected, the module will be called gamma.o. + +ATI Rage 128 +CONFIG_DRM40_R128 + Choose this option if you have an ATI Rage 128 graphics card. If M + is selected, the module will be called r128.o. AGP support for + this card is strongly suggested (unless you have a PCI version). + +ATI Radeon +CONFIG_DRM40_RADEON + Choose this option if you have an ATI Radeon graphics card. There + are both PCI and AGP versions. You don't need to choose this to + run the Radeon in plain VGA mode. There is a product page at + . + If M is selected, the module will be called radeon.o. + +Intel I810 +CONFIG_DRM40_I810 + Choose this option if you have an Intel I810 graphics card. If M is + selected, the module will be called i810.o. AGP support is required for this driver to work. -MTRR control and configuration +Matrox G200/G400/G450 +CONFIG_DRM40_MGA + Choose this option if you have a Matrox G200, G400 or G450 graphics + card. If M is selected, the module will be called mga.o. AGP + support is required for this driver to work. + +Creator/Creator3D/Elite3D +CONFIG_DRM_FFB + Choose this option if you have one of Sun's Creator3D-based graphics + and frame buffer cards. Product page at + . + +MTRR (Memory Type Range Register) support CONFIG_MTRR On Intel P6 family processors (Pentium Pro, Pentium II and later) the Memory Type Range Registers (MTRRs) may be used to control @@ -14563,10 +16722,10 @@ before bursting over the PCI/AGP bus. This can increase performance of image write operations 2.5 times or more. Saying Y here creates a /proc/mtrr file which may be used to manipulate your processor's - MTRRs. Typically the X server should use this. + MTRRs. Typically the X server should use this. - This code has a reasonably generic interface so that similar - control registers on other processors can be easily supported + This code has a reasonably generic interface so that similar + control registers on other processors can be easily supported as well: The Cyrix 6x86, 6x86MX and M II processors have Address Range @@ -14584,9 +16743,9 @@ You can safely say Y even if your machine doesn't have MTRRs, you'll just add about 9 KB to your kernel. - See Documentation/mtrr.txt for more information. + See for more information. -Main CPU frequency, only for DEC alpha machine +CPU clock frequency of your DEC Alpha 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 @@ -14595,11 +16754,11 @@ 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 + manufactured by RC Systems (). 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. + . The module will be called dtlk.o. Siemens R3964 serial protocol support CONFIG_R3964 @@ -14609,7 +16768,7 @@ 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 + and read . The module will be called n_r3964.o. If unsure, say N. @@ -14619,28 +16778,28 @@ 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 + , 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 + and read . The module will be called applicom.o. If unsure, say N. Sony Vaio Programmable I/O Control Device support CONFIG_SONYPI - This driver enables access to the Sony Programmable I/O Control Device - which can be found in many (all ?) Sony Vaio laptops. + This driver enables access to the Sony Programmable I/O Control + Device which can be found in many (all ?) Sony Vaio laptops. - If you have one of those laptops, read Documentation/sonypi.txt, - and say Y or M here. + If you have one of those laptops, read + , and say Y or M 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 . The module will be - called sonypi.o. + say M here and read . The module + will be called sonypi.o. Intel Random Number Generator support CONFIG_INTEL_RNG @@ -14653,7 +16812,7 @@ 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 + and read . The module will be called i810_rng.o. If unsure, say N. @@ -14662,50 +16821,76 @@ CONFIG_PM "Power Management" means that parts of your computer are shut off or put into a power conserving "sleep" mode if they are not - being used. There are two competing standards for doing this: APM - and ACPI. If you want to use either one, say Y here and then also to - the requisite support below. + being used. There are two competing standards for doing this: APM + and ACPI. If you want to use either one, say Y here and then also + to the requisite support below. Power Management is most important for battery powered laptop computers; if you have a laptop, check out the Linux Laptop home page on the WWW at - http://www.cs.utexas.edu/users/kharker/linux-laptop/ and the Battery - Powered Linux mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + and the + Battery Powered Linux mini-HOWTO, available from + . Note that, even if you say N here, Linux on the x86 architecture will issue the hlt instruction if nothing is to be done, thereby sending the processor to sleep and saving power. +USB SE401 Camera support +CONFIG_USB_SE401 + Say Y here if you want to connect this type of camera to your + computer's USB port. See for more + information and for a list of supported cameras. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Multimedia Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + on the WWW at . + + 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 se401.o. If you want to compile it as a + module, say M here and read . + ACPI support CONFIG_ACPI - ACPI/OSPM support for Linux is currently under development. As such, - this support is preliminary and EXPERIMENTAL. Configuring ACPI support - enables kernel interfaces that allow higher level software (OSPM) to - manipulate ACPI defined hardware and software interfaces, including - the evaluation of ACPI control methods. If unsure, choose N here. - Note, this option will enlarge your kernel by about 120K. + ACPI/OSPM support for Linux is currently under development. As such, + this support is preliminary and EXPERIMENTAL. Configuring ACPI + support enables kernel interfaces that allow higher level software + (OSPM) to manipulate ACPI defined hardware and software interfaces, + including the evaluation of ACPI control methods. If unsure, choose + N here. Note, this option will enlarge your kernel by about 120K. This support requires an ACPI compliant platform (hardware/firmware). If both ACPI and Advanced Power Management (APM) support are configured, whichever is loaded first shall be used. - This code DOES NOT currently provide a complete OSPM implementation -- - it has not yet reached APM's level of functionality. When fully + This code DOES NOT currently provide a complete OSPM implementation + -- it has not yet reached APM's level of functionality. When fully implemented, Linux ACPI/OSPM will provide a more robust functional - replacement for legacy configuration and power management interfaces, - including the Plug-and-Play BIOS specification (PNP BIOS), the Multi- - Processor Specification (MPS), and the Advanced Power Management - specification (APM). + replacement for legacy configuration and power management + interfaces, including the Plug-and-Play BIOS specification (PnP + BIOS), the Multi-Processor Specification (MPS), and the Advanced + Power Management specification (APM). Linux support for ACPI/OSPM is based on Intel Corporation's ACPI Component Architecture (ACPI CA). The latest ACPI CA source code, documentation, debug builds, and implementation status information can be downloaded from: - http://developer.intel.com/technology/iapc/acpi/downloads.htm - + . + The ACPI mailing list may also be of interest: - http://phobos.fs.tum.de/acpi/index.html + . + +Enable ACPI 2.0 with errata 1.3 +CONFIG_ACPI20 + Enable support for the 2.0 version of the ACPI interpreter. See the + help for ACPI for caveats and discussion. + +ACPI kernel configuration manager +CONFIG_ACPI_KERNEL_CONFIG + If you say `Y' here, Linux's ACPI support will use the + hardware-level system descriptions found on IA64 machines. ACPI Debug Statements CONFIG_ACPI_DEBUG @@ -14716,37 +16901,39 @@ ACPI Bus Manager CONFIG_ACPI_BUSMGR The ACPI Bus Manager enumerates devices in the ACPI namespace, and - handles PnP messages. All ACPI devices use its services, so using them - requires saying Y here. + handles PnP messages. All ACPI devices use its services, so using + them requires saying Y here. ACPI System Driver CONFIG_ACPI_SYS - This driver will enable your system to shut down using ACPI, and dump - your ACPI DSDT table using /proc/acpi/dsdt. + This driver will enable your system to shut down using ACPI, and + dump your ACPI DSDT table using /proc/acpi/dsdt. ACPI Processor Driver CONFIG_ACPI_CPU - This driver installs ACPI as the idle handler for Linux, and uses ACPI - C2 and C3 processor states to save power, on systems that support it. + This driver installs ACPI as the idle handler for Linux, and uses + ACPI C2 and C3 processor states to save power, on systems that + support it. ACPI Button CONFIG_ACPI_BUTTON - This driver registers for events based on buttons, such as the power, - sleep, and lid switch. In the future, a daemon will read + This driver registers for events based on buttons, such as the + power, sleep, and lid switch. In the future, a daemon will read /proc/acpi/event and perform user-defined actions such as shutting - down the system. Until then, you can cat it, and see output when + down the system. Until then, you can cat it, and see output when a button is pressed. ACPI AC Adapter CONFIG_ACPI_AC This driver adds support for the AC Adapter object, which indicates - whether a system is on AC, or not. Typically, only laptops have this - object, since desktops are always on AC. + whether a system is on AC, or not. Typically, only laptops have + this object, since desktops are always on AC. ACPI Embedded Controller CONFIG_ACPI_EC - This driver is required on some systems for the proper operation of the - battery and thermal drivers. If you are compiling for a laptop, say Y. + This driver is required on some systems for the proper operation of + the battery and thermal drivers. If you are compiling for a laptop, + say Y. ACPI Control Method Battery CONFIG_ACPI_CMBATT @@ -14774,13 +16961,13 @@ machines with more than one CPU. In order to use APM, you will need supporting software. For location - and more information, read Documentation/pm.txt and the Battery - Powered Linux mini-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + and more information, read and the + Battery Powered Linux mini-HOWTO, available from + . 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. + 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" @@ -14791,30 +16978,30 @@ 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). + 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 + 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 + 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/ + 7) read the sig11 FAQ at 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 + 11) exchange RAM chips 12) exchange the motherboard. 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 + and read . The module will be called apm.o. Ignore USER SUSPEND @@ -14839,7 +17026,7 @@ T400CDT. This is off by default since most machines do fine without this feature. -Do CPU IDLE calls +Make CPU Idle calls when idle 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 @@ -14887,7 +17074,7 @@ a work-around for a number of buggy BIOSes. Switch this option on if your computer crashes instead of powering off properly. -Watchdog Timer Support +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 @@ -14899,12 +17086,12 @@ 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. + your computer. For details, read + in the kernel source. - The watchdog is usually used together with the watchdog daemon + 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 + . This daemon can also monitor NFS connections and can reboot the machine when the process table is full. @@ -14929,22 +17116,22 @@ 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. + say M here and read . The module + will be called wdt.o. WDT PCI Watchdog timer CONFIG_WDTPCI - If you have a PCI WDT500/501 watchdog board, say Y here, - otherwise N. It is not possible to probe for this board, which means - that you have to inform the kernel about the IO port and IRQ using - the "wdt=" kernel 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). + If you have a PCI WDT500/501 watchdog board, say Y here, otherwise + N. It is not possible to probe for this board, which means that you + have to inform the kernel about the IO port and IRQ using the "wdt=" + kernel 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). 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_pci.o. + say M here and read . The module + will be called wdt_pci.o. WDT501 features CONFIG_WDT_501 @@ -14964,12 +17151,13 @@ 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. + 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. + . The module will be called + softdog.o. Berkshire Products PC Watchdog CONFIG_PCWATCHDOG @@ -14977,55 +17165,90 @@ 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 . + hardware. Please read . The PC + watchdog cards can be ordered from . 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. + say M here and read . 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 + 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 + The module is called pscwdt.o. If you want to compile it as a + module, say M here and read . Most + people will say N. + +Advantech SBC Watchdog Timer +CONFIG_ADVANTECH_WDT + If you are configuring a Linux kernel for the Advantech single-board + computer, say `Y' here to support its built-in watchdog timer + feature. See the help for CONFIG_WATCHDOG for discussion. + +W83877F Watchdog Timer +CONFIG_W83877F_WDT + This is the driver for the hardware watchdog on the W83877F chipset + as used in EMACS PC-104 motherboards (and likely 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 also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called mixcomwd.o. If you want to compile it as a + module, say M here and read . Most + people will say N. + +IB700 SBC Watchdog Timer +CONFIG_IB700_WDT + This is the driver for the hardware watchdog on the IB700 Single + Board Computer produced by TMC Technology (www.tmc-uk.com). 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 slightly 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 ib700wdt.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. Most people will say N. Mixcom Watchdog -CONFIG_MIXCOMWD - This is a driver for the Mixcom hardware watchdog cards. This +CONFIG_MIXCOMWD + This is a driver for the Mixcom hardware watchdog cards. 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 also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module is called mixcomwd.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. Most people - will say N. + The module is called mixcomwd.o. If you want to compile it as a + module, say M here and read . Most + people will say N. ZF MachZ Watchdog CONFIG_MACHZ_WDT - If you are using a ZF Micro MachZ processor, say Y here, otherwise N. - This is the driver for the watchdog timer builtin on that processor - using ZF-Logic interface. 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. + If you are using a ZF Micro MachZ processor, say Y here, otherwise + N. This is the driver for the watchdog timer builtin on that + processor using ZF-Logic interface. 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 also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module is called machzwd.o. If you want to compile it as a module, - say M here and read Documentation/modules.txt. + The module is called machzwd.o. If you want to compile it as a + module, say M here and read . SuperH 3/4 Watchdog CONFIG_SH_WDT @@ -15040,13 +17263,14 @@ Toshiba Laptop support CONFIG_TOSHIBA - This adds a driver to safely access the System Management Mode - of the CPU on Toshiba portables. The System Management Mode + This adds a driver to safely access the System Management Mode of + the CPU on Toshiba portables with a genuine Toshiba BIOS. It does + not work on models with a Pheonix BIOS. The System Management Mode is used to set the BIOS and power saving options on Toshiba portables. For information on utilities to make use of this driver see the Toshiba Linux utilities web site at: - http://www.buzzard.org.uk/toshiba/ + . Say Y if you intend to run this kernel on a Toshiba portable. Say N otherwise. @@ -15065,7 +17289,7 @@ For information on utilities to make use of this driver see the I8K Linux utilities web site at: - http://www.debian.org/~dz/i8k/ + Say Y if you intend to run this kernel on a Dell Inspiron 8000. Say N otherwise. @@ -15075,18 +17299,19 @@ If you say Y here and also to "/dev file system support" in the 'File systems' section, you will be able to update the microcode on Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II, - Pentium III, Pentium 4, Xeon etc. You will obviously need the actual - microcode binary data itself which is not shipped with the Linux kernel. + Pentium III, Pentium 4, Xeon etc. You will obviously need the + actual microcode binary data itself which is not shipped with the + Linux kernel. For latest news and information on obtaining all the required ingredients for this driver, check: - http://www.urbanmyth.org/microcode/ + . 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 microcode.o. 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 the line + The module will be called microcode.o. If you want to compile it as + a module, say M here and read . If + you use modprobe or kmod you may also want to add the line 'alias char-major-10-184 microcode' to your /etc/modules.conf file. /dev/cpu/*/msr - Model-specific register support @@ -15120,7 +17345,7 @@ 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 (or hardware clock) built + will get access to the real time clock (or hardware clock) built into your computer. Every PC has such a clock built in. It can be used to generate @@ -15134,23 +17359,19 @@ 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. + sampling), then say Y here, and read + 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 is called rtc.o. If you want to compile it as a module, - say M here and read Documentation/modules.txt. - -### Add -#EFI Real Time Clock Services -#CONFIG_EFI_RTC + say M here and read . 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. + communicate with it via a character special device. If unsure, say N. @@ -15160,7 +17381,7 @@ 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. + 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 @@ -15177,8 +17398,9 @@ 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. + module, say M here and read . +# Linus tree only Joystick support CONFIG_JOYSTICK If you have a joystick, 6dof controller, gamepad, steering wheel, @@ -15186,232 +17408,299 @@ enable generic support for these controllers. You will also need to say Y or M to at least one of the hardware specific drivers. This will make the controllers available as /dev/input/jsX devices. - Please read the file Documentation/joystick.txt which contains more - information and the location of the joystick package that you'll - need. + Please read the file which + contains more information and the location of the joystick package + that you'll need. + +# AC tree only +Game port support +CONFIG_INPUT_GAMEPORT + Gameport support is for the standard 15-pin PC gameport. If you + have a joystick, gamepad, gameport card, a soundcard with a gameport + or anything else that uses the gameport, say Y or M here and also to + at least one of the hardware specific drivers. + Please read the file which + contains more information and the location of the joystick package + that you'll need if you use the gameport with a joystick. + + 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 gameport.o. If you want to compile it as + a module, say M here and read . -ns558 gameports +Classic ISA/PnP gameports CONFIG_INPUT_NS558 - Say Y here if you have an ISA, ISAPnP or PCI standard gameport. + Say Y here if you have an ISA or PnP gameport. For more information on how to use the driver please read - Documentation/joystick.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 ns558.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called ns558.o. If you want to compile it as a + module, say M here and read . PDPI Lightning 4 gamecard CONFIG_INPUT_LIGHTNING Say Y here if you have a PDPI Lightning 4 gamecard. For more information on how to use the driver please read - Documentation/joystick.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 lightning.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called lightning.o. If you want to compile it as + a module, say M here and read . + +Crystal SoundFusion gameports +CONFIG_INPUT_CS461X + Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion" + PCI audio accelerator. A product page for the CS4614 is at + . + + 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 cs461x.o. If you want to compile it as a + module, say M here and read . Aureal Vortex and Trident 4DWave gameports CONFIG_INPUT_PCIGAME Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2 card. For more information on how to use the driver please read - Documentation/joystick.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 pcigame.o. If you want to compile it as a + module, say M here and read . + +SoundBlaster Live! gameports +CONFIG_INPUT_EMU10K1 + Say Y here if you have a SoundBlaster Live! card and want to use + its gameport. For more information on how to use the driver + please read . 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 pcigame.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called emu10k1-gp.o. If you want to compile it as + a module, say M here and read . Classic PC analog joysticks and gamepads CONFIG_INPUT_ANALOG Say Y here if you have a controller that connects to the PC - gameport. This supports many different types, including joysticks + 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, 6 and 8 button gamepads, or Saitek Cyborg - joysticks. For more information on how to use the driver please read - Documentation/joystick.txt + joysticks. For more information on how to use the driver please + read . 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 analog.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called analog.o. If you want to compile it as a + module, say M here and read . -Assasin 3D and MadCatz Panther devices +Assassin 3D and MadCatz Panther devices CONFIG_INPUT_A3D Say Y here if you have an FPGaming or MadCatz controller using the - A3D protocol over the PC gameport. For more information on how to - use the driver please read Documentation/joystick.txt + A3D protocol over the PC gameport. For more information on how to + use the driver please read . 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 a3d.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called a3d.o. If you want to compile it as a + module, say M here and read . Logitech ADI digital joysticks and gamepads CONFIG_INPUT_ADI Say Y here if you have a Logitech controller using the ADI protocol over the PC gameport. For more information on how to use - the driver please read Documentation/joystick.txt + the driver please read . 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 adi.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called adi.o. If you want to compile it as a + module, say M here and read . Creative Labs Blaster Cobra gamepad CONFIG_INPUT_COBRA Say Y here if you have a Creative Labs Blaster Cobra gamepad. For more information on how to use the driver please read - Documentation/joystick.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 cobra.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called cobra.o. If you want to compile it as a + module, say M here and read . Genius Flight2000 Digital joysticks and gamepads CONFIG_INPUT_GF2K - Say Y here if you have a Genius Flight2000 or MaxFighter - digitally communicating joystick or gamepad. For more information - on how to use the driver please read Documentation/joystick.txt + Say Y here if you have a Genius Flight2000 or MaxFighter digitally + communicating joystick or gamepad. For more information on how to + use the driver please read . 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 gf2k.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called gf2k.o. If you want to compile it as a + module, say M here and read . Gravis GrIP joysticks and gamepads CONFIG_INPUT_GRIP Say Y here if you have a Gravis controller using the GrIP protocol - over the PC gameport. For more information on how to use the driver - please read Documentation/joystick.txt + over the PC gameport. For more information on how to use the driver + please read . 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 grip.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called grip.o. If you want to compile it as a + module, say M here and read . InterAct digital joysticks and gamepads CONFIG_INPUT_INTERACT Say Y hereif you have an InterAct gameport or joystick - communicating digitally over the gameport. For more information on - how to use the driver please read Documentation/joystick.txt + communicating digitally over the gameport. For more information on + how to use the driver please read . 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 interact.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called interact.o. If you want to compile it as + a module, say M here and read . ThrustMaster DirectConnect joysticks and gamepads CONFIG_INPUT_TMDC Say Y here if you have a ThrustMaster controller using the - DirectConnect (BSP) protocol over the PC gameport. For more + DirectConnect (BSP) protocol over the PC gameport. For more information on how to use the driver please read - Documentation/joystick.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 tmdc.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called tmdc.o. If you want to compile it as a + module, say M here and read . Microsoft SideWinder digital joysticks and gamepads CONFIG_INPUT_SIDEWINDER Say Y here if you have a Microsoft controller using the Digital - Overdrive protocol over PC gameport. For more information on how to - use the driver please read Documentation/joystick.txt + Overdrive protocol over PC gameport. For more information on how to + use the driver please read . + + 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 sidewinder.o. If you want to compile it + as a module, say M here and read . + +Serial port device support +CONFIG_INPUT_SERIO + Say Y here and to the Serial port input line discipline option if + you plan to use a joystick that communicates over the serial (COM) + port. For more information on how to use the driver please read + . 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 sidewinder.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called sidewinder.o. If you want to compile it + as a module, say M here and read . Serial port input line discipline CONFIG_INPUT_SERPORT - Say Y hereif you plan to use a joystick that communicates over the - serial (COM) port. For more information on how to use the driver - please read Documentation/joystick.txt + Say Y here if you plan to use a joystick that communicates over the + serial (COM) port. For more information on how to use the driver + please read . 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 serport.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called serport.o. If you want to compile it as a + module, say M here and read . Logitech WingMan Warrior joystick CONFIG_INPUT_WARRIOR - Say Y here if you have a Logitech WingMan Warrior joystick - connected to your computer's serial port. For more information on - how to use the driver please read Documentation/joystick.txt + Say Y here if you have a Logitech WingMan Warrior joystick connected + to your computer's serial port. For more information on how to use + the driver please read . 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 warrior.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called warrior.o. If you want to compile it as a + module, say M here and read . LogiCad3d Magellan/SpaceMouse 6dof controller CONFIG_INPUT_MAGELLAN Say Y here if you have a Magellan or Space Mouse 6DOF controller connected to your computer's serial port. For more information on - how to use the driver please read Documentation/joystick.txt + how to use the driver please read . 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 magellan.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called magellan.o. If you want to compile it as + a module, say M here and read . SpaceTec SpaceOrb/Avenger 6dof controller CONFIG_INPUT_SPACEORB Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF controller connected to your computer's serial port. For more information on how to use the driver please read - Documentation/joystick.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 spaceorb.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. - + The module will be called spaceorb.o. If you want to compile it as + a module, say M here and read . + SpaceTec SpaceBall 4000 FLX 6dof controller CONFIG_INPUT_SPACEBALL Say Y here if you have a SpaceTec SpaceBall 4000 FLX controller - connected to your computer's serial port. For more information on - how to use the driver please read Documentation/joystick.txt + connected to your computer's serial port. For more information on + how to use the driver please read . + + 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 spaceball.o. If you want to compile it as + a module, say M here and read . + +Gravis Stinger gamepad +CONFIG_INPUT_STINGER + Say Y here if you have a Gravis Stinger connected to one of your + serial ports. For more information on how to use the driver please + read . + + 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 stinger.o. If you want to compile it as a + module, say M here and read . I-Force joysticks/wheels CONFIG_INPUT_IFORCE_232 Say Y here if you have an I-Force joystick or steering wheel - connected to your serial (COM) port. For more information on - how to use the driver please read Documentation/joystick.txt + connected to your serial (COM) port. For more information on how + to use the driver please read . 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 iforce.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called iforce.o. If you want to compile it as a + module, say M here and read . I-Force joysticks/wheels CONFIG_INPUT_IFORCE_USB Say Y here if you have an I-Force joystick or steering wheel - connected to your USB port. For more information on how to use the - driver please read Documentation/joystick.txt + connected to your USB port. For more information on how to use the + driver please read . 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 iforce.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. - + The module will be called iforce.o. If you want to compile it as a + module, say M here and read . + Multisystem, Sega Genesis, Saturn joysticks and gamepads CONFIG_INPUT_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 connected to your parallel port. - For more information on how to use the driver please read - Documentation/joystick.txt and Documentation/joystick-parport.txt. + Commodore, Amstrad CPC joystick connected to your parallel port. + For more information on how to use the driver please read + and + . 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 db9.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called db9.o. If you want to compile it as a + module, say M here and read . Multisystem, NES, SNES, N64, PSX joysticks and gamepads CONFIG_INPUT_GAMECON @@ -15420,47 +17709,48 @@ Sony PlayStation gamepad or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC joystick connected to your parallel port. For more information on how to use the driver please read - Documentation/joystick.txt and Documentation/joystick-parport.txt + and + . 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 gamecon.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called gamecon.o. If you want to compile it as a + module, say M here and read . Multisystem joysticks via TurboGraFX device CONFIG_INPUT_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 + Say Y here if you have the TurboGraFX interface by Steffen Schwenke, + and want to use it with Multisystem -- Atari, Amiga, Commodore, + Amstrad CPC joystick. For more information on how to use the driver + please read and + . 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 turbografx.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called turbografx.o. If you want to compile it + as a module, say M here and read . Amiga joysticks CONFIG_INPUT_AMIJOY 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 + to it. For more information on how to use the driver please read + . 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 joy-amiga.o. If you want to compile - it as a module, say M here and read Documentation/modules.txt. + The module will be called joy-amiga.o. If you want to compile it as + a module, say M here and read . -Atomwide Serial Support +Atomwide serial port 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 + this option. The driver can handle 1, 2, or 3 port cards. + If unsure, say N. -The Serial Port Dual Serial Port +Dual serial port support 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 + say Y to this option. If unsure, say N. NetWinder Button CONFIG_NWBUTTON @@ -15481,7 +17771,8 @@ 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. + . 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. @@ -15499,37 +17790,37 @@ 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 + 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. + interrupt and DMA channel), because you will be asked for it. You want to read the Sound-HOWTO, available from - http://www.linuxdoc.org/docs.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. + . General information about + the modular sound system is contained in the files + . The file + 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 + ), 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. + and load that module after the PnP configuration is finished. To do + this, say M here and read as well + as ; 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/ . + package, available at . 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 + 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. @@ -15546,7 +17837,7 @@ 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. + Say Y unless you have 16MB or more RAM or a PCI sound card. Support for Aztech Sound Galaxy (non-PnP) cards CONFIG_SOUND_SGALAXY @@ -15558,9 +17849,9 @@ "sgalaxy=,,,," to the kernel command line. -Support for AD1816(A) based cards (EXPERIMENTAL) +Support for AD1816(A) based cards CONFIG_SOUND_AD1816 - Say M here if you have a sound card based on the Analog Devices + Say M here if you have a sound card based on the Analog Devices AD1816(A) chip. If you compile the driver into the kernel, you have to add @@ -15569,8 +17860,8 @@ 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. + usually built into motherboards. Read + for details. If you compile the driver into the kernel, you have to add "opl3sa=,,,,," to the kernel @@ -15581,7 +17872,7 @@ Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio 16 or Logitech SoundMan 16 sound card. Answer N if you have some other card made by Media Vision or Logitech since those are not - PAS16 compatible. Please read Documentation/sound/PAS16. + PAS16 compatible. Please read . It is not necessary to add Sound Blaster support separately; it is included in PAS support. @@ -15589,6 +17880,11 @@ "pas2=,,,,,,, to the kernel command line. +Enable PAS16 joystick port +CONFIG_PAS_JOYSTICK + Say Y here to enable the Pro Audio Spectrum 16's auxiliary joystick + port. + 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 @@ -15596,48 +17892,43 @@ 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. + Please read the file . You should also say Y here for cards based on the Avance Logic - ALS-007 and ALS-1X0 chips (read Documentation/sound/ALS) 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 "AWE32 synth" below and read - Documentation/sound/INSTALL.awe. If you have an IBM Mwave card, say - Y here and read Documentation/sound/mwave. + ALS-007 and ALS-1X0 chips (read ) and + for cards based on ESS chips (read + and + ). If you have an SB AWE 32 or SB AWE + 64, say Y here and also to "AWE32 synth" below and read + . If you have an IBM Mwave + card, say Y here and read . If you compile the driver into the kernel and don't want to use isapnp, you have to add "sb=,,," to the kernel command line. - + You can say M here to compile this driver as a module; the module is called sb.o. -#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. + Say Y here for any type of Gravis Ultrasound card, including the GUS + or GUS MAX. See also for more + information on configuring this card with modules. If you compile the driver into the kernel, you have to add "gus=,,," to the kernel command line. 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 + 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. + instructions in the file. It + is safe to answer Y if you have a true MPU401 MIDI interface card. If you compile the driver into the kernel, you have to add "mpu401=," to the kernel command line. @@ -15657,7 +17948,7 @@ 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. + . If you compile the driver into the kernel, you have to add "pss=,,,,," to the kernel @@ -15672,7 +17963,7 @@ 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. + see the file . Have DSPxxx.LD firmware file CONFIG_PSS_HAVE_BOOT @@ -15687,10 +17978,10 @@ 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: + 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), @@ -15707,9 +17998,9 @@ 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. + specific instructions in . + Some drivers have their own MSS support and saying Y to this option + will cause a conflict. If you compile the driver into the kernel, you have to add "ad1848=,,,[,]" to the kernel command @@ -15717,11 +18008,12 @@ 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/vwsnd - for more info on this driver's capabilities. + Say Y or M if you have an SGI Visual Workstation and you want to be + able to use its on-board audio. Read + for more info on this driver's + capabilities. -Ensoniq Soundscape support +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 @@ -15751,27 +18043,28 @@ 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. These chips are + 82C928 or 82C929 or 82C931) audio interface chip. These chips are 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. + M to "Full support for Turtle Beach WaveFront", below. If you compile the driver into the kernel, you have to add "mad16=,,,,," to the kernel command line. - See also Documentation/sound/Opti and Documentation/sound/MAD16 for - more information on setting these cards up as modules. + See also and + for more information on setting + these cards up as modules. -Full support for Turtle Beach WaveFront synth/sound cards +Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) 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+. - + and read the files and + . + 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 @@ -15787,15 +18080,15 @@ "cs4232=,,,,," to the kernel command line. - See Documentation/sound/CS4232 for more information on configuring - this card. + See for more information on + configuring this card. Support for Yamaha OPL3-SA2 and SA3 based PnP cards CONFIG_SOUND_OPL3SA2 - Say Y or M if you have a card based on one of these Yamaha - sound chipsets or the "SAx", which is actually a SA3. Read - Documentation/sound/OPL3-SA2 for more information on configuring - these cards. + Say Y or M if you have a card based on one of these Yamaha sound + chipsets or the "SAx", which is actually a SA3. Read + for more information on + configuring these cards. If you compile the driver into the kernel and do not also configure in the optional ISA PnP support, you will have to add @@ -15824,52 +18117,118 @@ 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). + Monterey (not for the Pinnacle or Fiji). - See Documentation/sound/MultiSound for important information about - this driver. + See for important information + about this driver. Note that it has been discontinued, but the + Voyetra Turtle Beach knowledge base entry for it is still available + at . + +MSND Classic I/O +CONFIG_MSNDCLAS_IO + I/O port address for the MultiSound Classic and related cards. + +MSND Classic IRQ +CONFIG_MSNDCLAS_IRQ + Interrupt Request line for the MultiSound Classic and related cards. + +MSND Classic memory address +CONFIG_MSNDCLAS_MEM + Memory-mapped I/O base address for the MultiSound Classic and + related cards. 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. + obtained from Turtle Beach. See + 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. + obtained from Turtle Beach. See + 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. + See for important information + about this driver. Note that it has been discontinued, but the + Voyetra Turtle Beach knowledge base entry for it is still available + at . + +MSND Pinnacle IDE I/O 0 +CONFIG_MSNDPIN_IDE_IO0 + CD-ROM drive 0 memory-mapped I/O base address for the MultiSound + Pinnacle and Fiji sound cards. + +MSND Pinnacle IDE I/O 1 +CONFIG_MSNDPIN_IDE_IO1 + CD-ROM drive 1 memory-mapped I/O base address for the MultiSound + Pinnacle and Fiji sound cards. + +MSND Pinnacle IDE IRQ +CONFIG_MSNDPIN_IDE_IRQ + Interrupt request number for the IDE CD-ROM interface on the + MultiSound Pinnacle and Fiji sound cards. + +MSND Pinnacle I/O +CONFIG_MSNDPIN_IO + Memory-mapped I/O base address for the primary synthesizer on + MultiSound Pinnacle and Fiji sound cards. + +MSND Pinnacle MPU I/O +CONFIG_MSNDPIN_MPU_IO + Memory-mapped I/O base address for the Kurzweil daughterboard + synthesizer on MultiSound Pinnacle and Fiji sound cards. + +MSND Pinnacle MPU IRQ +CONFIG_MSNDPIN_MPU_IRQ + Iinterrupt request number for the Kurzweil daughterboard + synthesizer on MultiSound Pinnacle and Fiji sound cards. + +MSND Pinnacle IRQ +CONFIG_MSNDPIN_IRQ + Interrupt request line for the primary synthesizer on MultiSound + Pinnacle and Fiji sound cards. + +MSND Pinnacle joystick I/O +CONFIG_MSNDPIN_JOYSTICK_IO + Memory-mapped I/O base address for the joystick port on MultiSound + Pinnacle and Fiji sound cards. + +MSND Pinnacle memory +CONFIG_MSNDPIN_MEM + Memory-mapped I/O base address for the primary synthesizer on + MultiSound Pinnacle and Fiji sound cards. 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. + 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 + 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. + obtained from Turtle Beach. See + for information on how to + obtain this. -MSND Pinnacle have S/PDIF I/O +MSND Pinnacle has 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. + for information on how to make + use of this capability. MSND Pinnacle non-PnP Mode CONFIG_MSNDPIN_NONPNP @@ -15896,15 +18255,14 @@ and Pinnacle). Larger values reduce the chance of data overruns at the expense of overall latency. If unsure, use the default. -FM synthesizer (YM3812/OPL-3) support +Yamaha FM synthesizer (YM3812/OPL-3) support CONFIG_SOUND_YM3812 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. + cards, however). Please read the file + if your card has an OPL3 chip. If you compile the driver into the kernel, you have to add "opl3=" to the kernel command line. @@ -15914,27 +18272,27 @@ ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio) CONFIG_SOUND_ACI_MIXER ACI (Audio Command Interface) is a protocol used to communicate with - the microcontroller on some sound cards produced by miro and Cardinal - Technologies. The main function of the ACI is to control the mixer - and to get a product identification. + the microcontroller on some sound cards produced by miro and + Cardinal Technologies. The main function of the ACI is to control + the mixer and to get a product identification. - This Voxware ACI driver currently supports the ACI functions on the + This VoxWare ACI driver currently supports the ACI functions on the miroSOUND PCM1-pro, PCM12 and PCM20 radio. On the PCM20 radio, ACI also controls the radio tuner. This is supported in the video4linux - miropcm20 driver (say M or Y here and go back to "Multimedia devices" - -> "Radio Adapters"). + miropcm20 driver (say M or Y here and go back to "Multimedia + devices" -> "Radio Adapters"). This driver is also available as a module and will be called aci.o. SB32/AWE support CONFIG_SOUND_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://www.linuxdoc.org/docs.html#howto for more - info. + similar sound card. See , + and the Soundblaster-AWE + mini-HOWTO, available from + for more info. -Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600) +Gallant Audio Cards (SC-6000 and SC-6600 based) CONFIG_SOUND_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 @@ -15948,10 +18306,10 @@ 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. + Read the file and the head of + as well as + to get more information + about this driver and its configuration. Audio Excel DSP 16 (SBPro emulation) CONFIG_AEDSP16_SBPRO @@ -15981,17 +18339,22 @@ 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 CDROM interface of the Audio Excel +SC-6600 CD-ROM Interface +CONFIG_SC6600_CDROM (4=None, 3=IDE, 1=Panasonic, 0=Sony) + This is used to activate the CD-ROM interface of the Audio Excel DSP 16 card. Enter: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for no - CDROM present. + CD-ROM present. + +SC-6600 CD-ROM Interface I/O Address +CONFIG_SC6600_CDROMBASE + Base I/O port address for the CD-ROM interface of the Audio Excel + DSP 16 card. 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 @@ -16000,46 +18363,70 @@ C-Media PCI (CMI8338/8378) CONFIG_SOUND_CMPCI Say Y or M if you have a PCI sound card using the CMI8338 - or the CMI8378 chip.set. + or the CMI8378 chipset. Data on these chips are available at + . + +Support CMI8738 based audio cards +CONFIG_SOUND_CMPCI_CM8738 + Say Y or M if you have a PCI sound card using the CMI8338 + or the CMI8378 chipset. Data on this chip is available at + . + +Enable joystick +CONFIG_SOUND_CMPCI_JOYSTICK + Say here in order to enable the joystick port on a sound crd using + the CMI8338 or the CMI8738 chipset. Data on these chips are + available at . + +Number of speakers (2, 4, 5, 6) +CONFIG_SOUND_CMPCI_SPEAKERS + Specify the number of speaker channels you want the card to drive, + as an integer. + +Enable S/PDIF loop for CMI8738 +CONFIG_SOUND_CMPCI_SPDIFLOOP + Enable loopback from SPDIF in to SPDIF out. For discussion, see + "The 8738 Audio SPDIF In/Out Technical Data" on the technical + support page at . -Creative EMU10K1 based PCI sound cards +Creative SBLive! (EMU10K1) based PCI sound cards CONFIG_SOUND_EMU10K1 Say Y or M if you have a PCI sound card using the EMU10K1 chipset, - such as the various Creative SBLive!, SB PCI512 or Emu-APS. + such as the Creative SBLive!, SB PCI512 or Emu-APS. For more information on this driver and the degree of support for the different card models please check . It is now possible to load dsp microcode patches into the EMU10K1 - chip. These patches are used to implement real time sound processing - effects which include for example: signal routing, bass/treble - control, AC3 passthrough, ... + chip. These patches are used to implement real time sound + processing effects which include for example: signal routing, + bass/treble control, AC3 passthrough, ... Userspace tools to create new patches and load/unload them can be found at . - + Creative EMU10K1 MIDI CONFIG_MIDI_EMU10K1 - Say Y if you want to be able to use the OSS /dev/sequencer interface. - This code is still experimental. + Say Y if you want to be able to use the OSS /dev/sequencer + interface. This code is still experimental. Crystal SoundFusion (CS4280/461x) CONFIG_SOUND_FUSION - This module drives the Crystal SoundFusion devices (CS4280/46xx series) - when wired as native sound drivers with AC97 codecs. If this driver - does not work try the CS4232 driver. + This module drives the Crystal SoundFusion devices (CS4280/46xx + series) when wired as native sound drivers with AC97 codecs. If + this driver does not work try the CS4232 driver. -Ensoniq ES1370 based PCI sound cards +Ensoniq AudioPCI (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 + 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 +Ensoniq AudioPCI 97 (ES1371) based 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 @@ -16047,25 +18434,26 @@ 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. + slightly from OSS/Free, so PLEASE READ + . 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 + 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 + lspci -n and look for the PCI ID 5333:CA00. This driver differs slightly from OSS/Free, so PLEASE READ - Documentation/sound/sonicvibes. + . Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core CONFIG_SOUND_TRIDENT @@ -16082,26 +18470,29 @@ 10B9:5451 stands for ALi5451. This driver supports S/PDIF in/out (record/playback) for ALi 5451 - embedded in ALi M1535+ and M1535D+. Note that they aren't all + embedded in ALi M1535+ and M1535D+. Note that they aren't all enabled by default; you can enable them by saying Y to "/proc file - system support" and "Sysctl support", and after the /proc file + system support" and "Sysctl support", and after the /proc file system has been mounted, executing the command command what is enabled - + echo 0>/proc/ALi5451 pcm out is also set to S/PDIF out. (Default). - + echo 1>/proc/ALi5451 use S/PDIF out to output pcm data. - - echo 2>/proc/ALi5451 use S/PDIF out to output non-pcm data.(AC3...). - echo 3>/proc/ALi5451 record from Ac97 in(MIC, Line in...). (Default). - - echo 4>/proc/ALi5451 no matter Ac97 settings, record from S/PDIF in. - - + echo 2>/proc/ALi5451 use S/PDIF out to output non-pcm data. + (AC3...). + + echo 3>/proc/ALi5451 record from Ac97 in(MIC, Line in...). + (Default). + + echo 4>/proc/ALi5451 no matter Ac97 settings, record from S/PDIF + in. + + This driver differs slightly from OSS/Free, so PLEASE READ the - comments at the top of driver/sound/trident.c + comments at the top of . Rockwell WaveArtist CONFIG_SOUND_WAVEARTIST @@ -16119,10 +18510,10 @@ VIA 82C686 MIDI CONFIG_MIDI_VIA82CXXX - Answer Y to use the MIDI interface of the Via686. You may need to - enable this in the BIOS before it will work. This is for connection - to external MIDI hardware, and is not required for software playback - of MIDI files. + Answer Y to use the MIDI interface of the Via686. You may need to + enable this in the BIOS before it will work. This is for connection + to external MIDI hardware, and is not required for software playback + of MIDI files. NeoMagic 256AV/256ZX sound chipsets CONFIG_SOUND_NM256 @@ -16132,13 +18523,76 @@ laptops. It includes support for an AC97-compatible mixer and an apparently proprietary sound engine. - See Documentation/sound/NM256 for further information. + See for further information. -ESS Maestro sound chipsets +ESS Maestro, Maestro2, Maestro2E driver CONFIG_SOUND_MAESTRO Say Y or M if you have a sound system driven by ESS's Maestro line of PCI sound chips. These include the Maestro 1, Maestro 2, and - Maestro 2E. See Documentation/sound/Maestro for more details. + Maestro 2E. See for more + details. + +ESS Maestro3/Allegro driver +CONFIG_SOUND_MAESTRO3 + Say Y or M if you have a sound system driven by ESS's Maestro 3 + PCI sound chip. + +Adlib Cards +CONFIG_SOUND_ADLIB + Includes ASB 64 4D. Information on programming AdLib cards is + available at . + +Crystal Sound CS4281 +CONFIG_SOUND_CS4281 + Picture and feature list at + . + +16 bit sampling option of GUS (_NOT_ GUS MAX) +CONFIG_SOUND_GUS16 + Support for Gravis Ulstrasound (GUS) cards (other than the GUS), + sampling at 16-bit width. + +GUS MAX support +CONFIG_SOUND_GUSMAX + Support for Gravis Ulstrasound MAX. + +Intel ICH audio support +CONFIG_SOUND_ICH + Support for integral audio in Intel's I/O Controller Hub (ICH) + chipset, as used on the 810/820/840 motherboards. + +Verbose initialization +CONFIG_SOUND_TRACEINIT + Verbose soundcard initialization -- affects the format of autoprobe + and initialization messages at boot time. + +TV card (bt848) mixer support +CONFIG_SOUND_TVMIXER + Support for audio mixer facilities on the BT848 TV frame-grabber + card. + +VIDC 16-bit sound +CONFIG_SOUND_VIDC + 16-bit support for the VIDC onboard sound hardware found on Acorn + machines. + +Loopback MIDI device support +CONFIG_SOUND_VMIDI + Support for MIDI loopback on port 1 or 2. + +Yamaha YMF7xx PCI audio (native mode) +CONFIG_SOUND_YMFPCI + Support for Yamaha cards including the YMF711, YMF715, YMF718, + YMF719, YMF724, Waveforce 192XG, and Waveforce 192 Digital. + +Yamaha PCI legacy ports support +CONFIG_SOUND_YMFPCI_LEGACY + Support for YMF7xx PCI cards emulating an MP401. + +RME Hammerfall (RME96XX) support +CONFIG_SOUND_RME96XX + Say Y or M if you have a Hammerfall, Hammerfall light or Hammerfall + DSP card from RME. Are you using a crosscompiler CONFIG_CROSSCOMPILE @@ -16157,6 +18611,73 @@ only useful for people working on the floating point exception handler. If you don't, say N. +Galileo EV64120 Evaluation board +CONFIG_MIPS_EV64120 + This is an evaluation board based on the Galileo GT-64120 + single-chip system controller that contains a MIPS R5000 compatible + core running at 75/100MHz. Their website is located at + . Say Y here if you wish to build a + kernel for this platform. + +Galileo EV96100 Evaluation board +CONFIG_MIPS_EV96100 + This is an evaluation board based on the Galielo GT-96100 LAN/WAN + communications controllers containing a MIPS R5000 compatible core + running at 83MHz. Their website is . Say Y + here if you wish to build a kernel for this platform. + +Support for ITE 8172G board +CONFIG_MIPS_ITE8172 + Ths is an evaluation board made by ITE (http://www.ite.com.tw/) + with ATX form factor that utilizes a MIPS R5000 to work with its + ITE8172G companion internet appliance chip. The MIPS core can be + either a NEC Vr5432 or QED RM5231. Say Y here if you wish to build + a kernel for this platform. + +Support for Globespan IVR board +CONFIG_MIPS_IVR + This is an evaluation board built by Globespan to showcase thir + iVR (Internet Video Recorder) design. It utilizes a QED RM5231 + R5000 MIPS core. More information can be found out their website + located at P. Say Y + here if you wish to build a kernel for this platform. + +Support for Alchemy Semi PB1000 board +CONFIG_MIPS_PB1000 + This is an evaluation board built by Alchemy Semiconducttor to + showcase their Au1000 Internet Edge Processor. It is SOC design + containing a MIPS32 core running at 266/400/500MHz with many + integrated peripherals. Further information can be found at their + website, . Say Y here if you wish to + build a kernel for this platform. + +Support for Philips Nino +CONFIG_NINO + Say Y here to select a kernel for the Philips Nino Palm PC. The + website at + will have more information. + +Model-500/510 +CONFIG_NINO_16MB + Say Y here to build a kernel specifically for Nino 500/501 color + Palm PCs from Philips (INCOMPLETE). + +Model-200/210/312/320/325/350/390 +CONFIG_NINO_8MB + Say Y here to build a kernel specifically for Nino Palm PCs with + 8MB of memory. These include models 200/210/312/320/325/350/390. + +Model-300/301/302/319 +CONFIG_NINO_4MB + Say Y here to build a kernel specifically for Nino Palm PCs with + 4MB of memory. These include models 300/301/302/319. + +Low-level debugging +CONFIG_LL_DEBUG + Enable low-level debugging assertion macros in the kernel code. + Currently used only by the time services code in the MIPS port. + Don't turn this on unless you know what you are doing. + Remote GDB kernel debugging CONFIG_REMOTE_DEBUG If you say Y here, it will be possible to remotely debug the MIPS @@ -16182,34 +18703,34 @@ by pressing various keys while holding SysRq (Alt+PrintScreen). It also works on a serial console (on PC hardware at least), if you send a BREAK and then within 5 seconds a command keypress. The - keys are documented in Documentation/sysrq.txt. Don't say Y unless - you really know what this hack does. + keys are documented in . Don't say Y + unless you really know what this hack does. -ISDN subsystem +ISDN support 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 + 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 + 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. + provider purchased an ISDN line from the phone company. For + details, read 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, + 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. + 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 + 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. + want), say M here and read . The + module will be called isdn.o. If unsure, say N. Support synchronous PPP CONFIG_ISDN_PPP @@ -16220,20 +18741,21 @@ 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. + feature. See and + 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. + 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 BSD compression CONFIG_ISDN_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 @@ -16251,19 +18773,19 @@ 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. + 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 + This feature provides the X.25 protocol over ISDN connections. + See 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. + line. Supported options are CD (call deflection), CFU (Call forward unconditional), CFB (Call forward when busy) and CFNR (call forward @@ -16274,22 +18796,23 @@ 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. + Please read the file . 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 + 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. + separately. See and + 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. + say M here and read . The module + will be called icn.o. isdnloop support CONFIG_ISDN_DRV_LOOP @@ -16304,19 +18827,19 @@ 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). + 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. + say M here and read . The module + will be called hisax.o. See + for more information on using this driver. HiSax Support for EURO/DSS1 CONFIG_HISAX_EURO @@ -16324,9 +18847,9 @@ telephone service company provides. The call control protocol E-DSS1 is used in most European countries. - If unsure, say yes. + If unsure, say Y. -Support for german charge info +Support for German chargeinfo CONFIG_DE_AOC If you want that the HiSax hardware driver sends messages to the upper level of the isdn code on each AOCD (Advice Of Charge, During @@ -16361,230 +18884,265 @@ HiSax Support for US NI1 CONFIG_HISAX_NI1 - Enable this if you like to use ISDN in US on a NI1 basic rate interface. + Enable this if you like to use ISDN in US on a NI1 basic rate + interface. 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. + 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. + See on how to configure it + using the different cards, a different D-channel protocol, or + non-standard IRQ/port/shmem settings. 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. + + See on how to configure it + using the different cards, a different D-channel protocol, or + non-standard IRQ/port settings. Teles PCI CONFIG_HISAX_TELESPCI This enables HiSax support for the Teles PCI. - See Documentation/isdn/README.HiSax on how to configure it. - + See on how to configure it. + 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. + S0BOX. See on how to + configure it. 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. -AVM PnP/PCI (Fritz!PNP/PCI) + See on how to configure it + using the different cards, a different D-channel protocol, or + non-standard IRQ/port settings. + +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. + See on how to configure it. 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. + See on how to configure it. 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. + See on how to configure it + using the different cards, a different D-channel protocol, or + non-standard IRQ/port settings. 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. + See on how to configure it + using the different cards, a different D-channel protocol, or + non-standard IRQ/port settings. 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. + See on how to configure it + using the different cards, a different D-channel protocol, or + non-standard IRQ/port settings. ASUSCOM ISA cards CONFIG_HISAX_ASUSCOM This enables HiSax support for the AsusCom and their OEM versions passive ISDN ISA 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. + See on how to configure it + using the different cards, a different D-channel protocol, or + non-standard IRQ/port settings. 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. + See on how to configure it + using the different cards, a different D-channel protocol, or + non-standard IRQ/port settings. 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. + + See on how to configure it + using the different cards, a different D-channel protocol, or + non-standard IRQ/port settings. 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. + See on how to configure it + using the different cards, a different D-channel protocol, or + non-standard IRQ/port settings. 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. + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. MIC card CONFIG_HISAX_MIC - This enables HiSax support for the ITH MIC card. + 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. + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. 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. + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. NETspider U card CONFIG_HISAX_NETJET_U - This enables HiSax support for the Netspider U interface ISDN card 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. + This enables HiSax support for the Netspider U interface ISDN card + from Traverse Technologies. + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. Niccy PnP/PCI card CONFIG_HISAX_NICCY - This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI. + 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. + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. 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. + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. 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. + + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. 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. + + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. 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. + + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. 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. + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. 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. + + For more informations see under + . 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. -HFC-S+, HFC-SP, HFC-PCMCIA cards (EXPERIMENTAL) + See on how to configure it + using a different D-channel protocol, or non-standard IRQ/port + settings. + +HFC-S+, HFC-SP, HFC-PCMCIA cards CONFIG_HISAX_HFC_SX This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA cards. This code is not finished yet. -Am7930 (EXPERIMENTAL) +Am7930 CONFIG_HISAX_AMD7930 This enables HiSax support for the AMD7930 chips on some SPARCs. This code is not finished yet. +HiSax debugging +CONFIG_HISAX_DEBUG + This enables debugging code in the new-style HiSax drivers, i.e. + the ST5481 USB driver currently. + If in doubt, say yes. + +ELSA PCMCIA MicroLink cards +CONFIG_HISAX_ELSA_CS + This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink + card. + +Sedlbauer PCMCIA cards +CONFIG_HISAX_SEDLBAUER_CS + This enables the PCMCIA client driver for the Sedlbauer Speed Star + and Speed Star II cards. + +ST5481 USB ISDN adapter +CONFIG_HISAX_ST5481 + This enables the driver for ST5481 based USB ISDN adapters, + e.g. the BeWan Gazel 128 USB + 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. + 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 + and + 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. + say M here and read . The module + will be called pcbit.o. -Spellcaster support (EXPERIMENTAL) +Spellcaster support CONFIG_ISDN_DRV_SC - This enables support for the Spellcaster BRI ISDN boards. This + 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. + want, details in ); the module will + be called sc.o. See and + for more information. Eicon active card support CONFIG_ISDN_DRV_EICON @@ -16592,23 +19150,29 @@ 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 Diva Server card support + for more information. + +Legacy Eicon driver +CONFIG_ISDN_DRV_EICON_OLD + Say Y here to use your Eicon active ISDN card with ISDN4Linux + isdn module. + +Eicon PCI DIVA Server BRI/PRI/4BRI support CONFIG_ISDN_DRV_EICON_PCI - Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN card. - Please read Documentation/isdn/README.eicon for more information. - -Eicon old-type card support + Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN + card. Please read for more + information. + +Eicon old-type (S,SX,SCOM,Quadro,S2M) 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. + for more information. Eicon driver type standalone -CONFIG_ISDN_DRV_EICON_STANDALONE +CONFIG_ISDN_DRV_EICON_DIVAS Enable this option if you want the eicon driver as standalone version with no interface to the ISDN4Linux isdn module. If you say Y here, the eicon module only supports the Diva Server PCI @@ -16621,20 +19185,49 @@ Fax Class 1 and 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. + also. See for more information. CAPI2.0 support CONFIG_ISDN_CAPI This provides the CAPI (Common ISDN Application Programming Interface, a standard making it easy for programs to access ISDN - hardware, see http://www.capi.org/ . This is needed for AVM's set of - active ISDN controllers like B1, T1, M1. + hardware, see . This is needed for AVM's set + of active ISDN controllers like B1, T1, M1. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The modules will be called capi.o and kernelcapi.o. If you want to compile it as a module, say M here and read - Documentation/modules.txt. + . + +CAPI2.0 /dev/capi20 support +CONFIG_ISDN_CAPI_CAPI20 + This option will provide the CAPI 2.0 interface to userspace + applications via /dev/capi20. Applications should use the + standardized libcapi20 to access this functionality. You should say + Y/M here. + +CAPI2.0 Middleware support +CONFIG_ISDN_CAPI_MIDDLEWARE + This option will enhance the capabilities of the /dev/capi20 + interface. It will provide a means of moving a data connection, + established via the usual /dev/capi20 interface to a special tty + device. If you want to use pppd with pppdcapiplugin to dial up to + your ISP, say Y here. + +CAPI2.0 filesystem support +CONFIG_ISDN_CAPI_CAPIFS + This option provides a special file system, similar to /dev/pts with + device nodes for the special ttys established by using the + middleware extension above. If you want to use pppd with + pppdcapiplugin to dial up to your ISP, say Y here. + +CAPI2.0 capidrv interface support +CONFIG_ISDN_CAPI_CAPIDRV + This option provides the glue code to hook up CAPI driven cards to + the legacy isdn4linux link layer. If you have a card which is + supported by a CAPI driver, but still want to use old features like + ippp interfaces or ttyI emulation, say Y/M here. AVM B1 ISA support CONFIG_ISDN_DRV_AVMB1_B1ISA @@ -16657,6 +19250,11 @@ CONFIG_ISDN_DRV_AVMB1_B1PCMCIA Enable support for the PCMCIA version of the AVM B1 card. +AVM B1/M1/M2 PCMCIA cs module +CONFIG_ISDN_DRV_AVMB1_AVM_CS + Enable the PCMCIA client driver for the AVM B1/M1/M2 + PCMCIA cards. + AVM T1/T1-B PCI support CONFIG_ISDN_DRV_AVMB1_T1PCI Enable support for the AVM T1 T1B card. @@ -16673,40 +19271,40 @@ disconnecting. This will increase the size of the kernel by 7 KB. If unsure, say Y. -IBM Active 2000 support (EXPERIMENTAL) +IBM Active 2000 support 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. + for more information. Auvertech TurboPAM support CONFIG_ISDN_DRV_TPAM This enables support for the Auvertech TurboPAM ISDN-card. For running this card, additional firmware is necessary, which has to be downloaded into the card using a utility which is distributed - separately from the Auvertech's web site: http://www.auvertech.fr. + separately from the Auvertech's web site: . Please redirect all support questions to support@auvertech.fr. 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 tpam.o. + say M here and read . The module + will be called tpam.o. Hypercope HYSDN cards (Champ, Ergo, Metro) support (module) CONFIG_HYSDN Say Y here if you have one of Hypercope's active PCI ISDN cards Champ, Ergo and Metro. You will then get a module called hysdn.o. - Please read the file Documentation/isdn/README.hysdn for more + Please read the file for more information. HYSDN CAPI 2.0 support CONFIG_HYSDN_CAPI - Say Y here if you like to use Hypercope's CAPI 2.0 interface + Say Y here if you like to use Hypercope's CAPI 2.0 interface. -Support for Sun4 architecture +Support for SUN4 machines (disables SUN4[CDM] support) 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. @@ -16720,7 +19318,7 @@ This support is also available as a module called esp.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. + here and read . PTI Qlogic, ISP Driver CONFIG_SCSI_QLOGICPTI @@ -16732,17 +19330,22 @@ This support is also available as a module called qlogicpti.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. + here and read . -SPARC /dev/openprom compatibility driver (EXPERIMENTAL) +Sun PROM console +CONFIG_PROM_CONSOLE + Say Y to build a console driver for Sun machines that uses the + terminal emulation built into their console PROMS. + +/dev/openprom device support 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. + 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. + say M and read . If unsure, say Y. Openprom tree appears in /proc/openprom CONFIG_SUN_OPENPROMFS @@ -16752,8 +19355,9 @@ If you want to compile the /proc/openprom 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 openpromfs.o. If unsure, say M. + whenever you want), say M here and read + . + The module will be called openpromfs.o. If unsure, say M. Kernel support for Linux/Sparc 32bit binary compatibility CONFIG_SPARC32_COMPAT @@ -16773,11 +19377,11 @@ SunOS binary emulation CONFIG_SUNOS_EMUL - This allows you to run most SunOS binaries. If you want to do this, + This allows you to run most SunOS binaries. If you want to do this, say Y here and place appropriate files in /usr/gnemul/sunos. See - http://www.ultralinux.org/faq.html for more information. If you want - to run SunOS binaries on an Ultra you must also say Y to "Kernel - support for 32-bit a.out binaries" above. + for more information. If you + want to run SunOS binaries on an Ultra you must also say Y to + "Kernel support for 32-bit a.out binaries" above. Mostek real time clock support CONFIG_SUN_MOSTEK_RTC @@ -16802,17 +19406,37 @@ This driver supports the serial ports on newer (PCI) Ultra systems. Say Y if you want to be able to use your serial ports. -Aurora Multiboard 1600se (EXPERIMENTAL) +Videopix Frame Grabber +CONFIG_SUN_VIDEOPIX + Say Y here to support the Videopix Frame Grabber from Sun + Microsystems, commonly found on SPARCstations. This card, which is + based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and + SVIDEO signals. + +Sun bidirectional parallel port support +CONFIG_SUN_BPP + Say Y here to support Sun's obsolete variant of IEEE1284 + bidirectional parallel port protocol as /dev/bppX. Can be built on + x86 machines. + +Aurora Multiboard 1600se CONFIG_SUN_AURORA The Aurora Multiboard is a multi-port high-speed serial controller. If you have one of these, say Y. -Audio support (EXPERIMENTAL) +Tadpole TS102 Microcontroller support +CONFIG_TADPOLE_TS102_UCTRL + Say Y here to directly support the TS102 Microcontroller interface + on the Tadpole Sparcbook 3. This device handles power-management + events, and can also notice the attachment/detachment of external + monitors and mice. + +Audio support CONFIG_SPARCAUDIO This driver provides support for the build-in sound devices on most Sun machines. If you want to be able to use this, select this option and one or more of the lowlevel drivers below. See - http://www.dementia.org/~shadow/sparcaudio.html for more + for more information. AMD7930 Lowlevel Driver @@ -16830,18 +19454,83 @@ This driver supports the DBRI audio interface found on the SS10, SS20, Sparcbook 3, and Voyager systems. -Dummy lowlevel Driver +Dummy Lowlevel Driver CONFIG_SPARCAUDIO_DUMMY This is a pseudo-driver used for debugging and testing the sparcaudio subsystem. Say N unless you want to work on this subsystem. -Sparc hardware (EXPERIMENTAL) +Sparc hardware CONFIG_PARPORT_SUNBPP This driver provides support for the bidirectional parallel port found on many Sun machines. Note that many of the newer Ultras actually have pc style hardware instead. +/proc/hardware support +CONFIG_PROC_HARDWARE + Say Y here to support the /proc/hardware file, which gives you + access to information about the machine you're running on, + including the model, CPU, MMU, clock speed, BogoMIPS rating, + and memory size. + +Bluetooth subsystem support +CONFIG_BLUEZ + Bluetooth is low-cost, low-power, short-range wireless technology. + It was designed as a replacement for cables and other short-range + technologies like IrDA. Bluetooth operates in personal area range + that typically extends up to 10 meters. More information about + Bluetooth can be found at . + + Linux Bluetooth subsystem consist of several layers: + HCI Core (device and connection manager, scheduler) + HCI Device drivers (interface to the hardware) + L2CAP Module (L2CAP protocol) + + Say Y here to enable Linux Bluetooth support and to build HCI Core + layer. + + To use Linux Bluetooth subsystem, you will need several user-space + utilities like hciconfig and hcid. These utilities and updates to + Bluetooth kernel modules are provided in the BlueZ package. + For more information, see . + + If you want to compile HCI Core as module (hci.o) say M here. + +L2CAP protocol support +CONFIG_BLUEZ_L2CAP + L2CAP (Logical Link Control and Adaptation Protocol) provides + connection oriented and connection-less data transport. L2CAP + support is required for most Bluetooth applications. + + Say Y here to compile L2CAP support into the kernel or say M to + compile it as module (l2cap.o). + +HCI UART driver +CONFIG_BLUEZ_HCIUART + Bluetooth HCI UART driver. + This driver is required if you want to use Bluetooth devices with + serial port interface. + + Say Y here to compile support for Bluetooth UART devices into the + kernel or say M to compile it as module (hci_uart.o). + +HCI USB driver +CONFIG_BLUEZ_HCIUSB + Bluetooth HCI USB driver. + This driver is required if you want to use Bluetooth devices with + USB interface. + + Say Y here to compile support for Bluetooth USB devices into the + kernel or say M to compile it as module (hci_usb.o). + +HCI VHCI virtual HCI device driver +CONFIG_BLUEZ_HCIVHCI + Bluetooth Virtual HCI device driver. + This driver is required if you want to use HCI Emulation software. + + Say Y here to compile support for virtual HCI devices into the + kernel or say M to compile it as module (hci_vhci.o). + # The following options are for Linux when running on the Hitachi # SuperH family of RISC microprocessors. @@ -16959,20 +19648,45 @@ # # m68k-specific kernel options -# Documented by Chris Lawrence et al. +# 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. + material available in ; otherwise say N. + +Commodore A2232 serial support +CONFIG_A2232 + This option supports the 2232 7-port serial card shipped with the + Amiga 2000 and other Zorro-bus machines, dating from 1989. At + a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip + each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The + ports were connected with 8 pin DIN connectors on the card bracket, + for which 8 pin to DB25 adapters were supplied. The card also had + jumpers internally to toggle various pinning configurations. + + This driver can be built as a module; but then "generic_serial.o" + will also be built as a module. This has to be loaded before + "ser_a2232.o". If you want to do this, answer M here and read + "". + +A4000T SCSI support +CONFIG_A4000T_SCSI + Support for the NCR53C710 SCSI controller on the Amiga 4000T. + +A4091 SCSI support +CONFIG_A4091_SCSI + Support for the NCR53C710 chip on the Amiga 4091 Z3 SCSI2 controller + (1993). Very obscure -- the 4091 was part of an Amiga 4000 upgrade + plan at the time the Amiga business was sold to DKB. 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. + available in ; otherwise say N. Hades support CONFIG_HADES @@ -16984,7 +19698,7 @@ 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. ;) @@ -16995,14 +19709,51 @@ If you plan to try to use the kernel on such a machine say Y here. Everybody else says N. +Q40/Q60 support +CONFIG_Q40 + The Q40 is a Motorola 68040-based successor to the Sinclair QL + manufactured in Germany. There is an official Q40 home page at + . This option enables support for the Q40 and + Q60. Select your CPU below. For 68LC060 don't forget to enable FPU + emulation. + +Sun 3 support +CONFIG_SUN3 + This option enables support for the Sun 3 series of workstations. + Currently, only the Sun 3/80 is supported within the Sun 3x family. + You will also want to enable 68030 support. General Linux + information on the Sun 3x series (now discontinued) is at + . + + If you don't want to compile a kernel for a Sun 3, say N. + Sun 3X support CONFIG_SUN3X This option enables support for the Sun 3x 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. + General Linux information on the Sun 3x series (now discontinued) + is at . If you don't want to compile a kernel for a Sun 3x, say N. +Sun3x builtin serial support +CONFIG_SUN3X_ZS + ZS refers to a type of asynchronous serial port built in to the Sun3 + and Sun3x workstations; if you have a Sun 3, you probably have + these. Say 'Y' to support ZS ports directly. This option must be + enabled in order to support the + keyboard and mouse ports. + +Sun keyboard support +CONFIG_SUN_KEYBOARD + Say Y here to support the keyboard found on Sun 3 and 3x + workstations. It can also be used support Sun Type-5 keyboards + through an adaptor. See + and + for details on the + latter. + 68020 support CONFIG_M68020 If you anticipate running this kernel on a computer with a MC68020 @@ -17028,7 +19779,7 @@ If you anticipate running this kernel on a computer with a MC68060 processor, say Y. Otherwise, say N. -Math emulation support (EXPERIMENTAL) +Math emulation support 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 @@ -17060,19 +19811,25 @@ 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. + you are doing. Note that the answer to this question won't directly affect the - kernel: saying N will just cause this configure script to skip all + kernel: saying N will just cause the configurator to skip all the questions about these options. Most users should say N to this question. +Use one physical chunk of memory only +CONFIG_SINGLE_MEMORY_CHUNK + Ignore all but the first contiguous chunk of physical memory for VM + purposes. This will save a few bytes kernel size and may speed up + some operations. Say N if not sure. + 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 + 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 @@ -17081,7 +19838,7 @@ really know what you are doing, say N. Try Y only if you're quite adventurous. -Zorro support +Amiga Zorro (AutoConfig) bus support CONFIG_ZORRO This enables support for the Zorro bus in the Amiga. If you have expansion cards in your Amiga that conform to the Amiga @@ -17103,23 +19860,34 @@ When in doubt, say Y. -Amiga 1200/600 PCMCIA support (EXPERIMENTAL) +Amiga 1200/600 PCMCIA support 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. +Hisoft Whippet PCMCIA serial support +CONFIG_WHIPPET_SERIAL + HiSoft has a web page at , but there + is no listing for the Whippet in their Amiga section. + 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 + 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 +Support for ST-RAM as swap space CONFIG_STRAM_SWAP + Some Atari 68k macines (including the 520STF and 1020STE) divide + their addressible memory into ST and TT sections. The TT section + (up to 512MB) is the main memory; the ST section (up to 4MB) is + accessible to the built-in graphics board, runs slower, and is + present mainly for backward compatibility with older machines. + 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 @@ -17130,6 +19898,12 @@ sound). The probability that such allocations at module load time fail is drastically reduced. +ST-RAM statistics in /proc +CONFIG_STRAM_PROC + Say Y here to report ST-RAM usage statistics in /proc/stram. See + the help for CONFIG_STRAM_SWAP for discussion of ST-RAM and its + uses. + Atari ACSI support CONFIG_ATARI_ACSI This enables support for the Atari ACSI interface. The driver @@ -17140,7 +19914,7 @@ 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. + 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). @@ -17171,7 +19945,7 @@ 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. + and read . A2091 WD33C93A support CONFIG_A2091_SCSI @@ -17179,7 +19953,7 @@ 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. + a module, say M here and read . GVP Series II WD33C93A support CONFIG_GVP11_SCSI @@ -17192,21 +19966,21 @@ 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. + as a module, say M here and read . -Cyberstorm SCSI support +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 +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 (EXPERIMENTAL) +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, @@ -17228,18 +20002,25 @@ 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. +BSC Oktagon SCSI support +CONFIG_OKTAGON_SCSI + If you have the BSC Oktagon SCSI disk controller for the Amiga, say + Y to this question. If you're in doubt about whether you have one, + see the picture at + . + 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 + 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). + 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 . 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 @@ -17248,6 +20029,12 @@ use a Toshiba CD-ROM drive; otherwise, the option is not needed and would impact performance a bit, so say N. +Reset SCSI-devices at boottime +CONFIG_ATARI_SCSI_RESET_BOOT + Reset the devices on your Atari whenever it boots. This makes the + boot process fractionally longer but may assist recovery from errors + that leave the devices with SCSI operations partway completed. + Hades SCSI DMA emulator CONFIG_TT_DMA_EMUL This option enables code which emulates the TT SCSI DMA chip on the @@ -17262,7 +20049,7 @@ 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. + a module, say M here and read . Ariadne II and X-Surf support CONFIG_ARIADNE2 @@ -17273,7 +20060,7 @@ 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 ariadne2.o. If you want to compile it as - a module, say M here and read Documentation/modules.txt. + a module, say M here and read . A2065 support CONFIG_A2065 @@ -17283,7 +20070,7 @@ 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. + module, say M here and read . Hydra support CONFIG_HYDRA @@ -17292,17 +20079,30 @@ 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. + module, say M here and read . -Pcmcia NE2000 compatible support +Sun3 NCR5380 SCSI +CONFIG_SUN3_SCSI + This option will enable support for the OBIO (onboard io) NCR5380 + SCSI controller found in the Sun 3/50 and 3/60. Note that this + driver does not provide support for VME SCSI boards. + General Linux information on the Sun 3 series (now discontinued) + is at . + +Sun3x ESP SCSI driver +CONFIG_SUN3X_ESP + The ESP was an on-board SCSI controller used on Sun 3/80 + machines. Say Y here to compile in support for it. + +PCMCIA NE2000 and compatibles support CONFIG_APNE - If you have a pcmcia ne2000 compatible adapter, say Y. Otherwise, + 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. + module, say M here and read . Atari Lance support CONFIG_ATARILANCE @@ -17324,32 +20124,32 @@ Amiga mouse support CONFIG_AMIGAMOUSE - If you want to be able to use an Amiga mouse in Linux, say Y. + 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. + module, say M here and read . Atari mouse support CONFIG_ATARIMOUSE - If you want to be able to use an Atari mouse in Linux, say Y. + 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. + module, say M here and read . 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. + 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. @@ -17365,7 +20165,7 @@ 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 @@ -17382,9 +20182,9 @@ 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) +Atari DSP56k Digital Signal Processor support 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 @@ -17393,7 +20193,12 @@ 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. + . + +Support for early boot text console +CONFIG_BOOTX_TEXT + Say Y here to see progress messages from the boot firmware in text + mode. Requires either BootX or Open Firmware. Amiga builtin serial support CONFIG_AMIGA_BUILTIN_SERIAL @@ -17403,13 +20208,23 @@ 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. +GVP IO-Extender parallel printer support +CONFIG_GVPIOEXT_LP + Say Y to enable driving a printer from the parallel port on your + GVP IO-Extender card, N otherwise. + +GVP IO-Extender PLIP support +CONFIG_GVPIOEXT_PLIP + Say Y to enable doing IP over the parallel port on your GVP + IO-Extender card, N otherwise. + Multiface Card III serial support CONFIG_MULTIFACE_III_TTY If you want to use a Multiface III card's serial port in Linux, @@ -17418,7 +20233,15 @@ 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/Atari/PowerMac DMA sound support +CONFIG_DMASOUND + Support built-in audio chips accessible by DMA on various machines + that have them. Note that this symbol does not affect the kernel + directly; rather, it controls whether configuration questions + enabling DMA sound drivers for various specific machine + architectures will be used. Atari DMA sound support CONFIG_DMASOUND_ATARI @@ -17429,7 +20252,7 @@ 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. + . PowerMac DMA sound support CONFIG_DMASOUND_AWACS @@ -17440,7 +20263,7 @@ 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 DMA sound support CONFIG_DMASOUND_PAULA @@ -17451,7 +20274,7 @@ 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. + . Q40 sound support CONFIG_DMASOUND_Q40 @@ -17462,7 +20285,7 @@ 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 @@ -17480,39 +20303,122 @@ HP300 machines. If you are using such a system you almost certainly want this. +# Choice: ppctype Processor Type CONFIG_6xx - There are four types of PowerPC chips supported. The more common - types (601, 603, 604, 740, 750, 7400), the Motorola embedded versions - (821, 823, 850, 855, 860, 8260), the IBM embedded versions (403 and - 405) and the high end 64 bit Power processors (Power 3, Power 4). - Unless you are building a kernel for one of the embedded processor - systems, or a 64 bit IBM RS/6000, choose 6xx. Note that the kernel - runs in 32-bit mode even on 64-bit chips. Also note that because - the 82xx family has a 603e core, specific support for that chipset - is asked later on. + There are four types of PowerPC chips supported. The more common + types (601, 603, 604, 740, 750, 7400), the Motorola embedded + versions (821, 823, 850, 855, 860, 8260), the IBM embedded versions + (403 and 405) and the high end 64 bit Power processors (Power 3, + Power 4). Unless you are building a kernel for one of the embedded + processor systems, or a 64 bit IBM RS/6000, choose 6xx. Note that + the kernel runs in 32-bit mode even on 64-bit chips. Also note that + because the 82xx family has a 603e core, specific support for that + chipset is asked later on. Motorola MPC8260 CPM support CONFIG_8260 The MPC8260 CPM (Communications Processor Module) is a typical - embedded CPU made by Motorola. Selecting this option means that you - wish to build a kernel for a machine with specifically an 8260 for - a CPU. + embedded CPU made by Motorola. Selecting this option means that + you wish to build a kernel for a machine with specifically an 8260 + for a CPU. If in doubt, say N. +# Choice: Machine type +Oak +CONFIG_OAK + Select Oak if you have an IBM 403GCX "Oak" Evaluation Board. + + Select Walnut if you have an IBM 405GP "Walnut" Evaluation Board. + + More information on these boards is available at: + . + +Walnut +CONFIG_WALNUT + Select Walnut if you have an IBM 405GP "Walnut" Evaluation Board. + Workarounds for PPC601 bugs CONFIG_PPC601_SYNC_FIX Some versions of the PPC601 (the first PowerPC chip) have bugs which - mean that extra synchronization instructions are required near certain - instructions, typically those that make major changes to the CPU state. - These extra instructions reduce performance slightly. If you say N - here, these extra instructions will not be included, resulting in a - kernel which will run faster but may not run at all on some systems - with the PPC601 chip. + mean that extra synchronization instructions are required near + certain instructions, typically those that make major changes to the + CPU state. These extra instructions reduce performance slightly. + If you say N here, these extra instructions will not be included, + resulting in a kernel which will run faster but may not run at all + on some systems with the PPC601 chip. + + If in doubt, say Y here. + +8xx Cache (Copy-Back or Writethrough) +CONFIG_8xx_COPYBACK + Saying Y here will cause the cache on an MPC8xx processor to be used + in Copy-Back mode. If you say N here, it is used in Writethrough + mode. + + If in doubt, say Y here. + +MPC860 (Pre Rev. C) CPU6 Silicon Errata +CONFIG_8xx_CPU6 + MPC860 CPUs, prior to Rev C have some bugs in the silicon, which + require workarounds for Linux (and most other OSes to work). If you + get a BUG() very early in boot, this might fix the problem. For + more details read the document entitled "MPC860 Family Device Errata + Reference" on Motorola's website. This option also incurs a + performance hit. + + If in doubt, say N here. + +MPC8xx IDE support +CONFIG_BLK_DEV_MPC8xx_IDE + This option provides support for IDE on Motorola MPC8xx Systems. + Please see 'Type of MPC8xx IDE interface' for details. + + If unsure, say N. + +Type of MPC8xx IDE interface +CONFIG_IDE_8xx_PCCARD + Select how the IDE devices are connected to the MPC8xx system: + + 8xx_PCCARD uses the 8xx internal PCMCIA interface in combination + with a PC Card (e.g. ARGOSY portable Hard Disk Adapter), + ATA PC Card HDDs or ATA PC Flash Cards (example: TQM8xxL + systems) + + 8xx_DIRECT is used for directly connected IDE devices using the 8xx + internal PCMCIA interface (example: IVMS8 systems) + + EXT_DIRECT is used for IDE devices directly connected to the 8xx + bus using some glue logic, but _not_ the 8xx internal + PCMCIA interface (example: IDIF860 systems) + +Use SMC2 for UART +CONFIG_SMC2_UART + If you would like to use SMC2 as a serial port, say Y here. If in doubt, say Y here. +Use SMC2 for Console +CONFIG_CONS_SMC2 + If you are going to have a serial console on your device and are + using SMC2 for your serial port, say Y here, else say N. + +Use the alternate SMC2 I/O +CONFIG_ALTSMC2 + If you have an MPC823 or MPC850 and would like to use the alternate + SMC2 for I/O, say Y here. + + If in doubt, say N here. + +Enable SCC2 and SCC3 for UART +CONFIG_USE_SCC_IO + If your MPC8xx board has other SCC ports that you would like to use + for for a serial port, say Y here. + + If in doubt, say N here. + +# Choice: ppc6xxtype Machine Type CONFIG_ALL_PPC Linux currently supports several different kinds of PowerPC-based @@ -17522,7 +20428,28 @@ and some IBM RS/6000 systems), CHRP (Common Hardware Reference Platform), and several embedded PowerPC systems containing 4xx, 6xx, 7xx, 8xx, 74xx, and 82xx processors. Currently, the default option - is to build a kernel which works on the first three. + is to build a kernel which works on the first three. + + Select PowerMac/PReP/MTX/CHRP if configuring for any of the above. + + Select Gemini if configuring for a Synergy Microsystems' Gemini + series Single Board Computer. More information is available at: + . + + Select APUS if configuring for a PowerUP Amiga. More information is + available at: . + +Synergy-Gemini +CONFIG_GEMINI + Select Gemini if configuring for a Synergy Microsystems' Gemini + series Single Board Computer. More information is available at: + . + +Amiga-Apus +CONFIG_APUS + Select APUS if configuring for a PowerUP Amiga. + More information is available at: + . Embedded 8xx Board Type CONFIG_RPXLITE @@ -17646,7 +20573,7 @@ altivec registers, and turning on the 'altivec enable' bit so user processes can execute altivec instructions. - This option is only usefully if you have a processor that supports + This option is only usefully if you have a processor that supports altivec (G4, otherwise known as 74xx series), but does not have any affect on a non-altivec cpu (it does, however add code to the kernel). @@ -17657,7 +20584,7 @@ CONFIG_TAU G3 and G4 processors have an on-chip temperature sensor called the 'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die - temperature within 2-4 degrees celcius. This option shows the current + temperature within 2-4 degrees Celsius. This option shows the current on-die temperature in /proc/cpuinfo if the cpu supports it. Unfortunately, on some chip revisions, this sensor is very inaccurate @@ -17681,26 +20608,10 @@ Average high and low temp CONFIG_TAU_AVERAGE The TAU hardware can compare the temperature to an upper and lower bound. - The default behavior is to show both the upper and lower bound in + The default behavior is to show both the upper and lower bound in /proc/cpuinfo. If the range is large, the temperature is either changing - a lot, or the TAU hardware is broken (likely on some G4's). If the range - is small (around 4 degrees), the temperature is relatively stable. - -Support for CUDA based PowerMacs -CONFIG_ADB_CUDA - This provides support for CUDA based Power Macintosh systems. This - includes most OldWorld PowerMacs, the first generation iMacs, the - Blue&White G3 and the Yikes G4 (PCI Graphics). All later models - should use CONFIG_ADB_PMU instead. - - If unsure say Y. - -Support for PMU based PowerMacs -CONFIG_ADB_PMU - This provides support for PMU based Power Macintosh systems. This - includes all PowerBooks and all AGP-based machines. - - If unsure say Y. + a lot, or the TAU hardware is broken (likely on some G4's). If the range + is small (around 4 degrees), the temperature is relatively stable. Power management support for PowerBooks CONFIG_PMAC_PBOOK @@ -17710,7 +20621,7 @@ must get the power management daemon, pmud, to make it work and you must have the /dev/pmu device (see the pmud README). - Get pmud from ftp://linuxcare.com.au/pub/ppclinux/pmud/ + Get pmud from . If you have a PowerBook, you should say Y. @@ -17718,33 +20629,218 @@ have it autoloaded. The act of removing the module shuts down the sound hardware for more power savings. +Backlight control for LCD screens +CONFIG_PMAC_BACKLIGHT + Say Y here to build in code to manage the LCD backlight on a + Macintosh PowerBook. With this code, the backlight will be turned + on and off appropriately on power-management and lid-open/lid-closed + events; also, the PowerBook button device will be enabled so you can + change the screen brightness. + +# Choice: ppc8xxtype +RPX-Lite +CONFIG_RPXLITE + Single-board computers based around the PowerPC MPC8xx chips and + intended for embedded applications. The following types are + supported: + + RPX-Lite -- PC104 form-factor SBC based on the MPC823 + RPX-Classic -- Credit-card-size SBC based on the MPC 860 + BSE-IP -- Bright Star Engineering BSE-IP SBC + TQM823L -- TQM823L SBC from TQ Components + TQM850L -- TQM850L SBC from TQ Components + TQM855L -- TQM855L SBC from TQ Components + TQM860L -- TQM860L SBC from TQ Components + FPS850L -- FingerPrint Sensor from TQ Components + TQM860 -- TQM860 SBC from IKENDI AG + SPD823TS -- Speech Design TeleServer from Speech Design + IVMS8 -- Integrated VoiceMail SBC from Speech Design + SM850 -- Service Module 850 from Dependable Computer Systems + MBX -- MBX821 and MBX860 SBCs + Wincept -- Wincept SBCs for thin-client machines + +RPX-Classic +CONFIG_RPXCLASSIC + The RPX-Classic is a single-board computer based on the Motorola + MPC860. It features 16MB of DRAM and a variable amount of flash, + I2C EEPROM, thermal monitoring, a PCMCIA slot, a DIP switch and two + LEDs. Variants with Ethernet ports exist. Say Y here to support it + directly. + +BSE-IP +CONFIG_BSEIP + Say Y here to support the Bright Star Engineering ipEngine SBC. + This is a credit-card-sized device featuring a MPC823 processor, + 26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video + controller, and two RS232 ports. + +TQM823L +CONFIG_TQM823L + Say Y here to support the TQM823L, one of an MPC8xx-based family of + mini SBCs (half credit-card size) from TQ Components first released + in late 1999. Technical references are at + , and + , and an image at + . + +TQM850L +CONFIG_TQM850L + Say Y here to support the TQM850L, one of an MPC8xx-based family of + mini SBCs (half credit-card size) from TQ Components first released + in late 1999. Technical references are at + , and + , and an image at + . + +TQM855L +CONFIG_TQM855L + Say Y here to support the TQM855L, one of an MPC8xx-based family of + mini SBCs (half credit-card size) from TQ Components first released + in late 1999. Technical references are at + , and + , and an image at + . + +TQM860L +CONFIG_TQM860L + Say Y here to support the TQM860L, one of an MPC8xx-based family of + mini SBCs (half credit-card size) from TQ Components first released + in late 1999. Technical references are at + , and + , and an image at + . + +FPS850 +CONFIG_FPS850 + Say Y here to support the FingerPrint Sensor from AKENDI IG, based + on the TQ Components TQM850L module, released November 1999 and + discontinued a year later. + +TQM860 +CONFIG_TQM860 + Say Y here to support the TQM860, one of an MPC8xx-based family of + SBCs (credit-card size) from TQ Components first released in + mid-1999 and discontinued mid-2000. + +SM850 +CONFIG_SM850 + Say Y here to support the Service Module 850 from Dependable + Computer Systems, an SBC based on the TQM850L module by TQ + Components. This board is no longer in production. The + manufacturer's website is at . + +SPD823TS +CONFIG_SPD823TS + Say Y here to support the Speech Design 823 Tele-Server from Speech + Design, released in 2000. The manufacturer's website is at + . + +IVMS8 +CONFIG_IVMS8 + Say Y here to support the Integrated Voice-Mail Small 8-channel SBC + from Speech Design, released March 2001. The manufacturer's website + is at . + +# IVML24 is not yet active +IVML24 +CONFIG_IVML24 + Say Y here to support the Integrated Voice-Mail Large 24-channel SBC + from Speech Design, released March 2001. The manufacturer's website + is at . + +MBX +CONFIG_MBX + MBX is a line of Motorola single-board computer based around the + MPC821 and MPC860 processors, and intended for embedded-controller + applications. Say Y here to support these boards directly. + +WinCept +CONFIG_WINCEPT + The Wincept 100/110 is a Motorola single-board computer based on the + MPC821 PowerPC, introduced in 1998 and designed to be used in + thin-client machines. Say Y to support it directly. + +# More systems that will be supported soon, according to +# Wolfgang Denk : +# +# TQM8260: +# MPC8260 based module +# +# Manufacturer: TQ Components, www.tq-group.de +# Date of Release: June 2001 +# End of Life: not yet :-) +# URL: +# +# IP860: +# VMEBus IP (Industry Pack) carrier board with MPC860 +# +# Manufacturer: MicroSys GmbH, +# Date of Release: ? +# End of life: - +# URL: +# +# CU824: +# VMEBus Board with PCI extension with MPC8240 CPU +# +# Manufacturer: MicroSys GmbH, +# Date of Release: early 2001 (?) +# End of life: - +# URL: +# Date of Release: mid 2001 +# End of life: - +# URL: +# +# PCU_E: +# PCU = Peripheral Controller Unit; E = extended (?) +# +# Mfr: Siemens AG, ICN (Information and Communication Networks) +# +# Date of Release: April 2001 +# End of life: - +# URL: n. a.o + +Support for EST8260 +CONFIG_EST8260 + The EST8260 is a single-board computer manufactured by Wind River + Systems, Inc. (formerly Embedded Support Tools Corp.) and based on + the MPC8260. Wind River Systems has a website at + , but the EST8260 cannot be found on it + and has probably been discontinued or rebadged. + ADB raw keycode support CONFIG_MAC_ADBKEYCODES This provides support for sending raw ADB keycodes to console devices. This is the default up to 2.4.0, but in future this may be - phased out in favor of generic Linux keycodes. If you say Y here, you - can dynamically switch via the + phased out in favor of generic Linux keycodes. If you say Y here, + you can dynamically switch via the /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes - sysctl and with the "keyboard_sends_linux_keycodes=" kernel argument. - + sysctl and with the "keyboard_sends_linux_keycodes=" kernel + argument. + If unsure, say Y here. Mouse button 2+3 emulation support CONFIG_MAC_EMUMOUSEBTN This provides generic support for emulating the 2nd and 3rd mouse - button with keypresses. If you say Y here, the emulation is still - disabled by default. The emulation is controlled by these sysctl entries: + button with keypresses. If you say Y here, the emulation is still + disabled by default. The emulation is controlled by these sysctl + entries: /proc/sys/dev/mac_hid/mouse_button_emulation /proc/sys/dev/mac_hid/mouse_button2_keycode /proc/sys/dev/mac_hid/mouse_button3_keycode -Enhanced Real Time Clock Support +Enhanced Real Time Clock Support (/dev/rtc) CONFIG_PPC_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 (or hardware clock) built + will get access to the real time clock (or hardware clock) built into your computer. - + If unsure, say Y here. Support for Open Firmware device tree in /proc @@ -17753,27 +20849,27 @@ an image of the device tree that the kernel copies from Open Firmware. If unsure, say Y here. -RTAS proc interface +RTAS (RunTime Abstraction Services) in /proc CONFIG_PPC_RTAS When you use this option, you will be able to use RTAS from - userspace. - + userspace. + RTAS stands for RunTime Abstraction Services and should provide a portable way to access and set system information. This is - commonly used on RS/6000 (pSeries) computers. - - You can access RTAS via the special proc filesystem entry rtas. + commonly used on RS/6000 (pSeries) computers. + + You can access RTAS via the special proc file system entry rtas. Don't confuse this rtas entry with the one in /proc/device-tree/rtas which is readonly. - + If you don't know if you can use RTAS look into /proc/device-tree/rtas. If there are some entries, it is very likely that you will be able to use RTAS. You can do cool things with rtas. To print out information about - various sensors in the system, just do a + various sensors in the system, just do a - $ cat /proc/rtas/sensors + $ cat /proc/rtas/sensors or if you power off your machine at night but want it running when you enter your office at 7:45 am, do a @@ -17782,7 +20878,7 @@ and shutdown. - If unsure, say Y + If unsure, say Y. MESH (Power Mac internal SCSI) support CONFIG_SCSI_MESH @@ -17792,9 +20888,9 @@ 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. + say M here and read . -Maximum synchronous transfer rate +Maximum synchronous transfer rate (MB/s) (0 = async) 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 @@ -17810,12 +20906,12 @@ 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. + 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. + here and read . MACE (Power Mac Ethernet) support CONFIG_MACE @@ -17826,7 +20922,7 @@ 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. + here and read . Use AAUI port instead of TP by default CONFIG_MACE_AAUI_PORT @@ -17835,53 +20931,52 @@ instead of an 8-pin RJ45 connector for twisted-pair ethernet. Say Y here if you have such a machine. If unsure, say N. The driver will default to AAUI on ANS anyway, and if you use it as - a module, you can provide the port_aaui=0|1 to force the driver - setting. + a module, you can provide the port_aaui=0|1 to force the driver. -BMAC (G3 ethernet) support +BMAC (G3 Ethernet) support CONFIG_BMAC Say Y for support of BMAC Ethernet interfaces. These are used on G3 - computers. + 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. + here and read . -GMAC (G4/iBook ethernet) support +GMAC (G4/iBook Ethernet) support CONFIG_GMAC Say Y for support of GMAC Ethernet interfaces. These are used on G4 - and iBook computers. + and iBook computers. This driver is also available as a module called gmac.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. + here and read . -National DP83902AV (Oak ethernet) support +National DP83902AV (Oak Ethernet) support CONFIG_OAKNET Say Y if your machine has this type of Ethernet network card. This driver is also available as a module called oaknet.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. + here and read . 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. + the file . 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. + here and read . Video For Linux /proc file system information CONFIG_VIDEO_PROC_FS @@ -17897,122 +20992,121 @@ 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 + 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. + 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 + 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. + . More + information is contained in the file + . 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. + say M here and read . The module + will be called radio-aimslab.o. -RadioTrack i/o port +RadioTrack I/O port CONFIG_RADIO_RTRACK_PORT - Enter either 0x30f or 0x20f here. The card default is 0x30f, if you + 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 + 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 + 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. + say M here and read . The module + will be called radio-rtrack2.o. -RadioTrack II i/o port +RadioTrack II I/O port CONFIG_RADIO_RTRACK2_PORT - Enter either 0x30c or 0x20c here. The card default is 0x30c, if you + 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 + 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. + say M here and read . The module + will be called radio-aztech.o. -Aztech/Packard Bell radio card i/o port +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 + 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 + 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. + say M here and read . The module + will be called radio-cadet.o. 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. + Choose Y here if you have one of these FM radio cards. If you + compile the driver into the kernel and your card is not PnP one, you + have to add "sf16fm=" to the kernel command line (I/O address is + 0x284 or 0x384). In order to control your radio card, you will need to use programs - that are compatible with the Video for Linux API. Information on + 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. + say M here and read . The module + will be called radio-sf16fmi.o. -Typhoon Radio +Typhoon Radio (a.k.a. EcoRadio) 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 + 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 + say M here and read . The module + will be called radio-typhoon.o. Support for /proc/radio-typhoon CONFIG_RADIO_TYPHOON_PROC_FS @@ -18041,88 +21135,132 @@ 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 + 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 + say M here and read . 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 +I2C 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. + 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. + say M here and read . The module + will be called i2c-parport.o. miroSOUND PCM20 radio CONFIG_RADIO_MIROPCM20 - Choose Y here if you have this sound card. You also need to say Y + Choose Y here if you have this FM radio card. You also need to say Y to "ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)" (in "Sound") 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 + 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 miropcm20.o + say M here and read . The module + will be called miropcm20.o. miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL) CONFIG_RADIO_MIROPCM20_RDS - Choose Y here if you want to see RDS/RBDS information like RadioText, - Programme Service name, Clock Time and date, Programme TYpe and - Traffic Announcement/Programme identification. You also need to say - Y to "miroSOUND PCM20 radio" and devfs! + Choose Y here if you want to see RDS/RBDS information like + RadioText, Programme Service name, Clock Time and date, Programme + TYpe and Traffic Announcement/Programme identification. You also + need to say Y to "miroSOUND PCM20 radio" and devfs! It's not possible to read the raw RDS packets from the device, so - the driver cant provide an V4L interface for this. But the - availability of RDS is reported over V4L by the basic driver already. - Here RDS can be read from files in /dev/v4l/rds. + the driver cant provide an V4L interface for this. But the + availability of RDS is reported over V4L by the basic driver + already. Here RDS can be read from files in /dev/v4l/rds. As module the driver will be called miropcm20-rds.o. -GemTek Radio Card +Maestro on board radio +CONFIG_RADIO_MAESTRO + Say Y here to directly support the on-board radio tuner on the + Maestro 2 or 2E sound card. + + 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 + . + + 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 . The module + will be called radio-maestro.o. + +Guillemot MAXI Radio FM 2000 Radio Card +CONFIG_RADIO_MAXIRADIO + Choose Y here if you have this radio card. This card may also be + found as Gemtek PCI FM. + + 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 + . + + 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 . The module + will be called radio-maxiradio.o. + +GemTek Radio Card support CONFIG_RADIO_GEMTEK - Choose Y here if you have this FM radio card, and then fill in the + 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 + 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. + say M here and read . The module + will be called radio-gemtek.o. -GemTek i/o port +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. On - Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the i/o + Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O port is 0x28c. +Gemtek PCI Radio +CONFIG_RADIO_GEMTEK_PCI + Choose Y here if you have this PCI FM radio card. + + 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 + . + + 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 . The module + will be called radio-gemtek-pci.o. + 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. + See for more info. Saying M will compile this driver as a module (planb.o). @@ -18131,34 +21269,27 @@ 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 + 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) - + 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 + 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-terratec.o. + say M here and read . The module + will be called radio-terratec.o. -Terratec i/o port (normally 0x590) +Terratec I/O port (normally 0x590) CONFIG_RADIO_TERRATEC_PORT - Fill in the i/o port of your TerraTec FM radio card. If unsure, go + Fill in the I/O port of your TerraTec FM radio card. If unsure, go with the default. -### Add these -# Zoran ZR36057/36060 support -# CONFIG_VIDEO_ZORAN - -# Include support for Iomega Buz -# CONFIG_VIDEO_BUZ - Trust FM radio card CONFIG_RADIO_TRUST This is a driver for the Trust FM radio cards. Say Y if you have @@ -18167,38 +21298,76 @@ This driver is also available as a module called radio-trust.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. + here and read . -Trust i/o port (usually 0x350 or 0x358) +Trust I/O port (usually 0x350 or 0x358) CONFIG_RADIO_TRUST_PORT - Enter the i/o port of your Trust FM radio card. If unsure, try the + Enter the I/O port of your Trust FM radio card. If unsure, try the values "0x350" or "0x358". 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. + for more information. If you say Y or M here, you need to say Y or M to "I2C support" and "I2C bit-banging interfaces" in the character device section. - + This driver is 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. + here and read . + +BT878 Audio DMA +CONFIG_SOUND_BT878 + Audio DMA support for bt878 based grabber boards. As you might have + already noticed, bt878 is listed with two functions in /proc/pci. + Function 0 does the video stuff (bt848 compatible), function 1 does + the same for audio data. This is a driver for the audio part of + the chip. If you say 'Y' here you get a oss-compatible dsp device + where you can record from. If you want just watch TV you probably + don't need this driver as most TV cards handle sound with a short + cable from the TV card to your sound card's line-in. + + This driver is available as a module called btaudio.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 . + +SGI Vino Video For Linux +CONFIG_VIDEO_VINO + Say Y here to build in support for the Vino video input system found + on SGI Indy machines. + +Stradis 4:2:2 MPEG-2 video driver +CONFIG_VIDEO_STRADIS + Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video + driver for PCI. There is a product page at + . + +Zoran ZR36057/36060 Video For Linux +CONFIG_VIDEO_ZORAN + Say Y here to include support for video cards based on the Zoran + ZR36057/36060 encoder/decoder chip (including the Iomega Buz and the + Miro DC10 and DC30 video capture cards). + +Include support for Iomega Buz +CONFIG_VIDEO_BUZ + Say Y here to include support for the Iomega Buz video card. There + is a Buz/Linux homepage at . -ZR36120/36125 Video for Linux +Zoran ZR36120/36125 Video For Linux CONFIG_VIDEO_ZR36120 Support for ZR36120/ZR36125 based frame grabber/overlay boards. This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV, and Buster boards. Please read the material in - Documentation/video4linux/zr36120.txt for more information. + for more information. This driver is also available as a module called zr36120.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. + here and read . SAA5249 Teletext processor CONFIG_VIDEO_SAA5249 @@ -18208,26 +21377,37 @@ 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. + here and read . -Quickcam BW Video For Linux +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. + 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. + here and read . -Colour QuickCam Video For Linux +QuickCam Colour 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). Read Documentation/video4linux/CQcam.txt for - more information. + 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). + Read for more information. + +Winbond W9966CF Webcam Video For Linux +CONFIG_VIDEO_W9966 + Video4linux driver for Winbond's w9966 based Webcams. + Currently tested with the LifeView FlyCam Supra. + If you have one of these cameras, say Y here + otherwise say N. + This driver is also available as a module (w9966.o). + + Check out and + for more information. CPiA Video For Linux CONFIG_VIDEO_CPIA @@ -18236,10 +21416,10 @@ Blaster Webcam II. If you have one of these cameras, say Y here and select parallel port and/or USB lowlevel support below, otherwise say N. This will not work with the Creative Webcam III. - - Please read Documentation/video4linux/README.cpia for more + + Please read for more information. - + This driver is also available as a module (cpia.o). CPiA Parallel Port Lowlevel Support @@ -18260,11 +21440,13 @@ 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 + 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. + from the running kernel whenever you want). If you want to compile + it as a module, say M here and read + . +Sony Vaio Picturebook Motion Eye Video for Linux CONFIG_VIDEO_MEYE This is the video4linux driver for the Motion Eye camera found in the Vaio Picturebook laptops. Please read the material in @@ -18285,20 +21467,20 @@ s390-compiler released by IBM (based on gcc-2.95.1) before. Merge some code into the kernel to make the image IPLable -CONFIG_IPLABLE +CONFIG_IPL If you want to use the produced kernel to IPL directly from a device, you have to merge a bootsector specific to the device into the first bytes of the kernel. You will have to select the - IPL device on another question, that pops up, when you select - CONFIG_IPLABE. + IPL device. -IPL from a /390 tape unit +# Choice: s390_ipl +IPL from a S/390 tape unit CONFIG_IPL_TAPE Select this option if you want to IPL the image from a Tape. IPL from a virtual card reader emulated by VM/ESA CONFIG_IPL_RDR_VM - Select this option if you are running under VM/ESA and want + Select this option if you are running under VM/ESA and want to IPL the image from the emulated card reader. IPL from a real card reader @@ -18307,7 +21489,7 @@ card reader. Maybe you still got one and want to try. We didn't test. -IBMs S/390 Harddisks (DASDs) +Support for DASD hard disks CONFIG_DASD Enable this option if you want to access DASDs directly utilizing S/390s channel subsystem commands. This is necessary for running @@ -18340,6 +21522,163 @@ CONFIG_DASD_FBA FBA devices are currently unsupported. +Merge some code into the kernel to make the image IPLable +CONFIG_IPLABLE + If you want to use the produced kernel to IPL directly from a + device, you have to merge a bootsector specific to the device + into the first bytes of the kernel. You will have to select the + IPL device on another question, that pops up, when you select + CONFIG_IPLABE. + +Support for 3215 line mode terminal +CONFIG_3215 + Include support for IBM 3215 line-mode terminals. Can't be used + if 3270 console support is chosen. + +Support for console on 3215 line mode terminal +CONFIG_3215_CONSOLE + Include support for using an IBM 3215 line-mode terminal as the + Linux system console. Can't be used if 3270 console support is + chosen. + +Support for 3270 line mode terminal +CONFIG_3270 + Include support for IBM 3270 line-mode terminals. + +Support for console on 3270 line mode terminal +CONFIG_3270_CONSOLE + Include support for using an IBM 3270 line-mode terminal as the + Linux system console. Excludes using 3215s. Available only if 3270 + support is compiled in statically. + +Support for HWC line mode terminal +CONFIG_HWC + Include support for IBM HWC line-mode terminals. + +Console on HWC line mode terminal +CONFIG_HWC_CONSOLE + Include support for using an IBM HWC line-mode terminal as the Linux + system console. + +S/390 tape device support +CONFIG_S390_TAPE + Select this option if you want to access channel-attached tape + devices on IBM S/390 or zSeries. + If you select this option you will also want to select at + least one of the tape interface options and one of the tape + hardware options in order to access a tape device. + This option is also available as a module. The module will be + called tape390.o and include all selected interfaces and + hardware drivers. + +Support for tape character devices +CONFIG_S390_TAPE_CHAR + Select this option if you want to access your channel-attached + tape devices using the character device interface. + This interface is similar to other Linux tape devices like + SCSI-Tapes (st) and the floppy tape device (ftape). + If unsure, say "Y". + +Support for tape block devices +CONFIG_S390_TAPE_BLOCK + Select this option if you want to access your channel-attached tape + devices using the block device interface. This interface is similar + to CD-ROM devices on other platforms. The tapes can only be + accessed read-only when using this interface. Have a look at + Documentation/s390/TAPE for further information about creating + volumes for and using this interface. It is safe to say "Y" here. + +Support for 3490 tape hardware +CONFIG_S390_TAPE_3490 + Select this option if you want to access IBM 3480 magnetic + tape subsystems and 100% compatibles. + It is safe to say "Y" here. + +Support for 3480 tape hardware +CONFIG_S390_TAPE_3480 + Select this option if you want to access IBM 3490 magnetic + tape subsystems and 100% compatibles. + +CTC device support +CONFIG_CTC + Select this option if you want to use channel-to-channel networking + on IBM S/390 or zSeries. This device driver supports real CTC + coupling using ESCON. It also supports virtual CTCs when running + under VM. It will use the channel device configuration if this is + available. This option is also available as a module which will be + called ctc.o. If you do not know what it is, it's safe to say "Y". + +Support for DIAG access to CMS reserved Disks +CONFIG_DASD_DIAG + Select this option if you want to use CMS reserved Disks under VM + with the Diagnose250 command. If you are not running under VM or + unsure what it is, say "N". + +XPRAM disk support +CONFIG_BLK_DEV_XPRAM + Select this option if you want to use your expanded storage on S/390 + or zSeries as a disk. This is useful as a _fast_ swap device if you + want to access more than 2G of memory when running in 31 bit mode. + This option is also available as a module which will be called + xpram.o. If unsure, say "N". + +Fast IRQ handling +CONFIG_FAST_IRQ + Select this option in order to get the interrupts processed faster + on your S/390 or zSeries machine. If selected, after an interrupt + is processed, the channel subsystem will be asked for other pending + interrupts which will also be processed before leaving the interrupt + context. This speeds up the I/O a lot. Say "Y". + +IUCV device support (VM only) +CONFIG_IUCV + Select this option if you want to use inter-user communication + vehicle networking under VM or VIF. This option is also available + as a module which will be called iucv.o. If unsure, say "Y". + +Kernel support for 31 bit ELF binaries +CONFIG_S390_SUPPORT + Select this option if you want to enable your system kernel to + handle system-calls from ELF binaries for 31 bit ESA. This option + (and some other stuff like libraries and such) is needed for + executing 31 bit applications. It is safe to say "Y". + +Channel Device Configuration +CONFIG_CHANDEV + The channel device layer is a layer to provide a consistent + interface for configuration & default machine check (devices + appearing & disappearing) handling on Linux for s/390 & z/Series + channel devices. + + s/390 & z/Series channel devices include among others + + lcs (the most common ethernet/token ring/fddi standard on + zSeries) + ctc/escon hi speed like serial link standard on zSeries + claw used to talk to cisco routers. + qeth gigabit ethernet. + + These devices use two channels one read & one write for + configuration & communication (& a third channel, the data + channel the case of gigabit ethernet). The motivation + behind developing this layer was that there was a lot of + duplicate code among the channel device drivers for + configuration. + + Also the lcs & ctc drivers tended to fight over + 3088/08's & 3088/1F's which could be either 2216/3172 + channel attached lcs compatible devices or escon/ctc pipes + had to be configured separately as they couldn't autodetect, + this is now simplified by doing the configuration in a single + place (the channel device layer). + + This layer isn't invasive & it is quite okay to use channel + drivers which don't use the channel device layer in + conjunction with drivers which do. + + For more info see the chandev manpage usually distributed in + in the Linux source tree. + SAB3036 tuner support CONFIG_TUNER_3036 Say Y here to include support for Philips SAB3036 compatible tuners. @@ -18347,15 +21686,24 @@ 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. + This is the driver for Compaq Smart Array controllers. Everyone + using these boards should say Y here. See the file + for the current list of boards + supported by this driver, and for further information on the use of + this driver. + +Show crashed user process info +CONFIG_PROCESS_DEBUG + Say Y to print all process fault locations to the console. This is + a debugging option; you probably do not want to set it unless you + are an S390 port maintainer. # # ARM options # +# CML2 transition note: CML1 asks ARCH_ARCA5K, then has ARCH_A5K and ARCH_ARK +# as subquestions. CML2 asks the subquestions in the armtype menu and makes +# ARCH_ARCA5K a derived symbol. ARM System type CONFIG_ARCH_ARCA5K This selects what ARM system you wish to build the kernel for. It @@ -18363,110 +21711,224 @@ to set this option to, please consult any information supplied with your system. +# Choice: armtype +A5000 +CONFIG_ARCH_A5K + Say Y here to to support the Acorn A5000. Linux can support the + internal IDE disk and CD-ROM interface, serial and parallel port, + and the floppy drive. Note that on some A5000s the floppy is + plugged into the wrong socket on the motherboard. + +Archimedes +CONFIG_ARCH_ARC + The Acorn Archimedes was an personal computer based on an 8K ARM2 + processor, released in 1987. It supported 512K of RAM and 2 800K + floppy disks. Picture and more detailed specifications at + . + +EBSA-110 +CONFIG_ARCH_EBSA110 + This is an evaluation board for the StrongARM processor available + from Digital. It has limited hardware on-board, including an onboard + Ethernet interface, two PCMCIA sockets, two serial ports and a + parallel port. + +RiscPC +CONFIG_ARCH_RPC + On the Acorn Risc-PC, Linux can support the internal IDE disk and + CD-ROM interface, serial and parallel port, and the floppy drive. + 2MB physical memory CONFIG_PAGESIZE_16 Say Y here if your Archimedes or A5000 system has only 2MB of memory, otherwise say N. The resulting kernel will not run on a machine with 4MB of memory. -Include support for the CATS +CATS CONFIG_ARCH_CATS Say Y here if you intend to run this kernel on the CATS. Saying N will reduce the size of the Footbridge kernel. -Include support for the EBSA285 +EBSA285 (addin mode) +CONFIG_ARCH_EBSA285_ADDIN + Say Y here if you intend to run this kernel on the EBSA285 card + in addin mode. + + Saying N will reduce the size of the Footbridge kernel. + +EBSA285 (host mode) CONFIG_ARCH_EBSA285_HOST Say Y here if you intend to run this kernel on the EBSA285 card in host ("central function") mode. Saying N will reduce the size of the Footbridge kernel. -Include support for the LinkUp Systems L7200 SDB +LinkUp Systems L7200 SDB CONFIG_ARCH_L7200 Say Y here if you intend to run this kernel on a LinkUp Systems L7200 Software Development Board which uses an ARM720T processor. Information on this board can be obtained at: - http://www.linkupsys.com/ + If you have any questions or comments about the Linux kernel port - to this board, send e-mail to sjhill@cotw.com + to this board, send e-mail to sjhill@cotw.com. -Include support for the NetWinder +NetWinder CONFIG_ARCH_NETWINDER Say Y here if you intend to run this kernel on the Rebel.COM NetWinder. Information about this machine can be found at: - http://www.netwinder.org/ + Saying N will reduce the size of the Footbridge kernel. -Include support for the Compaq Personal Server +P720T +CONFIG_ARCH_P720T + Say Y here if you intend to run this kernel on the ARM Prospector + 720T. + +Compaq Personal Server CONFIG_ARCH_PERSONAL_SERVER Say Y here if you intend to run this kernel on the Compaq Personal Server. - + Saying N will reduce the size of the Footbridge kernel. - The Compaq Personal Server is not available for purchase. + The Compaq Personal Server is not available for purchase. There are no product plans beyond the current research prototypes at this time. Information is available at: - - http://crl.research.compaq.com/projects/personalserver - + + + If you have any questions or comments about the Compaq Personal - Server, send e-mail to skiff@crl.dec.com + Server, send e-mail to skiff@crl.dec.com. -Include support for Assabet +Assabet CONFIG_SA1100_ASSABET Say Y here if you are using the Intel(R) StrongARM(R) SA-1110 Microprocessor Development Board (also known as the Assabet). -Include support for Neponset +Neponset CONFIG_ASSABET_NEPONSET Say Y here if you are using the Intel(R) StrongARM(R) SA-1110 Microprocessor Development Board (Assabet) with the SA-1111 Development Board (Nepon). -Include support for the Compaq iPAQ H3600 (Bitsy) -CONFIG_SA1100_BITSY - Say Y here if you intend to run this kernel on the Compaq iPAQ +Compaq iPAQ H3600 +CONFIG_SA1100_H3600 + Say Y here if you intend to run this kernel on the Compaq iPAQ H3600 handheld computer. Information about this machine and the Linux port to this machine can be found at: - http://www.handhelds.org/Compaq/index.html#iPAQ_H3600 - http://www.compaq.com/products/handhelds/pocketpc/ + + -Include support for Brutus +Brutus CONFIG_SA1100_BRUTUS Say Y here if you are using the Intel(R) StrongARM(R) SA-1100 Microprocessor Development Board (also known as the Brutus). -Include support for LART +LART CONFIG_SA1100_LART Say Y here if you are using the Linux Advanced Radio Terminal - (also known as the LART). See http://www.lart.tudelft.nl/ for + (also known as the LART). See for information on the LART. -Include support for GraphicsClient +GraphicsClient CONFIG_SA1100_GRAPHICSCLIENT Say Y here if you are using an Applied Data Systems Intel(R) StrongARM(R) SA-1100 based Graphics Client SBC. See - http://www.flatpanels.com/ for information on this system. + for information on this system. + +CerfBoard +CONFIG_SA1100_CERF + The Intrinsyc CerfBoard is based on the StrongARM 1110. + More information is available at: + . + + Say Y if configuring for an Intrinsyc CerfBoard. + Say N otherwise. + +nanoEngine +CONFIG_SA1100_NANOENGINE + The nanoEngine is a StrongARM 1110-based single board computer + from Bright Star Engineering. More information is available at: + . + + Say Y if configuring for a nanoEngine. + Say N otherwise. + +Pangolin +CONFIG_SA1100_PANGOLIN + Pangolin is a StrongARM 1110-based evaluation platform produced + by Dialogue Technology. It has EISA slots for ease of configuration + with SDRAM/Flash memory card, USB/Serial/Audio card, Compact Flash + card, and TFT-LCD card. + + Say Y if configuring for a Pangolin. + Say N otherwise. -Include support for Victor +Victor CONFIG_SA1100_VICTOR Say Y here if you are using a Visu Aide Intel(R) StrongARM(R) SA-1100 based Victor Digital Talking Book Reader. See - http://www.visuaide.com/pagevictor.en.html for information on + for information on this system. -Load kernel using Angel Debug Monitor -CONFIG_ANGELBOOT - Say Y if you plan to load the kernel using Angel, ARM Ltd's target - debug stub. If you are not using Angel, you must say N. It is - important to get this setting correct. +Support ARM610 processor +CONFIG_CPU_ARM610 + The ARM610 is the successor to the ARM3 processor + and was produced by VLSI Technology Inc. + + Say Y if you want support for the ARM610 processor. + Otherwise, say N. + +Support ARM710 processor +CONFIG_CPU_ARM710 + A 32-bit RISC microprocessor based on the ARM7 processor core + designed by Advanced RISC Machines Ltd. The ARM710 is the + successor to the ARM610 processor. It was released in + July 1994 by VLSI Technology Inc. + + Say Y if you want support for the ARM710 processor. + Otherwise, say N. + +Support ARM720T processor +CONFIG_CPU_ARM720T + A 32-bit RISC processor with 8kByte Cache, Write Buffer and + MMU built around an ARM7TDMI core. + + Say Y if you want support for the ARM720T processor. + Otherwise, say N. + +Support ARM920T processor +CONFIG_CPU_ARM920T + The ARM920T is licensed to be produced by numerous vendors, + and is used in the Maverick EP9312. More information at + . + + Say Y if you want support for the ARM920T processor. + Otherwise, say N. + +Support ARM1020 processor +CONFIG_CPU_ARM1020 + The ARM1020 is the cached version of the ARM10 processor, + with an addition of a floating-point unit. + + Say Y if you want support for the ARM1020 processor. + Otherwise, say N. + +Support StrongARM SA-110 processor +CONFIG_CPU_SA110 + The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and + is available at five speeds ranging from 100 MHz to 233 MHz. + More information is available at + . + + Say Y if you want support for the SA-110 processor. + Otherwise, say N. Math emulation CONFIG_FPE_NWFPE @@ -18483,24 +21945,26 @@ You may say N here if you are going to load the Acorn FPEmulator early in the bootup. +FastFPE math emulation CONFIG_FPE_FASTFPE Say Y here to include the FAST floating point emulator in the kernel. This is an experimental much faster emulator which has only 32 bit - precision for the mantissa. It does not support any exceptions. This - makes it very simple, it is approximately 4-8 times faster than NWFPE. - - It should be sufficient for most programs. It is definitely not - suitable if you do scientific calculations that need double precision - for iteration formulas that sum up lots of very small numbers. If you - do not feel you need a faster FP emulation you should better choose + precision for the mantissa. It does not support any exceptions. + This makes it very simple, it is approximately 4-8 times faster than NWFPE. + It should be sufficient for most programs. It is definitely not + suitable if you do scientific calculations that need double + precision for iteration formulas that sum up lots of very small + numbers. If you do not feel you need a faster FP emulation you + should better choose NWFPE. + It is also possible to say M to build the emulator as a module - (fastfpe.o). But keep in mind that you should only load the FP emulator - early in the bootup. You should never change from NWFPE to FASTFPE or - vice versa in an active system! + (fastfpe.o). But keep in mind that you should only load the FP + emulator early in the bootup. You should never change from NWFPE to + FASTFPE or vice versa in an active system! -DS1620 Thermometer support +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 @@ -18531,7 +21995,7 @@ information that is reported is severely limited. Most people should say N here. -User fault debugging +Verbose user fault messages 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 @@ -18555,22 +22019,18 @@ Kernel low-level debugging messages via footbridge serial port CONFIG_DEBUG_DC21285_PORT - Say Y here if you want the low-level print routines to direct their - output to the serial port in the DC21285 (Footbridge). + Say Y here if you want the debug print routines to direct their + output to the serial port in the DC21285 (Footbridge). Saying N + will cause the debug messages to appear on the first 16550 + serial port. + +Kernel low-level debugging messages via UART2 +CONFIG_DEBUG_CLPS711X_UART2 + Say Y here if you want the debug print routines to direct their + output to the second serial port on these devices. Saying N will + cause the debug messages to appear on the first serial port. -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) +Disable pgtable cache CONFIG_NO_PGT_CACHE Normally the kernel maintains a `quicklist' of preallocated pagetable structures in order to increase performance. On machines @@ -18580,7 +22040,7 @@ 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 + 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). @@ -18591,9 +22051,9 @@ 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) + memory size and the root device (e.g., mem=64M root=/dev/nfs). -Hardware alignment trap (EXPERIMENTAL) +Kernel-mode alignment trap handler 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 @@ -18603,57 +22063,82 @@ correct operation of some network protocols. With an IP-only configuration it is safe to say N, otherwise say Y. -21285 serial port support +DC21285 serial port support CONFIG_SERIAL_21285 If you have a machine based on a 21285 (Footbridge) StrongARM(R)/ 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 +Console on DC21285 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. SA1100 serial port support CONFIG_SERIAL_SA1100 + * Orphaned entry retained 20 April 2001 by Russell King * + * If you read this note from the configurator, please contact * + * the Configure.help maintainers. * If you have a machine based on a SA1100/SA1110 StrongARM CPU you can enable its onboard serial port by enabling this option. - Please read Documentation/arm/SA1100/serial_UART for further info. + Please read for further + info. Console on SA1100 serial port CONFIG_SERIAL_SA1100_CONSOLE + * Orphaned entry retained 20 April 2001 by Russell King * + * If you read this note from the configurator, please contact * + * the Configure.help maintainers. * If you have enabled the serial port on the SA1100/SA1110 StrongARM CPU you can make it the console by answering Y to this option. L7200 serial port support CONFIG_SERIAL_L7200 + * Orphaned entry retained 20 April 2001 by Russell King * + * If you read this note from the configurator, please contact * + * the Configure.help maintainers. * If you have a LinkUp Systems L7200 board you can enable its two onboard serial ports by enabling this option. The device numbers are major ID 4 with minor 64 and 65 respectively. Console on L7200 serial port CONFIG_SERIAL_L7200_CONSOLE + * Orphaned entry retained 20 April 2001 by Russell King * + * If you read this note from the configurator, please contact * + * the Configure.help maintainers. * If you have enabled the serial ports on the L7200 development board you can make the first serial port the console by answering Y to this option. L7200 SDB keyboard support CONFIG_KEYBOARD_L7200 + * Orphaned entry retained 20 April 2001 by Russell King * + * If you read this note from the configurator, please contact * + * the Configure.help maintainers. * Enable this option if you would like to be able to use a keyboard on a LinkUp Systems L7200 board. L7200 SDB Fujitsu keyboard support CONFIG_KEYBOARD_L7200_NORM + * Orphaned entry retained 20 April 2001 by Russell King * + * If you read this note from the configurator, please contact * + * the Configure.help maintainers. * Select the Fujitsu keyboard if you want a normal QWERTY style keyboard on the LinkUp SDB. L7200 SDB Prototype keyboard support CONFIG_KEYBOARD_L7200_DEMO + * Orphaned entry retained 20 April 2001 by Russell King * + * If you read this note from the configurator, please contact * + * the Configure.help maintainers. * Select the prototype keyboard if you want to play with the LCD/keyboard combination on the LinkUp SDB. Footbridge Mode CONFIG_HOST_FOOTBRIDGE + * Orphaned entry retained 20 April 2001 by Russell King * + * If you read this note from the configurator, please contact * + * the Configure.help maintainers. * 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 @@ -18691,7 +22176,7 @@ 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 nwflash.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + module, say M here and read . If you're not sure, say N. @@ -18704,22 +22189,22 @@ This driver is also available as a module and will be called srm_env.o if you build it as a module. - + Footbridge internal watchdog CONFIG_21285_WATCHDOG - The Intel Footbridge chip contains a builtin watchdog circuit. Say Y + The Intel Footbridge chip contains a builtin watchdog circuit. Say Y here if you wish to use this. Alternatively say M to compile the driver as a module, which will be called wdt285.o. - This driver does not work on all machines. In particular, early CATS - boards have hardware problems that will cause the machine to simply + This driver does not work on all machines. In particular, early CATS + boards have hardware problems that will cause the machine to simply lock up if the watchdog fires. "If in doubt, leave it out" - say N. -NetWinder WB977 watchdog +NetWinder WB83C977 watchdog CONFIG_977_WATCHDOG - Say Y here to include support for the WB977 watchdog included in + Say Y here to include support for the WB977 watchdog included in NetWinder machines. Alternatively say M to compile the driver as a module, which will be called wdt977.o. @@ -18732,27 +22217,41 @@ 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 irattach. For more information, see the file - Documentation/networking/irda.txt. You also want to read the - IR-HOWTO, available at http://www.linuxdoc.org/docs.html#howto . + some user-space utilities like irattach. For more information, see + the file . You also want to + read the IR-HOWTO, available at + . + + If you want to exchange bits of data (vCal, vCard) with a PDA, you + will need to install some OBEX application, such as OpenObex : + - This support is also available as a module called irda.o. If you + This support is also available as a module called irda.o. If you want to compile it as a module, say M here and read - Documentation/modules.txt. + . + +Ultra (connectionless) protocol +CONFIG_IRDA_ULTRA + Say Y here to support the connectionless Ultra IRDA protocol. + Ultra allows to exchange data over IrDA with really simple devices + (watch, beacon) without the overhead of the IrDA protocol (no handshaking, + no management frames, simple fixed header). + Ultra is available as a special socket : socket(AF_IRDA, SOCK_DGRAM, 1); IrDA protocol options CONFIG_IRDA_OPTIONS - Say Y here if you want to configure any of the following IrDA options. + Say Y here if you want to configure any of the following IrDA + options. -IrDA Cache last LSAP +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. + 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 +IrDA Fast RRs 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 @@ -18768,129 +22267,165 @@ If unsure, say N. -IrDA Debug +IrDA debugging information 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 + /proc/sys/net/irda/debug . If unsure, say Y (since it makes it easier to find the bugs). -IrLAP Compression support +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) +IrLAP Deflate compression 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. + 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. + here and read . The module will be + called irda_deflate.o. -IrLAN Protocol +IrLAN protocol CONFIG_IRLAN - Say Y here if you want to build support for the IrLAN protocol. If + Say Y here if you want to build support for the IrLAN protocol. If you want to compile it as a module (irlan.o), 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. + . 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 + 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! -IrNET Protocol +IrNET protocol CONFIG_IRNET - Say Y here if you want to build support for the IrNET protocol. If + Say Y here if you want to build support for the IrNET protocol. If you want to compile it as a module (irnet.o), say M here and read - Documentation/modules.txt. IrNET is a PPP driver, so you will also - need a working PPP subsystem (driver, daemon and config)... + . IrNET is a PPP driver, so you + will also need a working PPP subsystem (driver, daemon and + config)... - IrNET is an alternate way to tranfer TCP/IP traffic over IrDA. It - uses synchronous PPP over a set of point to point IrDA sockets. You + IrNET is an alternate way to tranfer TCP/IP traffic over IrDA. It + uses synchronous PPP over a set of point to point IrDA sockets. You can use it between Linux machine or with W2k. -IrCOMM Protocol +IrCOMM protocol CONFIG_IRCOMM - Say Y here if you want to build support for the IrCOMM protocol. If + Say Y here if you want to build support for the IrCOMM protocol. If you want to compile it as a module (you will get ircomm.o and - ircomm-tty.o), 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. + ircomm-tty.o), say M here and read . + 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. 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 (irtty.o), 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) + discipline. If you want to compile it as a module (irtty.o), say M + here and read . 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 +IrPORT IrDA serial 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 (irport.o), 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. + and read . 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. +USB IrDA FIR dongle Device Driver +CONFIG_USB_IRDA + Say Y here if you want to build support for the USB IrDA FIR Dongle + device driver. If you want to compile it as a module (irda-usb.o), + say M here and read . IrDA-USB + support the various IrDA USB dongles available and most of their + pecularities. Those dongles plug in the USB port of your computer, + are plug and play, and support SIR and FIR (4Mbps) speeds. On the + other hand, those dongles tend to be less efficient than a FIR + chipset. + + Please note that the driver is still experimental. And of course, + you will need both USB and IrDA support in your kernel... + 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. This driver should be used for the IrDA - chipset in the Corel NetWinder. The driver supports SIR, MIR and FIR - (4Mbps) speeds. + W83977AF super-io chipset. This driver should be used for the IrDA + chipset in the Corel NetWinder. The driver supports SIR, MIR and + FIR (4Mbps) speeds. If you want to compile it as a module, say M here and read - Documentation/modules.txt. The module will be called w83977af_ir.o. + . The module will be called + w83977af_ir.o. -NSC PC87108 IrDA Device Driver +NSC PC87108/PC87338 IrDA Device Driver CONFIG_NSC_FIR Say Y here if you want to build support for the NSC PC87108 and - PC87338 IrDA chipsets. This driver supports SIR, - MIR and FIR (4Mbps) speeds. + PC87338 IrDA chipsets. This driver supports SIR, + MIR and FIR (4Mbps) speeds. If you want to compile it as a module, say M here and read - Documentation/modules.txt. The module will be called nsc-ircc.o. + . The module will be called + nsc-ircc.o. -Toshiba Type-O IR Port Device Driver +National Semiconductor DP83820 series driver +CONFIG_NS83820 + This is a driver for the National Semiconductor DP83820 series + of gigabit ethernet MACs. Cards using this chipset include + the D-Link DGE-500T, PureData's PDP8023Z-TG, SMC's SMC9462TX, + SOHO-GA2000T, SOHO-GA2500T. The driver supports the use of + zero copy. + +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. This chipset is used by the Toshiba Libretto 100CT, and - many more laptops. If you want to compile it as a module, say M here - and read Documentation/modules.txt. The module will be called - toshoboe.o. + chipset. This chipset is used by the Toshiba Libretto 100CT, and + many more laptops. If you want to compile it as a module, say M + here and read . The module will be + called toshoboe.o. -SMC IrCC (Experimental) +SMC IrCC CONFIG_SMC_IRCC_FIR Say Y here if you want to build support for the SMC Infrared - Communications Controller. It is used in the Fujitsu Lifebook 635t - and Sony PCG-505TX. If you want to compile it as a module, say M - here and read Documentation/modules.txt. The module will be called - smc-ircc.o. + Communications Controller. It is used in the Fujitsu Lifebook 635t + and Sony PCG-505TX. If you want to compile it as a module, say M + here and read . The module will be + called smc-ircc.o. + +ALi M5123 FIR Controller Driver +CONFIG_ALI_FIR + Say Y here if you want to build support for the ALi M5123 FIR + Controller. The ALi M5123 FIR Controller is embedded in ALi M1543C, + M1535, M1535D, M1535+, M1535D Sourth Bridge. This driver supports + SIR, MIR and FIR (4Mbps) speeds. + + If you want to compile it as a module, say M here and read + . The module will be called + ali-ircc.o. VLSI 82C147 PCI-IrDA Controller Driver CONFIG_VLSI_FIR @@ -18909,69 +22444,76 @@ or M to the driver for your particular dongle below. Note that the answer to this question won't directly affect the - kernel: saying N will just cause this configure script to skip all + kernel: saying N will just cause the configurator to skip all the questions about serial dongles. -ESI JetEye PC Dongle +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 + JetEye PC dongle. If you want to compile it as a module, say M here + and read . 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 start irattach like this: "irattach -d esi". 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 + 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 . 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 start irattach like this: + currently only be used by IrTTY. To activate support for ACTiSYS + dongles you will have to start irattach like this: "irattach -d actisys" or "irattach -d actisys+". 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 start irattach like this: "irattach -d tekram". + 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 + . 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 + start irattach like this: "irattach -d tekram". 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. + dongle. If you want to compile it as a module, say M here and read + . 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 +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 - start irattach like this "irattach -d litelink". + dongle. If you want to compile it as a module, say M here and read + . 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 start irattach like this "irattach -d litelink". Old Belkin dongle CONFIG_OLD_BELKIN_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 - old_belkin.o. Some information is contained in the comments at the - top of drivers/net/irda/old_belkin.c. + and 2000 dongles. If you want to compile it as a module, say M here + and read . The module will be + called old_belkin.o. Some information is contained in the comments + at the top of . 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. + board. Boards currently supported include Motorola boards MVME147, + MVME162, MVME166, MVME167, MVME172, and MVME177. BVME4000 and + BVME6000 boards from BVM Ltd are also supported. + +MVME147 support +CONFIG_MVME147 + Say Y to include support for early Motorola VME boards. This will + build a kernel which can run on MVME147 single-board computers. If + you select this option you will have to select the appropriate + drivers for SCSI, Ethernet and serial ports later on. MVME162, 166 and 167 support CONFIG_MVME16x @@ -19001,6 +22543,16 @@ is hardwired on. The 53c710 SCSI driver is known to suffer from this problem. +WD33C93 SCSI driver for MVME147 +CONFIG_MVME147_SCSI + Support for the on-board SCSI controller on the Motorola MVME147 + single-board computer. + +SCC support for MVME147 serial ports +CONFIG_MVME147_SCC + This is the driver for the serial ports on the Motorola MVME147 + boards. Everyone using one of these boards should say Y here. + NCR53C710 SCSI driver for MVME16x CONFIG_MVME16x_SCSI The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710 @@ -19013,19 +22565,26 @@ SCSI controller chip. Almost everyone using one of these boards will want to say Y to this question. +MVME147 (Lance) Ethernet support +CONFIG_MVME147_NET + Support for the on-board Ethernet interface on the Motorola MVME147 + single-board computer. 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 . + 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. + a module, say M here and read . 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. + and read . CD2401 support for MVME166/7 serial ports CONFIG_SERIAL167 @@ -19052,11 +22611,707 @@ 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 display7seg.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + as a module, say M here and read . If you do not have a CompactPCI model CP1400 or CP1500, or another UltraSPARC-IIi-cEngine boardset with a 7-segment display, - you should say N to this option. + you should say N to this option. + +# Choice: cristype +Etrax-100-LX-v1 +CONFIG_ETRAX100LX + Support version 1 of the Etrax 100LX. + +Etrax-100-LX-v2 +CONFIG_ETRAX100LX_V2 + Support version 2 of the Etrax 100LX. + +Etrax-100-LX-for-xsim-simulator +CONFIG_SVINTO_SIM + Support the xsim ETRAX Simulator. + +DRAM size (dec, in MB) +CONFIG_ETRAX_DRAM_SIZE + Size of DRAM (decimal in MB) typically 2, 8 or 16. + +ETRAX Flash Memory configuration +CONFIG_ETRAX_FLASH_BUSWIDTH + Width in bytes of the Flash bus (1, 2 or 4). Is usually 2. + +LED configuration on PA +CONFIG_ETRAX_PA_LEDS + The Etrax network driver is responsible for flashing LED's when + packets arrive and are sent. It uses macros defined in + , and those macros are defined after what + YOU choose in this option. The actual bits used are configured + separately. Select this if the LEDs are on port PA. Some products + put the leds on PB or a memory-mapped latch (CSP0) instead. + +LED configuration on PB +CONFIG_ETRAX_PB_LEDS + The Etrax network driver is responsible for flashing LED's when + packets arrive and are sent. It uses macros defined in + , and those macros are defined after what + YOU choose in this option. The actual bits used are configured + separately. Select this if the LEDs are on port PB. Some products + put the leds on PA or a memory-mapped latch (CSP0) instead. + +LED configuration on CSP0 +CONFIG_ETRAX_CSP0_LEDS + The Etrax network driver is responsible for flashing LED's when + packets arrive and are sent. It uses macros defined in + , and those macros are defined after what + YOU choose in this option. The actual bits used are configured + separately. Select this if the LEDs are on a memory-mapped latch + using chip select CSP0, this is mapped at 0x90000000. + Some products put the leds on PA or PB instead. + +No LED at all +CONFIG_ETRAX_NO_LEDS + Select this option if you don't have any LED at all. + +First green LED bit +CONFIG_ETRAX_LED1G + Bit to use for the first green LED. + Most Axis products use bit 2 here. + +First red LED bit +CONFIG_ETRAX_LED1R + Bit to use for the first red LED. + Most Axis products use bit 3 here. + For products with only one controllable LED, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Second green LED bit +CONFIG_ETRAX_LED2G + Bit to use for the second green LED. The "Active" LED. + Most Axis products use bit 4 here. + For products with only one controllable LED, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Second red LED bit +CONFIG_ETRAX_LED2R + Bit to use for the second red LED. + Most Axis products use bit 5 here. + For products with only one controllable LED, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Third green LED bit +CONFIG_ETRAX_LED3G + Bit to use for the third green LED. The "Drive" LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Third red LED bit +CONFIG_ETRAX_LED3R + Bit to use for the third red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Fourth green LED bit +CONFIG_ETRAX_LED4G + Bit to use for the fourth green LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Fourth red LED bit +CONFIG_ETRAX_LED4R + Bit to use for the fourth red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Fifth green LED bit +CONFIG_ETRAX_LED5G + Bit to use for the fifth green LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Fifth red LED bit +CONFIG_ETRAX_LED5R + Bit to use for the fifth red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Sixth green LED bit +CONFIG_ETRAX_LED6G + Bit to use for the sixth green LED. The "Drive" LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Sixth red LED bit +CONFIG_ETRAX_LED6R + Bit to use for the sixth red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Seventh green LED bit +CONFIG_ETRAX_LED7G + Bit to use for the seventh green LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Seventh red LED bit +CONFIG_ETRAX_LED7R + Bit to use for the seventh red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Eighth yellow LED bit +CONFIG_ETRAX_LED8Y + Bit to use for the eighth yellow LED. The "Drive" LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Ninth yellow LED bit +CONFIG_ETRAX_LED9Y + Bit to use for the ninth yellow LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Tenth yellow LED bit +CONFIG_ETRAX_LED10Y + Bit to use for the tenth yellow LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Eleventh yellow LED bit +CONFIG_ETRAX_LED11Y + Bit to use for the eleventh yellow LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Twelfth red LED bit +CONFIG_ETRAX_LED12R + Bit to use for the twelfth red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +Flash LED off during activity +CONFIG_ETRAX_LED_OFF_DURING_ACTIVITY + This option allows you to decide whether the network LED (and + Bluetooth LED in case you use Bluetooth) will be on or off when + the network is connected, and whether it should flash off or on + when there is activity. If you say y to this option the network + LED will be lit when there is a connection, and will flash off + when there is activity. + +PA button configuration +CONFIG_ETRAX_PA_BUTTON_BITMASK + This is a bitmask with information about what bits on PA that + are used for buttons. + Most products has a so called TEST button on PA1, if that's true + use 02 here. + Use 00 if there are no buttons on PA. + If the bitmask is <> 00 a button driver will be included in the gpio + driver. Etrax general I/O support must be enabled. + +PA changeable direction bits +CONFIG_ETRAX_PA_CHANGEABLE_DIR + This is a bitmask with information of what bits in PA that a user + can change direction on using ioctl's. + Bit set = changeable. + You probably want 00 here. + +PA changeable data bits +CONFIG_ETRAX_PA_CHANGEABLE_BITS + This is a bitmask with information of what bits in PA that a user + can change change the value on using ioctl's. + Bit set = changeable. + You probably want 00 here. + +PA changeable direction bits +CONFIG_ETRAX_PB_CHANGEABLE_DIR + This is a bitmask with information of what bits in PB that a user + can change direction on using ioctl's. + Bit set = changeable. + You probably want 00 here. + +PB changeable data bits +CONFIG_ETRAX_PB_CHANGEABLE_BITS + This is a bitmask with information of what bits in PB that a user + can change the value on using ioctl's. + Bit set = changeable. + You probably want 00 here. + +Kernel debugger (kgdb) +CONFIG_ETRAX_KGDB + The CRIS version of gdb can be used to remotely debug a running + Linux kernel via the serial debug port. Provided you have gdb-cris + installed, run gdb-cris vmlinux, then type + + (gdb) set remotebaud 115200 <- kgdb uses 115200 as default + (gdb) target remote /dev/ttyS0 <- maybe you use another port + + This should connect you to your booted kernel (or boot it now if you + didn't before). The kernel halts when it boots, waiting for gdb if + this option is turned on! + +Etrax bus waitstates +CONFIG_ETRAX_DEF_R_WAITSTATES + Waitstates for SRAM, Flash and peripherials (not DRAM). 95f8 is a + good choice for most Axis products... + +Etrax bus configuration +CONFIG_ETRAX_DEF_R_BUS_CONFIG + Assorted bits controlling write mode, DMA burst length etc. 104 is + a good choice for most Axis products... + +Etrax SDRAM configuration +CONFIG_ETRAX_SDRAM + Enable this if you use SDRAM chips and configure + R_SDRAM_CONFIG and R_SDRAM_TIMING as well. + +DRAM size (dec, in MB) +CONFIG_ETRAX_DEF_R_DRAM_CONFIG + The R_DRAM_CONFIG register specifies everything on how the DRAM + chips in the system are connected to the Etrax CPU. This is + different depending on the manufacturer, chip type and number of + chips. So this value often needs to be different for each Axis + product. + +Etrax DRAM timing +CONFIG_ETRAX_DEF_R_DRAM_TIMING + Different DRAM chips have different speeds. Current Axis products + use 50ns DRAM chips which can use the timing: 5611. + +Etrax SDRAM configuration +CONFIG_ETRAX_DEF_R_SDRAM_CONFIG + The R_SDRAM_CONFIG register specifies everything on how the SDRAM + chips in the system are connected to the Etrax CPU. This is + different depending on the manufacturer, chip type and number of + chips. So this value often needs to be different for each Axis + product. + +Etrax SDRAM timing +CONFIG_ETRAX_DEF_R_SDRAM_TIMING + Different SDRAM chips have different timing. + +Etrax General port A direction +CONFIG_ETRAX_DEF_R_PORT_PA_DIR + Configures the direction of general port A bits. 1 is out, 0 is in. + This is often totally different depending on the product used. + There are some guidelines though - if you know that only LED's are + connected to port PA, then they are usually connected to bits 2-4 + and you can therefore use 1c. On other boards which don't have the + LED's at the general ports, these bits are used for all kinds of + stuff. If you don't know what to use, it is always safe to put all + as inputs, although floating inputs isn't good. + +Etrax General port A data +CONFIG_ETRAX_DEF_R_PORT_PA_DATA + Configures the initial data for the general port A bits. Most + products should use 00 here. + +Etrax General port B config +CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG + Configures the type of the general port B bits. 1 is chip select, + 0 is port. Most products should use 00 here. + +Etrax General port B direction +CONFIG_ETRAX_DEF_R_PORT_PB_DIR + Configures the direction of general port B bits. 1 is out, 0 is in. + This is often totally different depending on the product used. Bits + 0 and 1 on port PB are usually used for I2C communication, but the + kernel I2C driver sets the appropriate directions itself so you + don't need to take that into consideration when setting this option. + If you don't know what to use, it is always safe to put all as + inputs. + +Etrax General port B data +CONFIG_ETRAX_DEF_R_PORT_PB_DATA + Configures the initial data for the general port A bits. Most + products should use FF here. + +Etrax General port device +CONFIG_ETRAX_GPIO + Enables the Etrax general port device (major 120, minors 0 and 1). + You can use this driver to access the general port bits. It supports + these ioctl's: + #include + fd = open("/dev/gpioa", O_RDWR); // or /dev/gpiob + ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETBITS), bits_to_set); + ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), bits_to_clear); + val = ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_READBITS), NULL); + Remember that you need to setup the port directions appropriately in + the General configuration. + +Etrax parallel data support +CONFIG_ETRAX_PARDATA + Adds support for writing data to the parallel port par0 of the ETRAX + 100. If you create a character special file with major number 126, + you can write to the data bits of par0. + Note: you need to disable Etrax100 parallel port support. + +Etrax parallel LCD (HD44780) Driver +CONFIG_ETRAX_LCD_HD44780 + Adds support for a HD44780 controlled LCD connected to the parallel + port par0 of the Etrax. + +Etrax Serial port ser0 support +CONFIG_ETRAX_SERIAL + Enables the ETRAX 100 serial driver for ser0 (ttyS0) + You probably want this enabled. + +/proc/serial entry +CONFIG_ETRAX_SERIAL_PROC_ENTRY + Enables /proc/serial entry where errors and statistics can be + viewed. CONFIG_PROC_FS must also be set for this to work. + +Etrax Serial port fast flush of DMA using fast timer API +CONFIG_ETRAX_SERIAL_FAST_TIMER + Select this to have the serial DMAs flushed at a higher rate than + normally, possible by using the fast timer API, the timeout is + approx. 4 character times. + If unsure, say N. + +Etrax Serial port fast flush of DMA +CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST + Select this to have the serial DMAs flushed at a higher rate than + normally possible through a fast timer interrupt (currently at + 15360 Hz). + If unsure, say N. + +Etrax Serial port receive flush timeout +CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS + Number of timer ticks between flush of receive fifo (1 tick = 10ms). + Try 0-3 for low latency applications. Approx 5 for high load + applications (e.g. PPP). Maybe this should be more adaptive some + day... + +Etrax Serial port ser0 DTR, RI, DSR and CD support on PB +CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB + Enables the status and control signals DTR, RI, DSR and CD on PB for + ser0. + +Serial port 1 enabled +CONFIG_ETRAX_SERIAL_PORT1 + Enables the ETRAX 100 serial driver for ser1 (ttyS1). + +Etrax Serial port ser1 DTR, RI, DSR and CD support on PB +CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB + Enables the status and control signals DTR, RI, DSR and CD on PB for + ser1. + +Serial port 2 enabled +CONFIG_ETRAX_SERIAL_PORT2 + Enables the ETRAX 100 serial driver for ser2 (ttyS2). + +Etrax Serial port ser2 DTR, RI, DSR and CD support on PA +CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA + Enables the status and control signals DTR, RI, DSR and CD on PA for + ser2. + +Serial port 3 enabled +CONFIG_ETRAX_SERIAL_PORT3 + Enables the ETRAX 100 serial driver for ser3 (ttyS3). + +Etrax100 RS-485 support +CONFIG_ETRAX_RS485 + Enables support for RS-485 serial communication. For a primer on + RS-485, see . + +Etrax100 RS-485 mode on PA +CONFIG_ETRAX_RS485_ON_PA + Control Driver Output Enable on RS485 tranceiver using a pin on PA + port: + Axis 2400/2401 uses PA 3. + +Etrax100 RS-485 mode on PA bit +CONFIG_ETRAX_RS485_ON_PA_BIT + Control Driver Output Enable on RS485 tranceiver using a this bit + on PA port. + +Ser0 DTR on PB bit +CONFIG_ETRAX_SER0_DTR_ON_PB_BIT + Specify the pin of the PB port to carry the DTR signal for serial + port 0. + +Ser0 RI on PB bit +CONFIG_ETRAX_SER0_RI_ON_PB_BIT + Specify the pin of the PB port to carry the RI signal for serial + port 0. + +Ser0 DSR on PB bit +CONFIG_ETRAX_SER0_DSR_ON_PB_BIT + Specify the pin of the PB port to carry the DSR signal for serial + port 0. + +Ser0 CD on PB bit +CONFIG_ETRAX_SER0_CD_ON_PB_BIT + Specify the pin of the PB port to carry the CD signal for serial + port 0. + +Ser1 DTR on PB bit +CONFIG_ETRAX_SER1_DTR_ON_PB_BIT + Specify the pin of the PB port to carry the DTR signal for serial + port 1. + +Ser1 RI on PB bit +CONFIG_ETRAX_SER1_RI_ON_PB_BIT + Specify the pin of the PB port to carry the RI signal for serial + port 1. + +Ser1 DSR on PB bit +CONFIG_ETRAX_SER1_DSR_ON_PB_BIT + Specify the pin of the PB port to carry the DSR signal for serial + port 1. + +Ser1 CD on PB bit +CONFIG_ETRAX_SER1_CD_ON_PB_BIT + Specify the pin of the PB port to carry the CD signal for serial + port 1. + +Ser2 DTR on PA bit +CONFIG_ETRAX_SER2_DTR_ON_PA_BIT + Specify the pin of the PA port to carry the DTR signal for serial + port 2. + +Ser2 RI on PA bit +CONFIG_ETRAX_SER2_RI_ON_PA_BIT + Specify the pin of the PA port to carry the RI signal for serial + port 2. + +Ser2 DSR on PA bit +CONFIG_ETRAX_SER2_DSR_ON_PA_BIT + Specify the pin of the PA port to carry the DTR signal for serial + port 2. + +Ser2 CD on PA bit +CONFIG_ETRAX_SER2_CD_ON_PA_BIT + Specify the pin of the PA port to carry the CD signal for serial + port 2. + +Etrax100 RS-485 disable receiver +CONFIG_ETRAX_RS485_DISABLE_RECEIVER + It's necessary to disable the serial receiver to avoid serial + loopback. Not all products are able to do this in software only. + Axis 2400/2401 must disable receiver. + +Etrax100 I2C Support +CONFIG_ETRAX_I2C + Enables an I2C driver on PB0 and PB1 on ETRAX100. + EXAMPLE usage: + i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val); + ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg); + i2c_arg = I2C_READARG(STA013_READ_ADDR, reg); + val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg); + +Etrax100 I2C configuration +CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C + Select whether to use the special I2C mode in the PB I/O register or + not. This option needs to be selected in order to use some drivers + that access the I2C I/O pins directly instead of going through the + I2C driver, like the DS1302 realtime-clock driver. If you are + uncertain, choose Y here. + +Etrax100 I2C EEPROM (NVRAM) support +CONFIG_ETRAX_I2C_EEPROM + Enables I2C EEPROM (non-volatile RAM) on PB0 and PB1 using the I2C + driver. Select size option: Probed, 2k, 8k, 16k. + (Probing works for 2k and 8k but not that well for 16k) + +Etrax100 I2C EEPROM (NVRAM) size/16kB +CONFIG_ETRAX_I2C_EEPROM_16KB + Use a 16kB EEPROM. + +Etrax100 I2C EEPROM (NVRAM) size/2kB +CONFIG_ETRAX_I2C_EEPROM_2KB + Use a 2kB EEPROM. + +Etrax100 I2C EEPROM (NVRAM) size/8kB +CONFIG_ETRAX_I2C_EEPROM_8KB + Use a 8kB EEPROM. + +Etrax100 I2C EEPROM (NVRAM) size/probe +CONFIG_ETRAX_I2C_EEPROM_PROBE + Specifies size or auto probe of the EEPROM size. + Options: Probed, 2k, 8k, 16k. + (Probing works for 2k and 8k but not that well for 16k) + +Etrax DS1302 Real-Time Clock driver +CONFIG_ETRAX_DS1302 + Enables the driver for the DS1302 Real-Time Clock battery-backed + chip on some products. The kernel reads the time when booting, and + the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a + rtc_time struct (see ) on the /dev/rtc + device, major 121. You can check the time with cat /proc/rtc, but + normal time reading should be done using libc function time and + friends. + +Etrax DS1302 RST on the Generic Port +CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + If your product has the RST signal line for the DS1302 RTC on the + Generic Port then say Y here, otherwise leave it as N in which + case the RST signal line is assumed to be connected to Port PB + (just like the SCL and SDA lines). + +Etrax DS1302 RST bit number +CONFIG_ETRAX_DS1302_RSTBIT + This is the bit number for the RST signal line of the DS1302 RTC on + the selected port. If you have selected the generic port then it + should be bit 27, otherwise your best bet is bit 5. + +Etrax DS1302 SCL bit number +CONFIG_ETRAX_DS1302_SCLBIT + This is the bit number for the SCL signal line of the DS1302 RTC on + Port PB. This is probably best left at 3. + +Etrax DS1302 SDA bit number +CONFIG_ETRAX_DS1302_SDABIT + This is the bit number for the SDA signal line of the DS1302 RTC on + Port PB. This is probably best left at 2. + +Etrax 100 IDE Reset +CONFIG_ETRAX_IDE_CSP0_8_RESET + Configures the pin used to reset the IDE bus. + +Etrax 100 IDE Reset +CONFIG_ETRAX_IDE_CSPE1_16_RESET + Configures the pin used to reset the IDE bus. + +Etrax 100 ATA/IDE support +CONFIG_ETRAX_IDE_DELAY + Sets the time to wait for disks to regain consciousness after reset. + +Etrax 100 IDE Reset +CONFIG_ETRAX_IDE_G27_RESET + Configures the pin used to reset the IDE bus. + +IDE reset on PB Bit 7 +CONFIG_ETRAX_IDE_PB7_RESET + Configures the pin used to reset the IDE bus. + +USB 1.1 host +CONFIG_ETRAX_USB_HOST + This option enables the host functionality of the ETRAX 100LX + built-in USB controller. In host mode the controller is designed + for CTRL and BULK traffic only, INTR traffic may work as well + however (depending on the requirements of timeliness). + +USB 1.1 host port 1 enabled +CONFIG_ETRAX_USB_HOST_PORT1 + This option enables port 1 of the ETRAX 100LX USB root hub (RH). + +USB 1.1 host port 2 enabled +CONFIG_ETRAX_USB_HOST_PORT2 + This option enables port 2 of the ETRAX 100LX USB root hub (RH). + +ETRAX 100LX 10/100Mbit Ethernet controller +CONFIG_ETRAX_ETHERNET + This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet + controller. + +ETRAX 100LX Synchronous serial ports +CONFIG_ETRAX_SYNCHRONOUS_SERIAL + This option enables support for the ETRAX 100LX built-in + synchronous serial ports. These ports are used for continuous + streamed data like audio. The default setting is compatible + with the STA 013 MP3 decoder, but can easily be tuned to fit + any other audio encoder/decoder and SPI. + +ETRAX 100LX Synchronous serial port 0 enabled +CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0 + Enables the ETRAX 100LX synchronous serial port 0 (syncser0). + +ETRAX 100LX Synchronous serial port 0 uses DMA +CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA + Makes synchronous serial port 0 use DMA. + +ETRAX 100LX Synchronous serial port 1 enabled +CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1 + Enables the ETRAX 100LX synchronous serial port 1 (syncser1). + +ETRAX 100LX Synchronous serial port 1 uses DMA +CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA + Makes synchronous serial port 1 use DMA. + +Delay for drives to regain consciousness +CONFIG_IDE_DELAY + Number of seconds to wait for IDE drives to spin up after an IDE + reset. + +ARTPEC-1 support +CONFIG_JULIETTE + The ARTPEC-1 is a video-compression chip used in the AXIS 2100 + network camera, which is built around an ETRAX-100 board. With this + option selected, the ETRAX kernel configures a DMA channel at boot + time to talk to the chip. + +Axis flash-map support +CONFIG_ETRAX_AXISFLASHMAP + This option enables MTD mapping of flash devices. Needed to use + flash memories. If unsure, say Y. + +Byte-offset of partition table sector +CONFIG_ETRAX_PTABLE_SECTOR + Byte-offset of the partition table in the first flash chip. + The default value is 64kB and should not be changed unless + you know exactly what you are doing. The only valid reason + for changing this is when the flash block size is bigger + than 64kB (e.g. when using two parallel 16 bit flashes). + +Enable Etrax100 watchdog +CONFIG_ETRAX_WATCHDOG + Enable the built-in watchdog timer support on Etrax100 embedded + network computers. + +# Choice: crisdebug +Serial-0 +CONFIG_ETRAX_DEBUG_PORT0 + Choose a serial port for the ETRAX debug console. Default to + port 0. + +Etrax debug port on ser1 +CONFIG_ETRAX_DEBUG_PORT1 + Use serial port 1 for the console. + +Etrax debug port on ser2 +CONFIG_ETRAX_DEBUG_PORT2 + Use serial port 2 for the console. + +Etrax debug port on ser3 +CONFIG_ETRAX_DEBUG_PORT3 + Use serial port 3 for the console. + +No Etrax debug port +CONFIG_ETRAX_DEBUG_PORT_NULL + Disable serial-port debugging. + +Parallel port support +CONFIG_ETRAX_PARPORT + Say Y here to enable the ETRAX on-board parallel ports. + +Parallel port 0 enabled +CONFIG_ETRAX_PARALLEL_PORT0 + Say Y here to enable parallel port 0. + +Parallel port 1 enabled +CONFIG_ETRAX_PARALLEL_PORT1 + Say Y here to enable parallel port 1. + +# Choice: crisrescue +Select a product rescue port +CONFIG_ETRAX_RESCUE_SER0 + Select one of the four serial ports as a rescue port. The default + is port 0. + +Serial-1 +CONFIG_ETRAX_RESCUE_SER1 + Use serial port 1 as the rescue port. + +Serial-2 +CONFIG_ETRAX_RESCUE_SER2 + Use serial port 2 as the rescue port. + +Serial-3 +CONFIG_ETRAX_RESCUE_SER3 + Use serial port 3 as the rescue port. + +RIO Hardware Watchdog support +CONFIG_WATCHDOG_RIO + Say Y here to support the hardware watchdog capability on Sun RIO + machines. The watchdog timeout period is normally one minute but + can be changed with a boot-time parameter. CP1XXX Hardware Watchdog support CONFIG_WATCHDOG_CP1XXX @@ -19066,12 +23321,22 @@ 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 cpwatchdog.o. If you want to compile it - as a module, say M here and read Documentation/modules.txt. + as a module, say M here and read . If you do not have a CompactPCI model CP1400 or CP1500, or another UltraSPARC-IIi-cEngine boardset with hardware watchdog, - you should say N to this option. + you should say N to this option. + +# Choice: ia64type +Itanium +CONFIG_ITANIUM + Select your IA64 processor type. The default is Intel Itanium. + +McKinley +CONFIG_MCKINLEY + Select this to configure for a McKinley processor. +# Choice: ia64system IA-64 system type CONFIG_IA64_GENERIC This selects the system type of your hardware. A "generic" kernel @@ -19079,19 +23344,21 @@ a kernel for your specific system, it will be faster and smaller. To find out what type of IA-64 system you have, you may want to - check the IA-64 Linux web site at http://www.linux-ia64.org/. + check the IA-64 Linux web site at . As of the time of this writing, most hardware is DIG compliant, so the "DIG-compliant" option is usually the right choice. - HP-simulator For the HP simulator (http://software.hp.com/ia64linux/). + HP-simulator For the HP simulator + (). SN1-simulator For the SGI SN1 simulator. - DIG-compliant For DIG ("Developer's Interface Guide") compliant system. + DIG-compliant For DIG ("Developer's Interface Guide") compliant + system. If you don't know what to do, choose "generic". +# Choice: pagesize Kernel page size CONFIG_IA64_PAGE_SIZE_4KB - This lets you select the page size of the kernel. For best IA-64 performance, a page size of 8KB or 16KB is recommended. For best IA-32 compatibility, a page size of 4KB should be selected (the vast @@ -19109,8 +23376,8 @@ Enable Itanium A-step specific code CONFIG_ITANIUM_ASTEP_SPECIFIC Select this option to build a kernel for an Itanium prototype system - with an A-step CPU. You have an A-step CPU if the "revision" field in - /proc/cpuinfo is 0. + with an A-step CPU. You have an A-step CPU if the "revision" field + in /proc/cpuinfo is 0. Enable Itanium B-step specific code CONFIG_ITANIUM_BSTEP_SPECIFIC @@ -19120,9 +23387,33 @@ Enable Itanium B0-step specific code CONFIG_ITANIUM_B0_SPECIFIC - Select this option to bild a kernel for an Itanium prototype system - with a B0-step CPU. You have a B0-step CPU if the "revision" field in - /proc/cpuinfo is 1. + Select this option to build a kernel for an Itanium prototype system + with a B0-step CPU. You have a B0-step CPU if the "revision" field + in /proc/cpuinfo is 1. + +Enable Itanium C-step specific code +CONFIG_ITANIUM_CSTEP_SPECIFIC + Select this option to build a kernel for an Itanium prototype system + with a C-step CPU. You have a C-step CPU if the "revision" field in + /proc/cpuinfo is in the range of 5 to 8. + +Enable Itanium B1-step specific code +CONFIG_ITANIUM_B1_SPECIFIC + Select this option to build a kernel for an Itanium prototype system + with a B1-step CPU. You have a B1-step CPU if the "revision" field + in /proc/cpuinfo is 2. + +Enable Itanium B2-step specific code +CONFIG_ITANIUM_B2_SPECIFIC + Select this option to build a kernel for an Itanium prototype system + with a B2-step CPU. You have a B2-step CPU if the "revision" field + in /proc/cpuinfo is 3. + +Enable Itanium C0-step specific code +CONFIG_ITANIUM_C0_SPECIFIC + Select this option to build a kernel for an Itanium prototype system + with a C0-step CPU. You have a C0-step CPU if the "revision" field + in /proc/cpuinfo is 5. Force interrupt redirection CONFIG_IA64_HAVE_IRQREDIR @@ -19130,38 +23421,56 @@ redirect interrupts to different CPUs. Select N here if you're unsure. -Enable use of global TLB purge instruction (ptc.g) -CONFIG_ITANIUM_PTCG - Say Y here if you want the kernel to use the IA-64 "ptc.g" - instruction to flush the TLB on all CPUs. Select N here if - you're unsure. - -Enable SoftSDV hacks -CONFIG_IA64_SOFTSDV_HACKS - Say Y here to enable hacks to make the kernel work on the Intel - SoftSDV simulator. Select N here if you're unsure. - -Enable AzusA hacks -CONFIG_IA64_AZUSA_HACKS - Say Y here to enable hacks to make the kernel work on the NEC - AzusA platform. Select N here if you're unsure. - -Force socket buffers below 4GB? -CONFIG_SKB_BELOW_4GB - Most of today's network interface cards (NICs) support DMA to - the low 32 bits of the address space only. On machines with - more then 4GB of memory, this can cause the system to slow - down if there is no I/O TLB hardware. Turning this option on - avoids the slow-down by forcing socket buffers to be allocated - from memory below 4GB. The downside is that your system could - run out of memory below 4GB before all memory has been used up. - If you're unsure how to answer this question, answer Y. - Enable IA-64 Machine Check Abort CONFIG_IA64_MCA Say Y here to enable machine check support for IA-64. If you're unsure, answer Y. +Disable IA-64 Virtual Hash Page Table +CONFIG_DISABLE_VHPT + The Virtual Hash Page Table (VHPT) enhances virtual address + translation performance. Normally you want the VHPT active but you + can select this option to disable the VHPT for debugging. If you're + unsure, answer N. + +Enable McKinley A-step specific code +CONFIG_MCKINLEY_ASTEP_SPECIFIC + Select this option to build a kernel for an IA64 McKinley system + with any A-stepping CPU. + +Enable McKinley A0/A1-step specific code +CONFIG_MCKINLEY_A0_SPECIFIC + Select this option to build a kernel for an IA64 McKinley system + with an A0 or A1 stepping CPU. + +Turn on compare-and-exchange bug checking (slow!) +CONFIG_IA64_DEBUG_CMPXCHG + Selecting this option turns on bug checking for the IA64 + compare-and-exchange instructions. This is slow! Itaniums + from step B3 or later don't have this problem. If you're unsure, + select N. + +IA64 IRQ bug checking +CONFIG_IA64_DEBUG_IRQ + Selecting this option turns on bug checking for the IA64 irq_save + and restore instructions. It's useful for tracking down spinlock + problems, but slow! If you're unsure, select N. + +Early printk support (requires VGA!) +CONFIG_IA64_EARLY_PRINTK + Selecting this option uses the VGA screen for printk() output before + the consoles are initialised. It is useful for debugging problems + early in the boot process, but only if you have a VGA screen + attached. If you're unsure, select N. + +Print possible IA64 hazards to console +CONFIG_IA64_PRINT_HAZARDS + Selecting this option prints more information for Illegal Dependency + Faults, that is, for Read after Write, Write after Write or Write + after Read violations. This option is ignored if you are compiling + for an Itanium A step processor (CONFIG_ITANIUM_ASTEP_SPECIFIC). If + you're unsure, select Y. + Performance monitor support CONFIG_PERFMON Selects whether support for the IA-64 performance monitor hardware @@ -19179,12 +23488,416 @@ To use this option, you have to check that the "/proc file system support" (CONFIG_PROC_FS) is enabled, too. +Kernel support for IA-32 emulation +CONFIG_IA32_SUPPORT + IA64 processors can run IA32 (that is, x86) binaries by emulating + the IA32 instruction set. Say Y here to build in kernel support for + this. If in doubt, say Y. + +/proc/efi/vars support +CONFIG_IA64_EFIVARS + If you say Y here, you are able to get EFI (Extensible Firmware + Interface) variable information in /proc/efi/vars. You may read, + write, create, and destroy EFI variables through this interface. + + To use this option, you have to check that the "/proc file system + support" (CONFIG_PROC_FS) is enabled, too. + +Directly Connected Compact Flash support +CONFIG_CF_ENABLER + Compact Flash is a small, removable mass storage device introduced + in 1994 originally as a PCMCIA device. If you say `Y' here, you + compile in support for Compact Flash devices directly connected to + a SuperH processor. A Compact Flash FAQ is available at + . + + If your board has "Directly Connected" CompactFlash at area 5 or 6, + you may want to enable this option. Then, you can use CF as + primary IDE drive (only tested for SanDisk). + + If in doubt, select 'N'. + +Kernel debugging +CONFIG_DEBUG_KERNEL + Say Y here if you are developing drivers or trying to debug and + identify kernel problems. + +Debug memory allocations +CONFIG_DEBUG_SLAB + Say Y here to have the kernel do limited verification on memory + allocation as well as poisoning memory on free to catch use of freed + memory. + +Memory mapped I/O debug support +CONFIG_DEBUG_IOVIRT + Say Y here to get warned whenever an attempt is made to do I/O on + obviously invalid addresses such as those generated when ioremap() + calls are forgotten. Memory mapped I/O will go through an extra + check to catch access to unmapped ISA addresses, an access method + that can still be used by old drivers that are being ported from + 2.0/2.2. + +Spinlock debugging +CONFIG_DEBUG_SPINLOCK + Say Y here and build SMP to catch missing spinlock initialization + and certain other kinds of spinlock errors commonly made. This is + best used in conjunction with the NMI watchdog so that spinlock + deadlocks are also debuggable. + +Verbose BUG() reporting (adds 70K) +CONFIG_DEBUG_BUGVERBOSE + Say Y here to make BUG() panics output the file name and line number + of the BUG call as well as the EIP and oops trace. This aids + debugging but costs about 70-100K of memory. + +Include kgdb kernel debugger +CONFIG_KGDB + Include in-kernel hooks for kgdb, the Linux kernel source level + debugger. This project has a web page at + . + +Include xmon kernel debugger +CONFIG_XMON + Include in-kernel hooks for the xmon kernel monitor/debugger + supported by the PPC port. + +Include kgdb kernel debugger +CONFIG_KWDB + Include in-kernel hooks for kdb, the source level debugger for the + PA-RISC port. + +IODC console +CONFIG_IODC_CONSOLE + IODC is HP's pre-PCI standard for device identification (a la PCI + vendor, device IDs), detection, configuration, initialization and so + on. It also can provide firmware function to do the actual IO, + which are slow, not really defined for runtime usage and generally + not desirable. + + See + for the gory details. + + Say Y here to enable use of the IODC firmware functions for console + I/O. This is only useful on older PA-RISC workstations. If in + doubt, say Y. + +U2/Uturn I/O MMU +CONFIG_IOMMU_CCIO + Say Y here to enable DMA management routines for the first + generation of PA-RISC cache-coherent machines. Programs the + U2/Uturn chip in "Virtual Mode" and use the I/O MMU. + +LBA/Elroy PCI support +CONFIG_PCI_LBA + Say Y here to give the PA-RISC kernel access to PCI configuration + and IO-port space on PA-RISC workstations equipped with a Lower Bus + Adapter (LBA). This includes A, B, C, J, L, and N-class machines + with 4-digit model numbers, also the A300. + +LASI I/O support +CONFIG_GSC_LASI + Say Y here to directly support the LASI controller chip found on + PA-RISC workstations. Linux-oriented documentation for this chip + can be found at . + +LASI/ASP builtin parallel-port +CONFIG_PARPORT_GSC + Say Y here to build in low-level parallel-support for PC-style + hardware integrated in the LASI-Controller (on the GSC Bus) for + HP-PARISC workstations. + +Fujitsu Vendor Specific +CONFIG_BLK_DEV_IDEDISK_FUJITSU + Enable vendor-specific code for Fujitsu IDE disks. Unless you are + the IDE maintainer, you probably do not want to mess with this. + +IBM Vendor Specific +CONFIG_BLK_DEV_IDEDISK_IBM + Enable vendor-specific code for IBM IDE disks. Unless you are the + IDE maintainer, you probably do not want to mess with this. + +Maxtor Vendor Specific +CONFIG_BLK_DEV_IDEDISK_MAXTOR + Enable vendor-specific code for Maxtor IDE disks. Unless you are + the IDE maintainer, you probably do not want to mess with this. + +Quantum Vendor Specific +CONFIG_BLK_DEV_IDEDISK_QUANTUM + Enable vendor-specific code for Quantum IDE disks. Unless you are + the IDE maintainer, you probably do not want to mess with this. + +Seagate Vendor Specific +CONFIG_BLK_DEV_IDEDISK_SEAGATE + Enable vendor-specific code for Seagate IDE disks. Unless you are + the IDE maintainer, you probably do not want to mess with this. + +Western Digital Vendor Specific +CONFIG_BLK_DEV_IDEDISK_WD + Enable vendor-specific code for Western Digital IDE disks. Unless + you are the IDE maintainer, you probably do not want to mess with + this. + +TiVo Commerial Application Specific +CONFIG_BLK_DEV_TIVO + Enable vendor-specific code for TiVo IDE disks. Unless you are the + IDE maintainer, you probably do not want to mess with this. + +# Choice: superhsys +Generic +CONFIG_SH_GENERIC + Select Generic if configuring for a generic SuperH system. + The "generic" option compiles in *all* the possible hardware + support and relies on the sh_mv= kernel commandline option to choose + at runtime which routines to use. "MV" stands for "machine vector"; + each of the machines below is described by a machine vector. + + Select SolutionEngine if configuring for a Hitachi SH7709 + or SH7750 evalutation board. + + Select Overdrive if configuring for a ST407750 Overdrive board. + More information at + . + + Select HP620 if configuring for a HP Jornada HP620. + More information (hardware only) at + . + + Select HP680 if configuring for a HP Jornada HP680. + More information (hardware only) at + . + + Select HP690 if configuring for a HP Jornada HP690. + More information (hardware only) at + . + + Select CqREEK if configuring for a CqREEK SH7708 or SH7750. + More information at + . + + Select DMIDA if configuring for a DataMyte 4000 Industrial + Digital Assistant. More information at . + + Select EC3104 if configuring for a system with an Eclipse + International EC3104 chip, e.g. the Harris AD2000. + + Select Dreamcast if configuring for a SEGA Dreamcast. + More information at + . There is a + Dreamcast project is at . + + Select BareCPU if you know what this means, and it applies + to your system. + +SolutionEngine +CONFIG_SH_SOLUTION_ENGINE + Select SolutionEngine if configuring for a Hitachi SH7709 + or SH7750 evalutation board. + +7751 SolutionEngine +CONFIG_SH_7751_SOLUTION_ENGINE + Select 7751 SolutionEngine if configuring for a Hitachi SH7751 + evalutation board. + +Overdrive +CONFIG_SH_OVERDRIVE + Select Overdrive if configuring for a ST407750 Overdrive board. + More information at + . + +HP620 +CONFIG_SH_HP620 + Select HP620 if configuring for a HP jornada HP620. + More information (hardware only) at + . + +HP680 +CONFIG_SH_HP680 + Select HP680 if configuring for a HP Jornada HP680. + More information (hardware only) at + . + +HP690 +CONFIG_SH_HP690 + Select HP690 if configuring for a HP Jornada HP690. + More information (hardware only) + at . + +CqREEK +CONFIG_SH_CQREEK + Select CqREEK if configuring for a CqREEK SH7708 or SH7750. + More information at + . + +DMIDA +CONFIG_SH_DMIDA + Select DMIDA if configuring for a DataMyte 4000 Industrial + Digital Assistant. More information at . + +EC3104 +CONFIG_SH_EC3104 + Select EC3104 if configuring for a system with an Eclipse + International EC3104 chip, e.g. the Harris AD2000. + +Dreamcast +CONFIG_SH_DREAMCAST + Select Dreamcast if configuring for a SEGA Dreamcast. + More information at + . There is a + Dreamcast project is at . + +BareCPU +CONFIG_SH_UNKNOWN + "Bare CPU" aka "unknown" means an SH-based system which is not one + of the specific ones mentioned above, which means you need to enter + all sorts of stuff like CONFIG_MEMORY_START because the config + system doesn't already know what it is. You get a machine vector + without any platform-specific code in it, so things like the RTC may + not work. + + This option is for the early stages of porting to a new machine. + +# Choice: superhtype +SH7707 +CONFIG_CPU_SUBTYPE_SH7707 + Select the type of SuperH processor you have. + + Select SH7707 if you have a 60 Mhz SH-3 HD6417707 CPU. + + Select SH7708 if you have a 60 Mhz SH-3 HD6417708S or + if you have a 100 Mhz SH-3 HD6417708R CPU. + + Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU. + + Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU. + +SH7708 +CONFIG_CPU_SUBTYPE_SH7708 + Select SH7708 if you have a 60 Mhz SH-3 HD6417708S or + if you have a 100 Mhz SH-3 HD6417708R CPU. + +SH7709 +CONFIG_CPU_SUBTYPE_SH7709 + Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU. + +SH7750 +CONFIG_CPU_SUBTYPE_SH7750 + Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU. + +Physical memory start address +CONFIG_MEMORY_START + The physical memory start address will be automatically + set to 08000000, unless you selected one of the following + processor types: SolutionEngine, Overdrive, HP620, HP680, HP690, + in which case the start address will be set to 0c000000. + + Tweak this only when porting to a new machine which is not already + known by the config system. Changing it from the known correct + value on any of the known systems will only lead to disaster. + +Hitachi HD64461 companion chip support +CONFIG_HD64461 + The Hitachi HD64461 provides an interface for + the SH7709 CPU, supporting a LCD controller, + CRT color controller, IrDA up to 4 Mbps, and a + PCMCIA controller supporting 2 slots. + + More information is available at + . + + Say Y if you want support for the HD64461. + Otherwise, say N. + +HD64461 PCMCIA enabler +CONFIG_HD64461_ENABLER + Say Y here if you want to enable PCMCIA support + via the HD64461 companion chip. + Otherwise, say N. + +HD64461 virtualized IRQ number +CONFIG_HD64461_IRQ + The default setting of the HD64461 IRQ is 36. + + Do not change this unless you know what you are doing. + +Hitachi HD64465 companion chip support +CONFIG_HD64465 + The Hitachi HD64465 provides an interface for + the SH7750 CPU, supporting a LCD controller, + CRT color controller, IrDA, USB, PCMCIA, + keyboard controller, and a printer interface. + + More information is available at + . + + Say Y if you want support for the HD64465. + Otherwise, say N. + +HD64465 virtualized IRQ number +CONFIG_HD64465_IRQ + The default setting of the HD64465 IRQ is 5. + + Do not change this unless you know what you are doing. + +HD64465 start address +CONFIG_HD64465_IOBASE + The default setting of the HD64465 IO base address is 0xb0000000. + + Do not change this unless you know what you are doing. + +Early printk support +CONFIG_SH_EARLY_PRINTK + Say Y here to redirect kernel messages to the serial port + used by the SH-IPL bootloader, starting very early in the boot + process and ending when the kernel's serial console is initialised. + This option is only useful porting the kernel to a new machine, + when the kernel may crash or hang before the serial console is + initialised. + +SuperH SCI (serial) support +CONFIG_SH_SCI + Selecting this option will allow the Linux kernel to transfer data + over SCI (Serial Communication Interface) and/or SCIF (Serial + Communication Interface with FIFO) which are built into the Hitachi + SuperH processor. The option provides 1 to 3 (depending + on the CPU model) standard Linux tty devices, /dev/ttySC[012]; one + of these is normally used as the system console. + + If in doubt, press "y". + +Use LinuxSH standard BIOS +CONFIG_SH_STANDARD_BIOS + Say Y here if your target has the gdb-sh-stub + package from www.m17n.org (or any conforming standard LinuxSH BIOS) + in FLASH or EPROM. The kernel will use standard BIOS calls during + boot for various housekeeping tasks (including calls to read and + write characters to a system console, get a MAC address from an + on-board Ethernet interface, and shut down the hardware). Note this + does not work with machines with an existing operating system in + mask ROM and no flash (WindowsCE machines fall in this category). + If unsure, say N. + +GDB Stub kernel debug +CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + If you say Y here, it will be possible to remotely debug the SuperH + kernel using gdb, if you have the gdb-sh-stub package from + www.m17n.org (or any conforming standard LinuxSH BIOS) in FLASH or + EPROM. This enlarges your kernel image disk size by several + megabytes but allows you to load, run and debug the kernel image + remotely using gdb. This is only useful for kernel hackers. If + unsure, say N. + +Console output to GDB +CONFIG_GDB_CONSOLE + If you are using GDB for remote debugging over a serial port and + would like kernel messages to be formatted into GDB $O packets so + that GDB prints them as program output, say 'Y'. + # # A couple of things I keep forgetting: -# capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, -# Intel, IRQ, ISDN, Linux, MSDOS, NetWare, NetWinder, +# capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, +# Intel, IRQ, ISDN, Linux, MSDOS, NetWare, NetWinder, # NFS, PCI, SCSI, SPARC -# two words: file system, hard drive, hard disk, home page, +# two words: file system, hard drive, hard disk, home page, # user space, web site # other: it's safe to save; daemon; use --, not - or ---; # use KB for 1024 bytes, not kB or K. @@ -19195,13 +23908,13 @@ # 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: HD CD-ROMs 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: 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: proc acct IPIP encapsulator decapsulator klogd RARP EXT PS # LocalWords: telnetting subnetted NAGLE rlogin NOSR ttyS TGA techinfo mbone nl # LocalWords: Mb SKB IPX Novell dosemu DDP ATALK vmalloc visar ehome # LocalWords: SD CHR scsi thingy SG CD LUNs LUN jukebox Adaptec BusLogic EATA @@ -19255,11 +23968,11 @@ # 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: 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: hitchcock Crynwr cnam pktdrvr NCSA's CyDROM CyCD-ROM 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 @@ -19275,7 +23988,7 @@ # 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: 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 @@ -19338,7 +24051,7 @@ # 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: Valencian Slovene Esperanto Estonian Latvian Belarusian KOI mt # LocalWords: charset Inuit Greenlandic Sami Lappish koi Alexey Kuznetsov's sa # 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 @@ -19404,7 +24117,7 @@ # 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: ACTiSYS 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 @@ -19416,7 +24129,7 @@ # 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: FPEmulator ds vmlinux initialization 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 @@ -19445,7 +24158,7 @@ # LocalWords: VWSND eg ESSSOLO CFU CFNR scribed eiconctrl eicon hylafax KFPU # LocalWords: EXTRAPREC fpu mainboards KHTTPD kHTTPd khttpd Xcelerator SBNI tw # LocalWords: LOGIBUSMOUSE Granch granch sbni Raylink NOHIGHMEM Athlon SIM sim -# LocalWords: hpl Tourrilhes DuraLAN starfile Davicom davicom dmfe auk tms tr +# LocalWords: hpl Tourrilhes DuraLAN starfire Davicom davicom dmfe auk tms tr # LocalWords: TokenExpress Belkin Peracom eTek DVDs infradead Cxxx Adlib AV ZX # LocalWords: NeoMagic CPi CPt Celeron decapsulation Undeletion BFS bfs nVidia # LocalWords: OnStream Irongate Riva phonedev QuickNet LineJack PhoneJack IXJ @@ -19465,7 +24178,7 @@ # LocalWords: DEVS FireWire PCILynx pcilynx LOCALRAM miro's DV RAWIO GRED Mk # LocalWords: Diffserv DSMARK Ingress Qdisc TCINDEX TMSPCI tmspci Ringode JE # LocalWords: MADGEMC madgemc TokenRing SMCTR TokenCard smctr Wacom Graphire -# LocalWords: WMFORCE mousedev ConnectTech HandSpring Xirlink IBMCAM ibmcam SN +# LocalWords: mousedev ConnectTech HandSpring Xirlink IBMCAM ibmcam SN # LocalWords: DEVICEFS yyy Cymraeg Dwave SIMM JSFLASH JavaStation's multilink # LocalWords: nsc ircc DDB Vrc CMN TB PROMs Vino rivafb DDC Matroxes MGA TVO # LocalWords: MAVEN fbdev crtc maven matroxset NTSC PCA SBA AAL SKFP DAS SAS @@ -19495,3 +24208,11 @@ # LocalWords: DMX Domex dmx wellington ftdi sio Accton Billington Corega FEter # LocalWords: MELCO LUA PNA Linksys SNC chkdsk AWACS Webcam RAMFS Ramfs ramfs # LocalWords: ramfiles MAKEDEV pty WDTPCI APA apa +# +# The following sets edit modes for GNU EMACS +# Local Variables: +# case-fold-search:nil +# fill-prefix:" " +# adaptive-fill:nil +# fill-column:70 +# End: diff -u --recursive --new-file v2.4.14/linux/Documentation/DocBook/via-audio.tmpl linux/Documentation/DocBook/via-audio.tmpl --- v2.4.14/linux/Documentation/DocBook/via-audio.tmpl Wed Jul 25 17:10:16 2001 +++ linux/Documentation/DocBook/via-audio.tmpl Fri Nov 9 13:45:35 2001 @@ -68,7 +68,7 @@ support are not yet available. - This driver supports any Linux kernel version after 2.3.50. + This driver supports any Linux kernel version after 2.4.10. Please send bug reports to the mailing list linux-via@gtf.org. @@ -157,14 +157,6 @@ - RealPlayer trouble - - - RealPlayer output very scratchy. Workaround: use esd, and - configure RealPlayer to output to esd. - - - @@ -191,6 +183,9 @@ MMAP support, and several other notable fixes that resulted from his hard work and testing. + + Thomas Sailer for further bugfixes. + @@ -233,6 +228,31 @@ Driver ChangeLog + + +Version 1.9.1 + + + + + DSP read/write bugfixes from Thomas Sailer. + + + + + + Add new PCI id for single-channel use of Via 8233. + + + + + + Other bug fixes, tweaks, new ioctls. + + + + + Version 1.1.15 diff -u --recursive --new-file v2.4.14/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v2.4.14/linux/Documentation/devices.txt Mon Aug 27 12:41:37 2001 +++ linux/Documentation/devices.txt Wed Nov 7 14:46:01 2001 @@ -971,7 +971,7 @@ 0 = /dev/rd/c0d0 First disk, whole disk 8 = /dev/rd/c0d1 Second disk, whole disk ... - 248 = /dev/rd/c0d15 32nd disk, whole disk + 248 = /dev/rd/c0d31 32nd disk, whole disk For partitions add: 0 = /dev/rd/c?d? Whole disk diff -u --recursive --new-file v2.4.14/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt --- v2.4.14/linux/Documentation/filesystems/proc.txt Fri Apr 6 10:42:48 2001 +++ linux/Documentation/filesystems/proc.txt Wed Nov 7 14:39:36 2001 @@ -471,6 +471,11 @@ ...] 1375103 17405 0 0 0 0 0 0 ...] 1703981 5535 0 0 0 3 0 0 +In addition, each Channel Bond interface has it's own directory. For +example, the bond0 device will have a directory called /proc/net/bond0/. +It will contain information that is specific to that bond, such as the +current slaves of the bond, the link status of the slaves, and how +many times the slaves link has failed. 1.5 SCSI info ------------- diff -u --recursive --new-file v2.4.14/linux/Documentation/i386/boot.txt linux/Documentation/i386/boot.txt --- v2.4.14/linux/Documentation/i386/boot.txt Wed Apr 11 18:50:25 2001 +++ linux/Documentation/i386/boot.txt Wed Nov 7 14:46:01 2001 @@ -2,7 +2,7 @@ ---------------------------- H. Peter Anvin <hpa@zytor.com> - Last update 2000-07-27 + Last update 2000-10-29 On the i386 platform, the Linux kernel uses a rather complicated boot convention. This has evolved partially due to historical aspects, as @@ -145,6 +145,9 @@ most of the fields in the header. The following fields should be filled out, however: + vid_mode: + Please see the section on SPECIAL COMMAND LINE OPTIONS. + type_of_loader: If your boot loader has an assigned id (see table below), enter 0xTV here, where T is an identifier for the boot loader and V is @@ -319,8 +322,8 @@ mem=<size> <size> is an integer in C notation optionally followed by K, M - or G (meaning << 10, << 20 or << 30). This specifies to the - kernel the memory size. This affects the possible placement + or G (meaning << 10, << 20 or << 30). This specifies the end + of memory to the kernel. This affects the possible placement of an initrd, since an initrd should be placed near end of memory. Note that this is an option to *both* the kernel and the bootloader! @@ -392,8 +395,8 @@ appropriate time. The use of these hooks should probably be considered an absolutely last resort! -IMPORTANT: All the hooks are required to preserve %ebp, %esi and %edi -across invocation. +IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and +%edi across invocation. realmode_swtch: A 16-bit real mode far subroutine invoked immediately before diff -u --recursive --new-file v2.4.14/linux/Documentation/memory.txt linux/Documentation/memory.txt --- v2.4.14/linux/Documentation/memory.txt Tue Dec 22 08:31:07 1998 +++ linux/Documentation/memory.txt Fri Nov 9 13:58:02 2001 @@ -37,7 +37,7 @@ * Not overclocking your CPU. * Having the memory tested in a memory tester or exchanged - with the vendor. + with the vendor. Consider testing it with memtest86 yourself. * Exchanging your CPU, cache, or motherboard for one that works. diff -u --recursive --new-file v2.4.14/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt --- v2.4.14/linux/Documentation/networking/8139too.txt Mon Nov 5 15:55:25 2001 +++ linux/Documentation/networking/8139too.txt Fri Nov 9 13:45:35 2001 @@ -82,7 +82,7 @@ (overwrite 8139too driver in kernel tree with different version) 1) cp 8139too.c $my_source_tree/drivers/net/8139too.c - + OPTION 2: Build outside kernel tree Use the included Makefile. @@ -139,7 +139,7 @@ Submitting Bug Reports ---------------------- -Obtain and compile the modified rtl8139-diag source code from the +Obtain and compile the modified rtl8139-diag source code from the 8139too driver Web site, http://sourceforge.net/projects/gkernel/ This diagnostics programs, originally from Donald Becker, has been modified to display all registers on your RTL8139 chip, not just the @@ -181,6 +181,27 @@ Change History -------------- +Version 0.9.22 - November 8, 2001 + +* Additional retries before aborting Tx +* Do not write other TxConfig bits when writing clear-abort bit. +* Ack TxErr intr status after each Tx abort, too. + + +Version 0.9.21 - November 1, 2001 + +* Disable early Rx, it hurts performance and creates races. +* Remove DPRINTK macro function tracing. +* Better interrupt sharing behavior. +* Acknowledge PCI errors. +* Remove early-Rx acknowledgement, unnecessary +* Remove code for uncommon case where Tx packets are + properly aligned, and do not need to be copied. + Tx packets are now always copied into a static DMA buffer, + which is allocated at interface open. +* Fix problems with kernel thread exit. + + Version 0.9.20 - October 18, 2001 * Print out notice when 8139C+ chip is detected @@ -212,7 +233,7 @@ Version 0.9.17 - May 7, 2001 * Fix chipset wakeup bug which prevent media connection for 8139B -* Print out "media is unconnected..." instead of +* Print out "media is unconnected..." instead of "partner ability 0000" diff -u --recursive --new-file v2.4.14/linux/Documentation/networking/bonding.txt linux/Documentation/networking/bonding.txt --- v2.4.14/linux/Documentation/networking/bonding.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/bonding.txt Wed Nov 7 14:39:36 2001 @@ -0,0 +1,524 @@ + + Linux Ethernet Bonding Driver mini-howto + +Initial release : Thomas Davis <tadavis at lbl.gov> +Corrections, HA extensions : 2000/10/03-15 : + - Willy Tarreau <willy at meta-x.org> + - Constantine Gavrilov <const-g at xpert.com> + - Chad N. Tindel <ctindel at ieee dot org> + - Janice Girouard <girouard at us dot ibm dot com> + +Note : +------ +The bonding driver originally came from Donald Becker's beowulf patches for +kernel 2.0. It has changed quite a bit since, and the original tools from +extreme-linux and beowulf sites will not work with this version of the driver. + +For new versions of the driver, patches for older kernels and the updated +userspace tools, please follow the links at the end of this file. + +Installation +============ + +1) Build kernel with the bonding driver +--------------------------------------- +For the latest version of the bonding driver, use kernel 2.4.12 or above +(otherwise you will need to apply a patch). + +Configure kernel with `make menuconfig/xconfig/config', and select +"Bonding driver support" in the "Network device support" section. It is +recommended to configure the driver as module since it is currently the only way +to pass parameters to the driver and configure more than one bonding device. + +Build and install the new kernel and modules. + +2) Get and install the userspace tools +-------------------------------------- +This version of the bonding driver requires updated ifenslave program. The +original one from extreme-linux and beowulf will not work. Kernels 2.4.12 +and above include the updated version of ifenslave.c in Documentation/network +directory. For older kernels, please follow the links at the end of this file. + +IMPORTANT!!! If you are running on Redhat 7.1 or greater, you need +to be careful because /usr/include/linux is no longer a symbolic link +to /usr/src/linux/include/linux. If you build ifenslave while this is +true, ifenslave will appear to succeed but your bond won't work. The purpose +of the -I option on the ifenslave compile line is to make sure it uses +/usr/src/linux/include/linux/if_bonding.h instead of the version from +/usr/include/linux. + +To install ifenslave.c, do: + # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave + # cp ifenslave /sbin/ifenslave + +3) Configure your system +------------------------ +Also see the following section on the module parameters. You will need to add +at least the following line to /etc/conf.modules (or /etc/modules.conf): + + alias bond0 bonding + +Use standard distribution techniques to define bond0 network interface. For +example, on modern RedHat distributions, create ifcfg-bond0 file in +/etc/sysconfig/network-scripts directory that looks like this: + +DEVICE=bond0 +IPADDR=192.168.1.1 +NETMASK=255.255.255.0 +NETWORK=192.168.1.0 +BROADCAST=192.168.1.255 +ONBOOT=yes +BOOTPROTO=none +USERCTL=no + +(put the appropriate values for you network instead of 192.168.1). + +All interfaces that are part of the trunk, should have SLAVE and MASTER +definitions. For example, in the case of RedHat, if you wish to make eth0 and +eth1 (or other interfaces) a part of the bonding interface bond0, their config +files (ifcfg-eth0, ifcfg-eth1, etc.) should look like this: + +DEVICE=eth0 +USERCTL=no +ONBOOT=yes +MASTER=bond0 +SLAVE=yes +BOOTPROTO=none + +(use DEVICE=eth1 for eth1 and MASTER=bond1 for bond1 if you have configured +second bonding interface). + +Restart the networking subsystem or just bring up the bonding device if your +administration tools allow it. Otherwise, reboot. (For the case of RedHat +distros, you can do `ifup bond0' or `/etc/rc.d/init.d/network restart'.) + +If the administration tools of your distribution do not support master/slave +notation in configuration of network interfaces, you will need to configure +the bonding device with the following commands manually: + + # /sbin/ifconfig bond0 192.168.1.1 up + # /sbin/ifenslave bond0 eth0 + # /sbin/ifenslave bond0 eth1 + +(substitute 192.168.1.1 with your IP address and add custom network and custom +netmask to the arguments of ifconfig if required). + +You can then create a script with these commands and put it into the appropriate +rc directory. + +If you specifically need that all your network drivers are loaded before the +bonding driver, use one of modutils' powerful features : in your modules.conf, +tell that when asked for bond0, modprobe should first load all your interfaces : + +probeall bond0 eth0 eth1 bonding + +Be careful not to reference bond0 itself at the end of the line, or modprobe will +die in an endless recursive loop. + +4) Module parameters. +--------------------- +The following module parameters can be passed: + + mode= + +Possible values are 0 (round robin policy, default) and 1 (active backup +policy), and 2 (XOR). See question 9 and the HA section for additional info. + + miimon= + +Use integer value for the frequency (in ms) of MII link monitoring. Zero value +is default and means the link monitoring will be disabled. A good value is 100 +if you wish to use link monitoring. See HA section for additional info. + + downdelay= + +Use integer value for delaying disabling a link by this number (in ms) after +the link failure has been detected. Must be a multiple of miimon. Default +value is zero. See HA section for additional info. + + updelay= + +Use integer value for delaying enabling a link by this number (in ms) after +the "link up" status has been detected. Must be a multiple of miimon. Default +value is zero. See HA section for additional info. + + arp_interval= + +Use integer value for the frequency (in ms) of arp monitoring. Zero value +is default and means the arp monitoring will be disabled. See HA section +for additional info. This field is value in active_backup mode only. + + arp_ip_target= + +An ip address to use when arp_interval is > 0. This is the target of the +arp request sent to determine the health of the link to the target. +Specify this value in ddd.ddd.ddd.ddd format. + +If you need to configure several bonding devices, the driver must be loaded +several times. I.e. for two bonding devices, your /etc/conf.modules must look +like this: + +alias bond0 bonding +alias bond1 bonding + +options bond0 miimon=100 +options bond1 -o bonding1 miimon=100 + +5) Testing configuration +------------------------ +You can test the configuration and transmit policy with ifconfig. For example, +for round robin policy, you should get something like this: + +[root]# /sbin/ifconfig +bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 + inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 + UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 Metric:1 + RX packets:7224794 errors:0 dropped:0 overruns:0 frame:0 + TX packets:3286647 errors:1 dropped:0 overruns:1 carrier:0 + collisions:0 txqueuelen:0 + +eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 + inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 + UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 + RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0 + TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0 + collisions:0 txqueuelen:100 + Interrupt:10 Base address:0x1080 + +eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 + inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 + UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 + RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0 + TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:100 + Interrupt:9 Base address:0x1400 + +Questions : +=========== + +1. Is it SMP safe? + + Yes. The old 2.0.xx channel bonding patch was not SMP safe. + The new driver was designed to be SMP safe from the start. + +2. What type of cards will work with it? + + Any Ethernet type cards (you can even mix cards - a Intel + EtherExpress PRO/100 and a 3com 3c905b, for example). + You can even bond together Gigabit Ethernet cards! + +3. How many bonding devices can I have? + + One for each module you load. See section on module parameters for how + to accomplish this. + +4. How many slaves can a bonding device have? + + Limited by the number of network interfaces Linux supports and the + number of cards you can place in your system. + +5. What happens when a slave link dies? + + If your ethernet cards support MII status monitoring and the MII + monitoring has been enabled in the driver (see description of module + parameters), there will be no adverse consequences. This release + of the bonding driver knows how to get the MII information and + enables or disables its slaves according to their link status. + See section on HA for additional information. + + For ethernet cards not supporting MII status, or if you wish to + verify that packets have been both send and received, you may + configure the arp_interval and arp_ip_target. If packets have + not been sent or received during this interval, an arp request + is sent to the target to generate send and receive traffic. + If after this interval, either the successful send and/or + receive count has not incremented, the next slave in the sequence + will become the active slave. + + If neither mii_monitor and arp_interval is configured, the bonding + driver will not handle this situation very well. The driver will + continue to send packets but some packets will be lost. Retransmits + will cause serious degradation of performance (in the case when one + of two slave links fails, 50% packets will be lost, which is a serious + problem for both TCP and UDP). + +6. Can bonding be used for High Availability? + + Yes, if you use MII monitoring and ALL your cards support MII link + status reporting. See section on HA for more information. + +7. Which switches/systems does it work with? + + In round-robin mode, it works with systems that support trunking: + + * Cisco 5500 series (look for EtherChannel support). + * SunTrunking software. + * Alteon AceDirector switches / WebOS (use Trunks). + * BayStack Switches (trunks must be explicitly configured). Stackable + models (450) can define trunks between ports on different physical + units. + * Linux bonding, of course ! + + In Active-backup mode, it should work with any Layer-II switches. + +8. Where does a bonding device get its MAC address from? + + If not explicitly configured with ifconfig, the MAC address of the + bonding device is taken from its first slave device. This MAC address + is then passed to all following slaves and remains persistent (even if + the the first slave is removed) until the bonding device is brought + down or reconfigured. + + If you wish to change the MAC address, you can set it with ifconfig: + + # ifconfig bond0 ha ether 00:11:22:33:44:55 + + The MAC address can be also changed by bringing down/up the device + and then changing its slaves (or their order): + + # ifconfig bond0 down ; modprobe -r bonding + # ifconfig bond0 .... up + # ifenslave bond0 eth... + + This method will automatically take the address from the next slave + that will be added. + + To restore your slaves' MAC addresses, you need to detach them + from the bond (`ifenslave -d bond0 eth0'), set them down + (`ifconfig eth0 down'), unload the drivers (`rmmod 3c59x', for + example) and reload them to get the MAC addresses from their + eeproms. If the driver is shared by several devices, you need + to turn them all down. Another solution is to look for the MAC + address at boot time (dmesg or tail /var/log/messages) and to + reset it by hand with ifconfig : + + # ifconfig eth0 down + # ifconfig eth0 hw ether 00:20:40:60:80:A0 + +9. Which transmit polices can be used? + + Round robin, based on the order of enslaving, the output device + is selected base on the next available slave. Regardless of + the source and/or destination of the packet. + + XOR, based on (src hw addr XOR dst hw addr) % slave cnt. This + selects the same slave for each destination hw address. + + Active-backup policy that ensures that one and only one device will + transmit at any given moment. Active-backup policy is useful for + implementing high availability solutions using two hubs (see + section on HA). + +High availability +================= + +To implement high availability using the bonding driver, you need to +compile the driver as module because currently it is the only way to pass +parameters to the driver. This may change in the future. + +High availability is achieved by using MII status reporting. You need to +verify that all your interfaces support MII link status reporting. On Linux +kernel 2.2.17, all the 100 Mbps capable drivers and yellowfin gigabit driver +support it. If your system has an interface that does not support MII status +reporting, a failure of its link will not be detected! + +The bonding driver can regularly check all its slaves links by checking the +MII status registers. The check interval is specified by the module argument +"miimon" (MII monitoring). It takes an integer that represents the +checking time in milliseconds. It should not come to close to (1000/HZ) +(10 ms on i386) because it may then reduce the system interactivity. 100 ms +seems to be a good value. It means that a dead link will be detected at most +100 ms after it goes down. + +Example: + + # modprobe bonding miimon=100 + +Or, put in your /etc/modules.conf : + + alias bond0 bonding + options bond0 miimon=100 + +There are currently two policies for high availability, depending on whether +a) hosts are connected to a single host or switch that support trunking +b) hosts are connected to several different switches or a single switch that + does not support trunking. + +1) HA on a single switch or host - load balancing +------------------------------------------------- +It is the easiest to set up and to understand. Simply configure the +remote equipment (host or switch) to aggregate traffic over several +ports (Trunk, EtherChannel, etc.) and configure the bonding interfaces. +If the module has been loaded with the proper MII option, it will work +automatically. You can then try to remove and restore different links +and see in your logs what the driver detects. When testing, you may +encounter problems on some buggy switches that disable the trunk for a +long time if all ports in a trunk go down. This is not Linux, but really +the switch (reboot it to ensure). + +Example 1 : host to host at double speed + + +----------+ +----------+ + | |eth0 eth0| | + | Host A +--------------------------+ Host B | + | +--------------------------+ | + | |eth1 eth1| | + +----------+ +----------+ + + On each host : + # modprobe bonding miimon=100 + # ifconfig bond0 addr + # ifenslave bond0 eth0 eth1 + +Example 2 : host to switch at double speed + + +----------+ +----------+ + | |eth0 port1| | + | Host A +--------------------------+ switch | + | +--------------------------+ | + | |eth1 port2| | + +----------+ +----------+ + + On host A : On the switch : + # modprobe bonding miimon=100 # set up a trunk on port1 + # ifconfig bond0 addr and port2 + # ifenslave bond0 eth0 eth1 + +2) HA on two or more switches (or a single switch without trunking support) +--------------------------------------------------------------------------- +This mode is more problematic because it relies on the fact that there +are multiple ports and the host's MAC address should be visible on one +port only to avoid confusing the switches. + +If you need to know which interface is the active one, and which ones are +backup, use ifconfig. All backup interfaces have the NOARP flag set. + +To use this mode, pass "mode=1" to the module at load time : + + # modprobe bonding miimon=100 mode=1 + +Or, put in your /etc/modules.conf : + + alias bond0 bonding + options bond0 miimon=100 mode=1 + +Example 1: Using multiple host and multiple switches to build a "no single +point of failure" solution. + + + | | + |port3 port3| + +-----+----+ +-----+----+ + | |port7 ISL port7| | + | switch A +--------------------------+ switch B | + | +--------------------------+ | + | |port8 port8| | + +----++----+ +-----++---+ + port2||port1 port1||port2 + || +-------+ || + |+-------------+ host1 +---------------+| + | eth0 +-------+ eth1 | + | | + | +-------+ | + +--------------+ host2 +----------------+ + eth0 +-------+ eth1 + +In this configuration, there are an ISL - Inter Switch Link (could be a trunk), +several servers (host1, host2 ...) attached to both switches each, and one or +more ports to the outside world (port3...). One an only one slave on each host +is active at a time, while all links are still monitored (the system can +detect a failure of active and backup links). + +Each time a host changes its active interface, it sticks to the new one until +it goes down. In this example, the hosts are not too much affected by the +expiration time of the switches' forwarding tables. + +If host1 and host2 have the same functionality and are used in load balancing +by another external mechanism, it is good to have host1's active interface +connected to one switch and host2's to the other. Such system will survive +a failure of a single host, cable, or switch. The worst thing that may happen +in the case of a switch failure is that half of the hosts will be temporarily +unreachable until the other switch expires its tables. + +Example 2: Using multiple ethernet cards connected to a switch to configure + NIC failover (switch is not required to support trunking). + + + +----------+ +----------+ + | |eth0 port1| | + | Host A +--------------------------+ switch | + | +--------------------------+ | + | |eth1 port2| | + +----------+ +----------+ + + On host A : On the switch : + # modprobe bonding miimon=100 mode=1 # (optional) minimize the time + # ifconfig bond0 addr # for table expiration + # ifenslave bond0 eth0 eth1 + +Each time the host changes its active interface, it sticks to the new one until +it goes down. In this example, the host is strongly affected by the expiration +time of the switch forwarding table. + +3) Adapting to your switches' timing +------------------------------------ +If your switches take a long time to go into backup mode, it may be +desirable not to activate a backup interface immediately after a link goes +down. It is possible to delay the moment at which a link will be +completely disabled by passing the module parameter "downdelay" (in +milliseconds, must be a multiple of miimon). + +When a switch reboots, it is possible that its ports report "link up" status +before they become usable. This could fool a bond device by causing it to +use some ports that are not ready yet. It is possible to delay the moment at +which an active link will be reused by passing the module parameter "updelay" +(in milliseconds, must be a multiple of miimon). + +A similar situation can occur when a host re-negotiates a lost link with the +switch (a case of cable replacement). + +A special case is when a bonding interface has lost all slave links. Then the +driver will immediately reuse the first link that goes up, even if updelay +parameter was specified. (If there are slave interfaces in the "updelay" state, +the interface that first went into that state will be immediately reused.) This +allows to reduce down-time if the value of updelay has been overestimated. + +Examples : + + # modprobe bonding miimon=100 mode=1 downdelay=2000 updelay=5000 + # modprobe bonding miimon=100 mode=0 downdelay=0 updelay=5000 + +4) Limitations +-------------- +The main limitations are : + - only the link status is monitored. If the switch on the other side is + partially down (e.g. doesn't forward anymore, but the link is OK), the link + won't be disabled. Another way to check for a dead link could be to count + incoming frames on a heavily loaded host. This is not applicable to small + servers, but may be useful when the front switches send multicast + information on their links (e.g. VRRP), or even health-check the servers. + Use the arp_interval/arp_ip_target parameters to count incoming/outgoing + frames. + +Resources and links +=================== + +Current developement on this driver is posted to: + - http://www.sourceforge.net/projects/bonding/ + +Donald Becker's Ethernet Drivers and diag programs may be found at : + - http://www.scyld.com/network/ + +You will also find a lot of information regarding Ethernet, NWay, MII, etc. at +www.scyld.com. + +For new versions of the driver, patches for older kernels and the updated +userspace tools, take a look at Willy Tarreau's site : + - http://wtarreau.free.fr/pub/bonding/ + - http://www-miaif.lip6.fr/willy/pub/bonding/ + +To get latest informations about Linux Kernel development, please consult +the Linux Kernel Mailing List Archives at : + http://boudicca.tux.org/hypermail/linux-kernel/latest/ + +-- END -- diff -u --recursive --new-file v2.4.14/linux/Documentation/networking/ifenslave.c linux/Documentation/networking/ifenslave.c --- v2.4.14/linux/Documentation/networking/ifenslave.c Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/ifenslave.c Wed Nov 7 14:39:36 2001 @@ -0,0 +1,562 @@ +/* Mode: C; + * ifenslave.c: Configure network interfaces for parallel routing. + * + * This program controls the Linux implementation of running multiple + * network interfaces in parallel. + * + * Usage: ifenslave [-v] master-interface < slave-interface [metric <N>] > ... + * + * Author: Donald Becker <becker@cesdis.gsfc.nasa.gov> + * Copyright 1994-1996 Donald Becker + * + * 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. + * + * The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + * Center of Excellence in Space Data and Information Sciences + * Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + * + * Changes : + * - 2000/10/02 Willy Tarreau <willy at meta-x.org> : + * - few fixes. Master's MAC address is now correctly taken from + * the first device when not previously set ; + * - detach support : call BOND_RELEASE to detach an enslaved interface. + * - give a mini-howto from command-line help : # ifenslave -h + * + * - 2001/02/16 Chad N. Tindel <ctindel at ieee dot org> : + * - Master is now brought down before setting the MAC address. In + * the 2.4 kernel you can't change the MAC address while the device is + * up because you get EBUSY. + * + * - 2001/09/13 Takao Indoh <indou dot takao at jp dot fujitsu dot com> + * - Added the ability to change the active interface on a mode 1 bond + * at runtime. + * + * - 2001/10/23 Chad N. Tindel <ctindel at ieee dot org> : + * - No longer set the MAC address of the master. The bond device will + * take care of this itself + * - Try the SIOC*** versions of the bonding ioctls before using the + * old versions + */ + +static char *version = +"ifenslave.c:v0.07 9/9/97 Donald Becker (becker@cesdis.gsfc.nasa.gov).\n" +"detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" +"2.4 kernel support added on 2001/02/16 by Chad N. Tindel (ctindel at ieee dot org.\n"; + +static const char *usage_msg = +"Usage: ifenslave [-adfrvVh] <master-interface> < <slave-if> [metric <N>] > ...\n" +" ifenslave -c master-interface slave-if\n"; + +static const char *howto_msg = +"Usage: ifenslave [-adfrvVh] <master-interface> < <slave-if> [metric <N>] > ...\n" +" ifenslave -c master-interface slave-if\n" +"\n" +" To create a bond device, simply follow these three steps :\n" +" - ensure that the required drivers are properly loaded :\n" +" # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n" +" - assign an IP address to the bond device :\n" +" # ifconfig bond0 <addr> netmask <mask> broadcast <bcast>\n" +" - attach all the interfaces you need to the bond device :\n" +" # ifenslave bond0 eth0 eth1 eth2\n" +" If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" +" interfaces attached AFTER this assignment will get the same MAC addr.\n" +"\n" +" To detach a dead interface without setting the bond device down :\n" +" # ifenslave -d bond0 eth1\n" +"\n" +" To set the bond device down and automatically release all the slaves :\n" +" # ifconfig bond0 down\n" +"\n" +" To change active slave :\n" +" # ifenslave -c bond0 eth0\n" +"\n"; + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <linux/if.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/if_bonding.h> +#include <linux/sockios.h> + +struct option longopts[] = { + /* { name has_arg *flag val } */ + {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ + {"force", 0, 0, 'f'}, /* Force the operation. */ + {"help", 0, 0, '?'}, /* Give help */ + {"howto", 0, 0, 'h'}, /* Give some more help */ + {"receive-slave", 0, 0, 'r'}, /* Make a receive-only slave. */ + {"verbose", 0, 0, 'v'}, /* Report each action taken. */ + {"version", 0, 0, 'V'}, /* Emit version information. */ + {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ + {"change-active", 0, 0, 'c'}, /* Change the active slave. */ + { 0, 0, 0, 0 } +}; + +/* Command-line flags. */ +unsigned int +opt_a = 0, /* Show-all-interfaces flag. */ +opt_f = 0, /* Force the operation. */ +opt_r = 0, /* Set up a Rx-only slave. */ +opt_d = 0, /* detach a slave interface. */ +opt_c = 0, /* change-active-slave flag. */ +verbose = 0, /* Verbose flag. */ +opt_version = 0, +opt_howto = 0; +int skfd = -1; /* AF_INET socket for ioctl() calls. */ + +static void if_print(char *ifname); + +int +main(int argc, char **argv) +{ + struct ifreq ifr2, if_hwaddr, if_ipaddr, if_metric, if_mtu, if_dstaddr; + struct ifreq if_netmask, if_brdaddr, if_flags; + int goterr = 0; + int c, errflag = 0; + sa_family_t master_family; + char **spp, *master_ifname, *slave_ifname; + int hwaddr_notset; + + while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF) + switch (c) { + case 'a': opt_a++; break; + case 'f': opt_f++; break; + case 'r': opt_r++; break; + case 'd': opt_d++; break; + case 'c': opt_c++; break; + case 'v': verbose++; break; + case 'V': opt_version++; break; + case 'h': opt_howto++; break; + case '?': errflag++; + } + + /* option check */ + if (opt_c) + if(opt_a || opt_f || opt_r || opt_d || verbose || opt_version || + opt_howto || errflag ) { + fprintf(stderr, usage_msg); + return 2; + } + + if (errflag) { + fprintf(stderr, usage_msg); + return 2; + } + + if (opt_howto) { + fprintf(stderr, howto_msg); + return 0; + } + + if (verbose || opt_version) { + printf(version); + if (opt_version) + exit(0); + } + + /* Open a basic socket. */ + if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) { + perror("socket"); + exit(-1); + } + + if (verbose) + fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n", + argc, optind, argv[optind]); + + /* No remaining args means show all interfaces. */ + if (optind == argc) { + if_print((char *)NULL); + (void) close(skfd); + exit(0); + } + + /* Copy the interface name. */ + spp = argv + optind; + master_ifname = *spp++; + slave_ifname = *spp++; + + /* Check command line. */ + if (opt_c) { + char **tempp = spp; + if ((master_ifname == NULL)||(slave_ifname == NULL)||(*tempp++ != NULL)) { + fprintf(stderr, usage_msg); + return 2; + } + } + + /* A single args means show the configuration for this interface. */ + if (slave_ifname == NULL) { + if_print(master_ifname); + (void) close(skfd); + exit(0); + } + + /* Get the vitals from the master interface. */ + { + struct ifreq *ifra[7] = { &if_ipaddr, &if_mtu, &if_dstaddr, + &if_brdaddr, &if_netmask, &if_flags, + &if_hwaddr }; + const char *req_name[7] = { + "IP address", "MTU", "destination address", + "broadcast address", "netmask", "status flags", + "hardware address" }; + const int ioctl_req_type[7] = { + SIOCGIFADDR, SIOCGIFMTU, SIOCGIFDSTADDR, + SIOCGIFBRDADDR, SIOCGIFNETMASK, SIOCGIFFLAGS, + SIOCGIFHWADDR }; + int i; + + for (i = 0; i < 7; i++) { + strncpy(ifra[i]->ifr_name, master_ifname, IFNAMSIZ); + if (ioctl(skfd, ioctl_req_type[i], ifra[i]) < 0) { + fprintf(stderr, + "Something broke getting the master's %s: %s.\n", + req_name[i], strerror(errno)); + } + } + + hwaddr_notset = 1; /* assume master's address not set yet */ + for (i = 0; hwaddr_notset && (i < 6); i++) { + hwaddr_notset &= ((unsigned char *)if_hwaddr.ifr_hwaddr.sa_data)[i] == 0; + } + + /* The family '1' is ARPHRD_ETHER for ethernet. */ + if (if_hwaddr.ifr_hwaddr.sa_family != 1 && !opt_f) { + fprintf(stderr, "The specified master interface '%s' is not" + " ethernet-like.\n This program is designed to work" + " with ethernet-like network interfaces.\n" + " Use the '-f' option to force the operation.\n", + master_ifname); + + exit (1); + } + master_family = if_hwaddr.ifr_hwaddr.sa_family; + if (verbose) { + unsigned char *hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data; + printf("The current hardware address (SIOCGIFHWADDR) of %s is type %d " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", master_ifname, + if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); + } + } + + + /* do this when enslaving interfaces */ + do { + if (opt_d) { /* detach a slave interface from the master */ + strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); + strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDRELEASE, &if_flags) < 0) && + (ioctl(skfd, BOND_RELEASE_OLD, &if_flags) < 0)) { + fprintf(stderr, "SIOCBONDRELEASE: cannot detach %s from %s. errno=%s.\n", + slave_ifname, master_ifname, strerror(errno)); + } + else { /* we'll set the interface down to avoid any conflicts due to + same IP/MAC */ + strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); + if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { + int saved_errno = errno; + fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, + strerror(saved_errno)); + } + else { + ifr2.ifr_flags &= ~(IFF_UP | IFF_RUNNING); + if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { + int saved_errno = errno; + fprintf(stderr, "Shutting down interface %s failed: %s\n", + slave_ifname, strerror(saved_errno)); + } + } + } + } + else { /* attach a slave interface to the master */ + /* two possibilities : + - if hwaddr_notset, do nothing. The bond will assign the + hwaddr from it's first slave. + - if !hwaddr_notset, assign the master's hwaddr to each slave + */ + + if (hwaddr_notset) { /* we do nothing */ + + } + else { /* we'll assign master's hwaddr to this slave */ + strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); + if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { + int saved_errno = errno; + fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, + strerror(saved_errno)); + return 1; + } + + if (ifr2.ifr_flags & IFF_UP) { + ifr2.ifr_flags &= ~IFF_UP; + if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { + int saved_errno = errno; + fprintf(stderr, "Shutting down interface %s failed: %s\n", + slave_ifname, strerror(saved_errno)); + } + } + + strncpy(if_hwaddr.ifr_name, slave_ifname, IFNAMSIZ); + if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) { + int saved_errno = errno; + fprintf(stderr, "SIOCSIFHWADDR on %s failed: %s\n", if_hwaddr.ifr_name, + strerror(saved_errno)); + if (saved_errno == EBUSY) + fprintf(stderr, " The slave device %s is busy: it must be" + " idle before running this command.\n", slave_ifname); + else if (saved_errno == EOPNOTSUPP) + fprintf(stderr, " The slave device you specified does not support" + " setting the MAC address.\n Your kernel likely does not" + " support slave devices.\n"); + else if (saved_errno == EINVAL) + fprintf(stderr, " The slave device's address type does not match" + " the master's address type.\n"); + } else { + if (verbose) { + unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; + printf("Slave's (%s) hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", slave_ifname, + hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); + } + } + } + + if (*spp && !strcmp(*spp, "metric")) { + if (*++spp == NULL) { + fprintf(stderr, usage_msg); + exit(2); + } + if_metric.ifr_metric = atoi(*spp); + strncpy(if_metric.ifr_name, slave_ifname, IFNAMSIZ); + if (ioctl(skfd, SIOCSIFMETRIC, &if_metric) < 0) { + fprintf(stderr, "SIOCSIFMETRIC on %s: %s\n", slave_ifname, + strerror(errno)); + goterr = 1; + } + spp++; + } + + if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) { + fprintf(stderr, + "Something broke setting the slave's address: %s.\n", + strerror(errno)); + } else { + if (verbose) { + unsigned char *ipaddr = if_ipaddr.ifr_addr.sa_data; + printf("Set the slave's (%s) IP address to %d.%d.%d.%d.\n", + slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + } + + if (strncpy(if_mtu.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) { + fprintf(stderr, "Something broke setting the slave MTU: %s.\n", + strerror(errno)); + } else { + if (verbose) + printf("Set the slave's (%s) MTU to %d.\n", slave_ifname, if_mtu.ifr_mtu); + } + + if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) { + fprintf(stderr, "Error setting the slave (%s) with SIOCSIFDSTADDR: %s.\n", + slave_ifname, strerror(errno)); + } else { + if (verbose) { + unsigned char *ipaddr = if_dstaddr.ifr_dstaddr.sa_data; + printf("Set the slave's (%s) destination address to %d.%d.%d.%d.\n", + slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + } + + if (strncpy(if_brdaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFBRDADDR, &if_brdaddr) < 0) { + fprintf(stderr, + "Something broke setting the slave (%s) broadcast address: %s.\n", + slave_ifname, strerror(errno)); + } else { + if (verbose) { + unsigned char *ipaddr = if_brdaddr.ifr_broadaddr.sa_data; + printf("Set the slave's (%s) broadcast address to %d.%d.%d.%d.\n", + slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + } + + if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) { + fprintf(stderr, + "Something broke setting the slave (%s) netmask: %s.\n", + slave_ifname, strerror(errno)); + } else { + if (verbose) { + unsigned char *ipaddr = if_netmask.ifr_netmask.sa_data; + printf("Set the slave's (%s) netmask to %d.%d.%d.%d.\n", + slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + } + + ifr2.ifr_flags |= IFF_UP; /* the interface will need to be up to be bonded */ + if ((ifr2.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0 + || strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { + fprintf(stderr, + "Something broke setting the slave (%s) flags: %s.\n", + slave_ifname, strerror(errno)); + } else { + if (verbose) + printf("Set the slave's (%s) flags %4.4x.\n", slave_ifname, if_flags.ifr_flags); + } + + /* Do the real thing */ + if ( ! opt_r) { + strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); + strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); + if (!opt_c) { + if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) && + (ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) { + fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno)); + } + } + else { + if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) && + (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) { + fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno)); + } + } + } + } + } while ( (slave_ifname = *spp++) != NULL); + + /* Close the socket. */ + (void) close(skfd); + + return(goterr); +} + +static short mif_flags; + +/* Get the inteface configuration from the kernel. */ +static int if_getconfig(char *ifname) +{ + struct ifreq ifr; + int metric, mtu; /* Parameters of the master interface. */ + struct sockaddr dstaddr, broadaddr, netmask; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) + return -1; + mif_flags = ifr.ifr_flags; + printf("The result of SIOCGIFFLAGS on %s is %x.\n", + ifname, ifr.ifr_flags); + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) + return -1; + printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n", + ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], + ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) + return -1; + + { + /* Gotta convert from 'char' to unsigned for printf(). */ + unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; + printf("The result of SIOCGIFHWADDR is type %d " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); + } + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) { + metric = 0; + } else + metric = ifr.ifr_metric; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0) + mtu = 0; + else + mtu = ifr.ifr_mtu; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) { + memset(&dstaddr, 0, sizeof(struct sockaddr)); + } else + dstaddr = ifr.ifr_dstaddr; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) { + memset(&broadaddr, 0, sizeof(struct sockaddr)); + } else + broadaddr = ifr.ifr_broadaddr; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) { + memset(&netmask, 0, sizeof(struct sockaddr)); + } else + netmask = ifr.ifr_netmask; + + return(0); +} + +static void if_print(char *ifname) +{ + char buff[1024]; + struct ifconf ifc; + struct ifreq *ifr; + int i; + + if (ifname == (char *)NULL) { + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { + fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + return; + } + + ifr = ifc.ifc_req; + for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { + if (if_getconfig(ifr->ifr_name) < 0) { + fprintf(stderr, "%s: unknown interface.\n", + ifr->ifr_name); + continue; + } + + if (((mif_flags & IFF_UP) == 0) && !opt_a) continue; + /*ife_print(&ife);*/ + } + } else { + if (if_getconfig(ifname) < 0) + fprintf(stderr, "%s: unknown interface.\n", ifname); + } +} + + +/* + * Local variables: + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" + * End: + */ diff -u --recursive --new-file v2.4.14/linux/Documentation/networking/multicast.txt linux/Documentation/networking/multicast.txt --- v2.4.14/linux/Documentation/networking/multicast.txt Wed Jul 25 17:10:17 2001 +++ linux/Documentation/networking/multicast.txt Wed Nov 7 14:46:01 2001 @@ -31,6 +31,7 @@ de600 NO NO NO N/A de620 PROMISC PROMISC YES Software depca YES PROMISC YES Hardware +dmfe YES YES YES Software(*) e2100 YES YES YES Hardware eepro YES PROMISC YES Hardware eexpress NO NO NO N/A @@ -52,9 +53,12 @@ tulip YES YES YES Hardware wavelan YES PROMISC YES Hardware wd YES YES YES Hardware +xirc2ps_cs YES YES YES Hardware znet YES YES YES Software PROMISC = This multicast mode is in fact promiscuous mode. Avoid using cards who go PROMISC on any multicast in a multicast kernel. + (#) = Hardware multicast support is not used yet. +(*) = Hardware support for Davicom 9132 chipset only. diff -u --recursive --new-file v2.4.14/linux/Documentation/parport.txt linux/Documentation/parport.txt --- v2.4.14/linux/Documentation/parport.txt Sat May 19 17:54:14 2001 +++ linux/Documentation/parport.txt Fri Nov 9 14:30:55 2001 @@ -162,6 +162,10 @@ is available and will be used. DMA DMA is available and will be used. + Note that the current implementation will only take + advantage of COMPAT and ECP modes if it has an IRQ + line to use. + autoprobe Any IEEE-1284 device ID information that has been acquired from the (non-IEEE 1284.3) device. diff -u --recursive --new-file v2.4.14/linux/Documentation/s390/Debugging390.txt linux/Documentation/s390/Debugging390.txt --- v2.4.14/linux/Documentation/s390/Debugging390.txt Sun Aug 12 13:27:58 2001 +++ linux/Documentation/s390/Debugging390.txt Wed Nov 7 14:46:01 2001 @@ -1287,10 +1287,14 @@ circumstances as the process may change when doing a TR I R <address range>. Thankfully after reading VM's online help I figured out how to debug -I particular process. +particular processes in 31 bit mode, however, according to the current +VM online help documentation the method described below uses +TR STO or STD which don't currently work on z/Series while in +64-bit mode. Your first problem is to find the STD ( segment table designation ) of the program you wish to debug. + There are several ways you can do this here are a few 1) objdump --syms <program to be debugged> | grep main To get the address of main in the program. diff -u --recursive --new-file v2.4.14/linux/Documentation/s390/chandev.8 linux/Documentation/s390/chandev.8 --- v2.4.14/linux/Documentation/s390/chandev.8 Tue Oct 23 22:48:49 2001 +++ linux/Documentation/s390/chandev.8 Wed Nov 7 14:46:01 2001 @@ -56,7 +56,7 @@ .El .Bl -item .It -Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. To be consistent with other hotpluggable architectures the script pointed to /proc/sys/kernel/hotplug (normally /sbin/hotplug) will be called automatically on startup or a machine check of a device as follows. +Multiple options can be passed separated by semicolons, no spaces or newlines are allowed between parameters on the kernel parameter line as it complicates parsing, spaces are allowed in /proc/chandev & chandev.conf, newlines are allowed in chandev.conf only. To be consistent with other hotpluggable architectures the script pointed to /proc/sys/kernel/hotplug (normally /sbin/hotplug) will be called automatically on startup or a machine check of a device as follows. /sbin/hotplug chandev <start starting_devnames> <machine_check (devname last/pre_recovery_status) (current/post_recovery_status)>. The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script, here is a sample script which starts devices as they become available. .It @@ -132,7 +132,7 @@ .It Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( default 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter. This can be used for instance to force a device if it presents bad sense data to the IO layer & thus autodetection fails. .It -lcs,0x7c00,0x7d00,-1,4096 +lcs,0x7c00,0x7d00,4096,-1 All devices between 0x7c00 & 7d00 should be detected as lcs, let the driver use 4096k for each instance, don't care what port relative adapter number is chosen, don't checksum received ip packets & use hw stats . .It qeth1,0x7c00,0x7c01,0x7c02 diff -u --recursive --new-file v2.4.14/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.14/linux/MAINTAINERS Mon Nov 5 15:55:25 2001 +++ linux/MAINTAINERS Fri Nov 9 13:45:35 2001 @@ -201,6 +201,12 @@ M: linux@treblig.org S: Maintained +ARM/SHARK MACHINE SUPPORT +P: Alexander Schulz +M: alex@shark-linux.de +W: http://www.shark-linux.de/shark.html +S: Maintained + ARM/STRONGARM110 PORT P: Russell King M: rmk@arm.linux.org.uk @@ -1406,8 +1412,8 @@ S: Maintained SYSV FILESYSTEM -P: Krzysztof G. Baranowski -M: kgb@manjak.knm.org.pl +P: Christoph Hellwig +M: hch@caldera.de S: Maintained TLAN NETWORK DRIVER diff -u --recursive --new-file v2.4.14/linux/Makefile linux/Makefile --- v2.4.14/linux/Makefile Mon Nov 5 15:55:25 2001 +++ linux/Makefile Wed Nov 7 17:45:50 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 14 -EXTRAVERSION = +SUBLEVEL = 15 +EXTRAVERSION =-pre2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -u --recursive --new-file v2.4.14/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.4.14/linux/arch/alpha/config.in Mon Nov 5 15:55:25 2001 +++ linux/arch/alpha/config.in Fri Nov 9 14:21:21 2001 @@ -296,6 +296,10 @@ fi endmenu +if [ "$CONFIG_PCI" = "y" ]; then + source drivers/message/fusion/Config.in +fi + if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment comment 'Network device support' diff -u --recursive --new-file v2.4.14/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.4.14/linux/arch/alpha/kernel/entry.S Sun Aug 12 13:27:58 2001 +++ linux/arch/alpha/kernel/entry.S Fri Nov 9 13:45:35 2001 @@ -1145,3 +1145,6 @@ .quad sys_mincore /* 375 */ .quad sys_pciconfig_iobase .quad sys_getdents64 + .quad sys_gettid + .quad sys_readahead + .quad sys_ni_syscall /* 380, sys_security */ diff -u --recursive --new-file v2.4.14/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.4.14/linux/arch/alpha/kernel/signal.c Wed Jan 24 15:16:23 2001 +++ linux/arch/alpha/kernel/signal.c Fri Nov 9 13:45:35 2001 @@ -17,6 +17,7 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/stddef.h> +#include <linux/tty.h> #include <asm/bitops.h> #include <asm/uaccess.h> diff -u --recursive --new-file v2.4.14/linux/arch/alpha/kernel/sys_miata.c linux/arch/alpha/kernel/sys_miata.c --- v2.4.14/linux/arch/alpha/kernel/sys_miata.c Tue Oct 23 22:48:49 2001 +++ linux/arch/alpha/kernel/sys_miata.c Fri Nov 9 13:58:02 2001 @@ -176,6 +176,19 @@ { -1, -1, -1, -1, -1}, /* IdSel 31, PCI-PCI */ }; const long min_idsel = 3, max_idsel = 20, irqs_per_slot = 5; + + /* the USB function of the 82c693 has it's interrupt connected to + the 2nd 8259 controller. So we have to check for it first. */ + + if((slot == 7) && (PCI_FUNC(dev->devfn) == 3)) { + u8 irq=0; + + if(pci_read_config_byte(pci_find_slot(dev->bus->number, dev->devfn & ~(7)), 0x40,&irq)!=PCIBIOS_SUCCESSFUL) + return -1; + else + return irq; + } + return COMMON_TABLE_LOOKUP; } diff -u --recursive --new-file v2.4.14/linux/arch/alpha/lib/dec_and_lock.c linux/arch/alpha/lib/dec_and_lock.c --- v2.4.14/linux/arch/alpha/lib/dec_and_lock.c Mon Nov 5 15:55:25 2001 +++ linux/arch/alpha/lib/dec_and_lock.c Fri Nov 9 13:39:57 2001 @@ -18,15 +18,16 @@ subl $1, 1, $1 \n\ beq $1, 2f \n\ stl_c $1, 0($16) \n\ - beq $1, 3f \n\ + beq $1, 4f \n\ mb \n\ clr $0 \n\ ret \n\ -3: br 1b \n\ -2: lda $27, atomic_dec_and_lock_1 \n\ +2: br $29, 3f \n\ +3: ldgp $29, 0($29) \n\ + br $atomic_dec_and_lock_1..ng \n\ + .subsection 2 \n\ +4: br 1b \n\ .end atomic_dec_and_lock"); - - /* FALLTHRU */ static int __attribute__((unused)) atomic_dec_and_lock_1(atomic_t *atomic, spinlock_t *lock) diff -u --recursive --new-file v2.4.14/linux/arch/alpha/lib/io.c linux/arch/alpha/lib/io.c --- v2.4.14/linux/arch/alpha/lib/io.c Sat Nov 27 15:27:48 1999 +++ linux/arch/alpha/lib/io.c Fri Nov 9 13:45:35 2001 @@ -9,124 +9,124 @@ #include <asm/io.h> -unsigned int _inb(unsigned long addr) +u8 _inb(unsigned long addr) { return __inb(addr); } -unsigned int _inw(unsigned long addr) +u16 _inw(unsigned long addr) { return __inw(addr); } -unsigned int _inl(unsigned long addr) +u32 _inl(unsigned long addr) { return __inl(addr); } -void _outb(unsigned char b, unsigned long addr) +void _outb(u8 b, unsigned long addr) { __outb(b, addr); } -void _outw(unsigned short b, unsigned long addr) +void _outw(u16 b, unsigned long addr) { __outw(b, addr); } -void _outl(unsigned int b, unsigned long addr) +void _outl(u32 b, unsigned long addr) { __outl(b, addr); } -unsigned long ___raw_readb(unsigned long addr) +u8 ___raw_readb(unsigned long addr) { return __readb(addr); } -unsigned long ___raw_readw(unsigned long addr) +u16 ___raw_readw(unsigned long addr) { return __readw(addr); } -unsigned long ___raw_readl(unsigned long addr) +u32 ___raw_readl(unsigned long addr) { return __readl(addr); } -unsigned long ___raw_readq(unsigned long addr) +u64 ___raw_readq(unsigned long addr) { return __readq(addr); } -unsigned long _readb(unsigned long addr) +u8 _readb(unsigned long addr) { unsigned long r = __readb(addr); mb(); return r; } -unsigned long _readw(unsigned long addr) +u16 _readw(unsigned long addr) { unsigned long r = __readw(addr); mb(); return r; } -unsigned long _readl(unsigned long addr) +u32 _readl(unsigned long addr) { unsigned long r = __readl(addr); mb(); return r; } -unsigned long _readq(unsigned long addr) +u64 _readq(unsigned long addr) { unsigned long r = __readq(addr); mb(); return r; } -void ___raw_writeb(unsigned char b, unsigned long addr) +void ___raw_writeb(u8 b, unsigned long addr) { __writeb(b, addr); } -void ___raw_writew(unsigned short b, unsigned long addr) +void ___raw_writew(u16 b, unsigned long addr) { __writew(b, addr); } -void ___raw_writel(unsigned int b, unsigned long addr) +void ___raw_writel(u32 b, unsigned long addr) { __writel(b, addr); } -void ___raw_writeq(unsigned long b, unsigned long addr) +void ___raw_writeq(u64 b, unsigned long addr) { __writeq(b, addr); } -void _writeb(unsigned char b, unsigned long addr) +void _writeb(u8 b, unsigned long addr) { __writeb(b, addr); mb(); } -void _writew(unsigned short b, unsigned long addr) +void _writew(u16 b, unsigned long addr) { __writew(b, addr); mb(); } -void _writel(unsigned int b, unsigned long addr) +void _writel(u32 b, unsigned long addr) { __writel(b, addr); mb(); } -void _writeq(unsigned long b, unsigned long addr) +void _writeq(u64 b, unsigned long addr) { __writeq(b, addr); mb(); diff -u --recursive --new-file v2.4.14/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.4.14/linux/arch/arm/Makefile Tue Oct 23 22:48:49 2001 +++ linux/arch/arm/Makefile Fri Nov 9 13:58:02 2001 @@ -39,11 +39,12 @@ tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710 tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi +tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu +AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu -msoft-float ifeq ($(CONFIG_CPU_26),y) PROCESSOR = armo @@ -120,6 +121,10 @@ MACHINE = integrator endif +ifeq ($(CONFIG_ARCH_CAMELOT),y) +MACHINE = epxa10db +endif + ifeq ($(CONFIG_ARCH_CLPS711X),y) TEXTADDR = 0xc0028000 MACHINE = clps711x @@ -150,17 +155,22 @@ HEAD := arch/arm/kernel/head-$(PROCESSOR).o \ arch/arm/kernel/init_task.o -SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe \ - arch/arm/fastfpe +SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) LIBS := arch/arm/lib/lib.a $(LIBS) ifeq ($(CONFIG_FPE_NWFPE),y) LIBS := arch/arm/nwfpe/math-emu.o $(LIBS) endif + +# Only include fastfpe if it is part of the kernel tree. +FASTFPE := arch/arm/fastfpe +ifeq ($(FASTFPE),$(wildcard $(FASTFPE))) +SUBDIRS += $(FASTFPE) ifeq ($(CONFIG_FPE_FASTFPE),y) LIBS := arch/arm/fastfpe/fast-math-emu.o $(LIBS) endif +endif ifeq ($(findstring y,$(CONFIG_ARCH_CLPS7500) $(CONFIG_ARCH_L7200)),y) SUBDIRS += drivers/acorn/char @@ -213,7 +223,8 @@ @$(MAKETOOLS) dep @$(MAKEBOOT) dep -maketools: checkbin +# we need version.h +maketools: checkbin include/linux/version.h @$(MAKETOOLS) all # Ensure this is ld "2.9.4" or later diff -u --recursive --new-file v2.4.14/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.4.14/linux/arch/arm/config.in Mon Nov 5 15:55:25 2001 +++ linux/arch/arm/config.in Fri Nov 9 13:58:02 2001 @@ -12,7 +12,7 @@ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n define_bool CONFIG_GENERIC_BUST_SPINLOCK n - +define_bool CONFIG_GENERIC_ISA_DMA n mainmenu_option next_comment comment 'Code maturity level options' @@ -261,19 +261,42 @@ fi fi +# ARM926T +if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + bool 'Support ARM926T processor' CONFIG_CPU_ARM926T +else + define_bool CONFIG_CPU_ARM926T n +fi +if [ "$CONFIG_CPU_ARM926T" = "y" ]; then + bool ' ARM926T CPU idle' CONFIG_CPU_ARM926_CPU_IDLE + bool ' ARM926T I-Cache on' CONFIG_CPU_ARM926_I_CACHE_ON + bool ' ARM926T D-Cache on' CONFIG_CPU_ARM926_D_CACHE_ON + if [ "$CONFIG_CPU_ARM926_D_CACHE_ON" = "y" ] ; then + bool ' Force write through caches on ARM926T' CONFIG_CPU_ARM926_WRITETHROUGH + fi + if [ "$CONFIG_CPU_ARM926_I_CACHE_ON" = "y" -o \ + "$CONFIG_CPU_ARM926_D_CACHE_ON" = "y" ]; then + bool ' Round robin I and D cache replacement algorithm' CONFIG_CPU_ARM926_ROUND_ROBIN + fi +fi + # ARM1020 -#if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then -# bool 'Support ARM1020 processor' CONFIG_CPU_ARM1020 -#else +if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + bool 'Support ARM1020 processor' CONFIG_CPU_ARM1020 +else define_bool CONFIG_CPU_ARM1020 n -#fi -#if [ "$CONFIG_CPU_ARM1020" = "y" ]; then -# bool ' ARM10 I-Cache on' CONFIG_CPU_ARM10_I_CACHE_ON -# bool ' ARM10 D-Cache on' CONFIG_CPU_ARM10_D_CACHE_ON -# if [ "$CONFIG_CPU_ARM10_D_CACHE_ON" = "y" ] ; then -# bool ' Force write through caches on ARM10' CONFIG_CPU_ARM10_FORCE_WRITE_THROUGH -# fi -#fi +fi +if [ "$CONFIG_CPU_ARM1020" = "y" ]; then + bool ' ARM1020 I-Cache on' CONFIG_CPU_ARM1020_I_CACHE_ON + bool ' ARM10 D-Cache on' CONFIG_CPU_ARM1020_D_CACHE_ON + if [ "$CONFIG_CPU_ARM1020_D_CACHE_ON" = "y" ] ; then + bool ' Force write through caches on ARM1020' CONFIG_CPU_ARM1020_FORCE_WRITE_THROUGH + fi + if [ "$CONFIG_CPU_ARM1020_I_CACHE_ON" = "y" -o \ + "$CONFIG_CPU_ARM1020_D_CACHE_ON" = "y" ]; then + bool ' Round robin I and D cache replacement algorithm' CONFIG_CPU_ARM1020_ROUND_ROBIN + fi +fi # SA110 if [ "$CONFIG_ARCH_EBSA110" = "y" -o "$CONFIG_FOOTBRIDGE" = "y" -o \ diff -u --recursive --new-file v2.4.14/linux/arch/arm/lib/gcclib.h linux/arch/arm/lib/gcclib.h --- v2.4.14/linux/arch/arm/lib/gcclib.h Tue Oct 23 22:48:49 2001 +++ linux/arch/arm/lib/gcclib.h Fri Nov 9 13:58:02 2001 @@ -11,7 +11,7 @@ typedef int word_type __attribute__ ((mode (__word__))); typedef unsigned int UDItype __attribute__ ((mode (DI))); -#if 0 /* FIXME: endian test here!!! */ +#ifdef __ARMEB__ struct DIstruct {SItype high, low;}; #else struct DIstruct {SItype low, high;}; diff -u --recursive --new-file v2.4.14/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.4.14/linux/arch/arm/mm/Makefile Mon Aug 27 12:41:38 2001 +++ linux/arch/arm/mm/Makefile Fri Nov 9 13:58:02 2001 @@ -34,6 +34,7 @@ p-$(CONFIG_CPU_ARM710) += proc-arm6,7.o p-$(CONFIG_CPU_ARM720T) += proc-arm720.o p-$(CONFIG_CPU_ARM920T) += proc-arm920.o +p-$(CONFIG_CPU_ARM926T) += proc-arm926.o p-$(CONFIG_CPU_ARM1020) += proc-arm1020.o p-$(CONFIG_CPU_SA110) += proc-sa110.o p-$(CONFIG_CPU_SA1100) += proc-sa110.o diff -u --recursive --new-file v2.4.14/linux/arch/arm/mm/proc-arm1020.S linux/arch/arm/mm/proc-arm1020.S --- v2.4.14/linux/arch/arm/mm/proc-arm1020.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/proc-arm1020.S Fri Nov 9 13:58:02 2001 @@ -0,0 +1,762 @@ +/* + * linux/arch/arm/mm/arm1020.S: MMU functions for ARM1020 + * + * Copyright (C) 2000 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * 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 + * + * + * These are the low level assembler for performing cache and TLB + * functions on the arm1020. + */ +#include <linux/linkage.h> +#include <linux/config.h> +#include <asm/assembler.h> +#include <asm/constants.h> +#include <asm/procinfo.h> +#include <asm/hardware.h> + +/* + * This is the maximum size of an area which will be invalidated + * using the single invalidate entry instructions. Anything larger + * than this, and we go for the whole cache. + * + * This value should be chosen such that we choose the cheapest + * alternative. + */ +#define MAX_AREA_SIZE 32768 + +/* + * the cache line size of the I and D cache + */ +#define DCACHELINESIZE 32 +#define ICACHELINESIZE 32 + +/* + * and the page size + */ +#define PAGESIZE 4096 + + .text + +/* + * cpu_arm1020_data_abort() + * + * obtain information about current aborted instruction + * + * r0 = address of aborted instruction + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR + */ + .align 5 +ENTRY(cpu_arm1020_data_abort) + ldr r1, [r0] @ read aborted instruction + mrc p15, 0, r0, c6, c0, 0 @ get FAR + tst r1, r1, lsr #21 @ C = bit 20 + mrc p15, 0, r3, c5, c0, 0 @ get FSR + sbc r1, r1, r1 @ r1 = C - 1 + and r3, r3, #255 + mov pc, lr + +/* + * cpu_arm1020_check_bugs() + */ +ENTRY(cpu_arm1020_check_bugs) + mrs ip, cpsr + bic ip, ip, #F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_arm1020_proc_init() + */ +ENTRY(cpu_arm1020_proc_init) + mov pc, lr + +/* + * cpu_arm1020_proc_fin() + */ +ENTRY(cpu_arm1020_proc_fin) + stmfd sp!, {lr} + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip + bl cpu_arm1020_cache_clean_invalidate_all + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} + +/* + * cpu_arm1020_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_arm1020_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 + +/* + * cpu_arm1020_do_idle() + */ + .align 5 +ENTRY(cpu_arm1020_do_idle) + mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* ================================= CACHE ================================ */ + + +/* + * cpu_arm1020_cache_clean_invalidate_all() + * + * clean and invalidate all cache lines + * + * Note: + * 1. we should preserve r0 at all times + */ + .align 5 +ENTRY(cpu_arm1020_cache_clean_invalidate_all) + mov r2, #1 +cpu_arm1020_cache_clean_invalidate_all_r2: +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, ip, c7, c10, 4 + + mov r1, #0xf @ 16 segments +1: mov r3, #0x3F @ 64 entries +2: mov ip, r3, LSL #26 @ shift up entry + orr ip, ip, r1, LSL #5 @ shift in/up index + mcr p15, 0, ip, c7, c14, 2 @ Clean & Inval DCache entry + mcr p15, 0, ip, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov ip, ip +#endif + subs r3, r3, #1 + cmp r3, #0 + bge 2b @ entries 3F to 0 + subs r1, r1, #1 + cmp r1, #0 + bge 1b @ segments 7 to 0 +#endif + +#ifdef CONFIG_CPU_ARM1020_I_CACHE_ON + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache +#endif + mcr p15, 0, ip, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov ip, ip + mov ip, ip +#endif + mov pc, lr + +/* + * cpu_arm1020_cache_clean_invalidate_range(start, end, flags) + * + * clean and invalidate all cache lines associated with this area of memory + * + * start: Area start address + * end: Area end address + * flags: nonzero for I cache as well + */ + .align 5 +ENTRY(cpu_arm1020_cache_clean_invalidate_range) + bic r0, r0, #DCACHELINESIZE - 1 + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_arm1020_cache_clean_invalidate_all_r2 + mcr p15, 0, r3, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcr p15, 0, r3, c7, c10, 4 @ drain WB + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcr p15, 0, r3, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b +#endif + +#ifdef CONFIG_CPU_ARM1020_I_CACHE_ON + teq r2, #0 + movne r0, #0 + mcrne p15, 0, r0, c7, c5, 0 @ invalidate I cache +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif +#endif + mov pc, lr + +/* + * cpu_arm1020_flush_ram_page(page) + * + * clean and invalidate all cache lines associated with this area of memory + * + * page: page to clean and invalidate + */ + .align 5 +ENTRY(cpu_arm1020_flush_ram_page) + mcr p15, 0, r1, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + subs r1, r1, #2 * DCACHELINESIZE + bne 1b + mov r0, #0 + +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* ================================ D-CACHE =============================== */ + +/* + * cpu_arm1020_dcache_invalidate_range(start, end) + * + * throw away all D-cached data in specified region without an obligation + * to write them back. Note however that we must clean the D-cached entries + * around the boundaries if the start and/or end address are not cache + * aligned. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm1020_dcache_invalidate_range) +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + /* D cache are on */ + tst r0, #DCACHELINESIZE - 1 + bic r0, r0, #DCACHELINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 4 + mcrne p15, 0, r0, c7, c10, 1 @ clean D entry at start + mcrne p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + tst r1, #DCACHELINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 4 + mcrne p15, 0, r1, c7, c10, 1 @ clean D entry at end + mcrne p15, 0, r1, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r1, r1 + mov r1, r1 + mov r1, r1 +#endif + +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b +#else + /* D cache off, but still drain the write buffer */ + mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif +#endif + mov pc, lr + +/* + * cpu_arm1020_dcache_clean_range(start, end) + * + * For the specified virtual address range, ensure that all caches contain + * clean data, such that peripheral accesses to the physical RAM fetch + * correct data. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm1020_dcache_clean_range) + bic r0, r0, #DCACHELINESIZE - 1 + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_arm1020_cache_clean_invalidate_all_r2 + mcr p15, 0, r3, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcr p15, 0, r3, c7, c10, 4 @ drain WB + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcr p15, 0, r3, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b +#endif + +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* + * cpu_arm1020_dcache_clean_page(page) + * + * Cleans a single page of dcache so that if we have any future aliased + * mappings, they will be consistent at the time that they are created. + * + * page: virtual address of page to clean from dcache + * + * Note: + * 1. we don't need to flush the write buffer in this case. + * 2. we don't invalidate the entries since when we write the page + * out to disk, the entries may get reloaded into the cache. + */ + .align 5 +ENTRY(cpu_arm1020_dcache_clean_page) + mov r1, #PAGESIZE + mcr p15, 0, r0, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bhi 1b +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* + * cpu_arm1020_dcache_clean_entry(addr) + * + * Clean the specified entry of any caches such that the MMU + * translation fetches will obtain correct data. + * + * addr: cache-unaligned virtual address + */ + .align 5 +ENTRY(cpu_arm1020_dcache_clean_entry) + mov r1, #0 + mcr p15, 0, r1, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, r0, c7, c10, 1 @ clean single D entry + mcr p15, 0, r1, c7, c10, 4 @ drain WB +#endif +#ifdef CONFIG_CPU_ARM1020_I_CACHE_ON + mcr p15, 0, r1, c7, c5, 1 @ invalidate I entry +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r1, r1 + mov r1, r1 +#endif + mov pc, lr + +/* ================================ I-CACHE =============================== */ + +/* + * cpu_arm1020_icache_invalidate_range(start, end) + * + * invalidate a range of virtual addresses from the Icache + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm1020_icache_invalidate_range) +1: mcr p15, 0, r0, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, r0, c7, c10, 1 @ Clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ Clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blo 1b +ENTRY(cpu_arm1020_icache_invalidate_page) + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* ================================== TLB ================================= */ + +/* + * cpu_arm1020_tlb_invalidate_all() + * + * Invalidate all TLB entries + */ + .align 5 +ENTRY(cpu_arm1020_tlb_invalidate_all) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D tlbs +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* + * cpu_arm1020_tlb_invalidate_range(start, end) + * + * invalidate TLB entries covering the specified range + * + * start: range start address + * end: range end address + */ + .align 5 +ENTRY(cpu_arm1020_tlb_invalidate_range) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + add r0, r0, #PAGESIZE +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 +#endif + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm1020_tlb_invalidate_page(page, flags) + * + * invalidate the TLB entries for the specified page. + * + * page: page to invalidate + * flags: non-zero if we include the I TLB + */ + .align 5 +ENTRY(cpu_arm1020_tlb_invalidate_page) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + teq r1, #0 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* =============================== PageTable ============================== */ + +/* + * cpu_arm1020_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_arm1020_set_pgd) +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, r3, c7, c10, 4 + mov r1, #0xF @ 16 segments +1: mov r3, #0x3F @ 64 entries +2: mov ip, r3, LSL #26 @ shift up entry + orr ip, ip, r1, LSL #5 @ shift in/up index + mcr p15, 0, ip, c7, c14, 2 @ Clean & Inval DCache entry + mov ip, #0 + mcr p15, 0, ip, c7, c10, 4 +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov ip, ip +#endif + subs r3, r3, #1 + cmp r3, #0 + bge 2b @ entries 3F to 0 + subs r1, r1, #1 + cmp r1, #0 + bge 1b @ segments 15 to 0 + +#endif + mov r1, #0 +#ifdef CONFIG_CPU_ARM1020_I_CACHE_ON + mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache +#endif + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov ip, ip + mov ip, ip +#endif + mov pc, lr + +/* + * cpu_arm1020_set_pmd(pmdp, pmd) + * + * Set a level 1 translation table entry, and clean it out of + * any caches such that the MMUs can load it correctly. + * + * pmdp: pointer to PMD entry + * pmd: PMD value to store + */ + .align 5 +ENTRY(cpu_arm1020_set_pmd) +#ifdef CONFIG_CPU_ARM1020_FORCE_WRITE_THROUGH + eor r2, r1, #0x0a @ C & Section + tst r2, #0x0b + biceq r1, r1, #4 @ clear bufferable bit +#endif + str r1, [r0] +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, r0, c7, c10, 4 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + +/* + * cpu_arm1020_set_pte(ptep, pte) + * + * Set a PTE and flush it out + */ + .align 5 +ENTRY(cpu_arm1020_set_pte) + str r1, [r0], #-1024 @ linux version + + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? + movne r2, #0 + +#ifdef CONFIG_CPU_ARM1020_FORCE_WRITE_THROUGH + eor r3, r1, #0x0a @ C & small page? + tst r3, #0x0b + biceq r2, r2, #4 +#endif + str r2, [r0] @ hardware version + mov r0, r0 +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + mcr p15, 0, r0, c7, c10, 4 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + mov r0, r0 + mov r0, r0 +#endif + mov pc, lr + + +cpu_manu_name: + .asciz "ARM/VLSI" +ENTRY(cpu_arm1020_name) + .ascii "Arm1020" +#if defined(CONFIG_CPU_ARM1020_CPU_IDLE) + .ascii "s" +#endif +#if defined(CONFIG_CPU_ARM1020_I_CACHE_ON) + .ascii "i" +#endif +#if defined(CONFIG_CPU_ARM1020_D_CACHE_ON) + .ascii "d" +#if defined(CONFIG_CPU_ARM1020_FORCE_WRITE_THROUGH) + .ascii "(wt)" +#else + .ascii "(wb)" +#endif +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + .ascii "B" +#endif +#ifdef CONFIG_CPU_ARM1020_ROUND_ROBIN + .ascii "RR" +#endif + .ascii "\0" + .align + + .section ".text.init", #alloc, #execinstr + +__arm1020_setup: + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 +/* + * Clear out 'unwanted' bits (then put them in if we need them) + */ + bic r0, r0, #0x0e00 @ ....??r......... + bic r0, r0, #0x0002 @ ..............a. + bic r0, r0, #0x000c @ W,D + bic r0, r0, #0x1000 @ I +/* + * Turn on what we want + */ + orr r0, r0, #0x0031 @ ..........DP...M + orr r0, r0, #0x0100 @ .......S........ + +#ifdef CONFIG_CPU_ARM1020_ROUND_ROBIN + orr r0, r0, #0x4000 @ .R.............. +#endif +#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION + orr r0, r0, #0x0800 @ ....Z........... +#endif +#ifdef CONFIG_CPU_ARM1020_D_CACHE_ON + orr r0, r0, #0x0004 @ Enable D cache +#endif +#ifdef CONFIG_CPU_ARM1020_I_CACHE_ON + orr r0, r0, #0x1000 @ I Cache on +#endif + mov pc, lr + + .text + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm1020_processor_functions, #object +arm1020_processor_functions: + .word cpu_arm1020_data_abort + .word cpu_arm1020_check_bugs + .word cpu_arm1020_proc_init + .word cpu_arm1020_proc_fin + .word cpu_arm1020_reset + .word cpu_arm1020_do_idle + + /* cache */ + .word cpu_arm1020_cache_clean_invalidate_all + .word cpu_arm1020_cache_clean_invalidate_range + .word cpu_arm1020_flush_ram_page + + /* dcache */ + .word cpu_arm1020_dcache_invalidate_range + .word cpu_arm1020_dcache_clean_range + .word cpu_arm1020_dcache_clean_page + .word cpu_arm1020_dcache_clean_entry + + /* icache */ + .word cpu_arm1020_icache_invalidate_range + .word cpu_arm1020_icache_invalidate_page + + /* tlb */ + .word cpu_arm1020_tlb_invalidate_all + .word cpu_arm1020_tlb_invalidate_range + .word cpu_arm1020_tlb_invalidate_page + + /* pgtable */ + .word cpu_arm1020_set_pgd + .word cpu_arm1020_set_pmd + .word cpu_arm1020_set_pte + .size arm1020_processor_functions, . - arm1020_processor_functions + + .type cpu_arm1020_info, #object +cpu_arm1020_info: + .long cpu_manu_name + .long cpu_arm1020_name + .size cpu_arm1020_info, . - cpu_arm1020_info + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __arm1020_proc_info,#object +__arm1020_proc_info: + .long 0x4100a200 + .long 0xff00fff0 + .long 0x00000c02 @ mmuflags + b __arm1020_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_arm1020_info + .long arm1020_processor_functions + .size __arm1020_proc_info, . - __arm1020_proc_info diff -u --recursive --new-file v2.4.14/linux/arch/arm/mm/proc-arm926.S linux/arch/arm/mm/proc-arm926.S --- v2.4.14/linux/arch/arm/mm/proc-arm926.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/proc-arm926.S Fri Nov 9 13:58:02 2001 @@ -0,0 +1,667 @@ +/* + * linux/arch/arm/mm/arm926.S: MMU functions for ARM926EJ-S + * + * Copyright (C) 1999-2001 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * 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 + * + * + * These are the low level assembler for performing cache and TLB + * functions on the arm926. + */ +#include <linux/linkage.h> +#include <linux/config.h> +#include <asm/assembler.h> +#include <asm/constants.h> +#include <asm/procinfo.h> +#include <asm/hardware.h> + +/* + * This is the maximum size of an area which will be invalidated + * using the single invalidate entry instructions. Anything larger + * than this, and we go for the whole cache. + * + * This value should be chosen such that we choose the cheapest + * alternative. + */ +#define MAX_AREA_SIZE 16384 + +/* + * the cache line size of the I and D cache + */ +#define DCACHELINESIZE 32 +#define ICACHELINESIZE 32 + +/* + * and the page size + */ +#define PAGESIZE 4096 + + .text + +/* + * cpu_arm926_data_abort() + * + * obtain information about current aborted instruction + * + * Inputs: + * r0 = address of abort + * r1 = cpsr of abort + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR + */ + .align 5 +ENTRY(cpu_arm926_data_abort) + tst r1, #1<<24 @ Check for Jbit (NE -> found) + movne r1, #-1 @ Mark as writing + bne 2f + + tst r1, #1<<5 @ Check for Thumb-bit (NE -> found) + ldrneh r1, [r0] @ Read aborted Thumb instruction + tstne r1, r1, lsr #12 @ C = bit 11 + + ldreq r1, [r0] @ Read aborted ARM instruction + tsteq r1, r1, lsr #21 @ C = bit 20 + + sbc r1, r1, r1 @ r1 = C - 1 +2: + mrc p15, 0, r3, c5, c0, 0 @ get FSR + and r3, r3, #255 + mrc p15, 0, r0, c6, c0, 0 @ get FAR + + mov pc, lr + +/* + * cpu_arm926_check_bugs() + */ +ENTRY(cpu_arm926_check_bugs) + mrs ip, cpsr + bic ip, ip, #F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_arm926_proc_init() + */ +ENTRY(cpu_arm926_proc_init) + mov pc, lr + +/* + * cpu_arm926_proc_fin() + */ +ENTRY(cpu_arm926_proc_fin) + stmfd sp!, {lr} + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip + bl cpu_arm926_cache_clean_invalidate_all + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} + +/* + * cpu_arm926_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_arm926_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 + +/* + * cpu_arm926_do_idle() + */ + .align 5 +ENTRY(cpu_arm926_do_idle) +#if defined(CONFIG_CPU_ARM926_CPU_IDLE) + mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt +#endif + mov pc, lr + +/* ================================= CACHE ================================ */ + + +/* + * cpu_arm926_cache_clean_invalidate_all() + * + * clean and invalidate all cache lines + * + * Note: + * 1. we should preserve r0 at all times + */ + .align 5 +ENTRY(cpu_arm926_cache_clean_invalidate_all) + mov r2, #1 +cpu_arm926_cache_clean_invalidate_all_r2: + mov ip, #0 +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else +1: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate + bne 1b +#endif + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm926_cache_clean_invalidate_range(start, end, flags) + * + * clean and invalidate all cache lines associated with this area of memory + * + * This is a little misleading, it is not intended to clean out + * the i-cache but to make sure that any data written to the + * range is made consistant. This means that when we execute code + * in that region, everything works as we expect. + * + * This generally means writing back data in the Dcache and + * write buffer and flushing the Icache over that region + * start: Area start address + * end: Area end address + * flags: nonzero for I cache as well + */ + .align 5 +ENTRY(cpu_arm926_cache_clean_invalidate_range) + bic r0, r0, #DCACHELINESIZE - 1 @ && added by PGM + bic r1, r1, #DCACHELINESIZE - 1 @ && added by DHM + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_arm926_cache_clean_invalidate_all_r2 + +1: teq r2, #0 +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE +#else + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry + add r0, r0, #DCACHELINESIZE +#endif + + cmp r0, r1 + blt 1b + + mcr p15, 0, r1, c7, c10, 4 @ drain WB + + mov pc, lr + +/* + * cpu_arm926_flush_ram_page(page) + * + * clean and invalidate all cache lines associated with this area of memory + * + * page: page to clean and invalidate + */ + .align 5 +ENTRY(cpu_arm926_flush_ram_page) + mov r1, #PAGESIZE +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE +#else +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE +#endif + subs r1, r1, #2 * DCACHELINESIZE + bne 1b + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ D-CACHE =============================== */ + +/* + * cpu_arm926_dcache_invalidate_range(start, end) + * + * throw away all D-cached data in specified region without an obligation + * to write them back. Note however that we must clean the D-cached entries + * around the boundaries if the start and/or end address are not cache + * aligned. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm926_dcache_invalidate_range) +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + tst r0, #DCACHELINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 1 @ clean D entry + tst r1, #DCACHELINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 1 +#endif @ clean D entry + bic r0, r0, #DCACHELINESIZE - 1 + bic r1, r1, #DCACHELINESIZE - 1 +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm926_dcache_clean_range(start, end) + * + * For the specified virtual address range, ensure that all caches contain + * clean data, such that peripheral accesses to the physical RAM fetch + * correct data. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm926_dcache_clean_range) +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + bic r0, r0, #DCACHELINESIZE - 1 + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + mov r2, #0 + bgt cpu_arm926_cache_clean_invalidate_all_r2 + + bic r1, r1, #DCACHELINESIZE -1 + add r1, r1, #DCACHELINESIZE + +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #DCACHELINESIZE + bpl 1b +#endif + mcr p15, 0, r2, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm926_dcache_clean_page(page) + * + * Cleans a single page of dcache so that if we have any future aliased + * mappings, they will be consistent at the time that they are created. + * + * page: virtual address of page to clean from dcache + * + * Note: + * 1. we don't need to flush the write buffer in this case. + * 2. we don't invalidate the entries since when we write the page + * out to disk, the entries may get reloaded into the cache. + */ + .align 5 +ENTRY(cpu_arm926_dcache_clean_page) +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bne 1b +#endif + mov pc, lr + +/* + * cpu_arm926_dcache_clean_entry(addr) + * + * Clean the specified entry of any caches such that the MMU + * translation fetches will obtain correct data. + * + * addr: cache-unaligned virtual address + */ + .align 5 +ENTRY(cpu_arm926_dcache_clean_entry) +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ I-CACHE =============================== */ + +/* + * cpu_arm926_icache_invalidate_range(start, end) + * + * invalidate a range of virtual addresses from the Icache + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm926_icache_invalidate_range) + bic r0, r0, #DCACHELINESIZE - 1 @ Safety check + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + bgt cpu_arm926_cache_clean_invalidate_all_r2 + + bic r1, r1, #DCACHELINESIZE - 1 + add r1, r1, #DCACHELINESIZE + +1: mcr p15, 0, r0, c7, c5, 1 @ clean I entries + add r0, r0, #DCACHELINESIZE + subs r1, r1, #DCACHELINESIZE + bne 1b + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +ENTRY(cpu_arm926_icache_invalidate_page) + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mov pc, lr + + +/* ================================== TLB ================================= */ + +/* + * cpu_arm926_tlb_invalidate_all() + * + * Invalidate all TLB entries + */ + .align 5 +ENTRY(cpu_arm926_tlb_invalidate_all) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_arm926_tlb_invalidate_range(start, end) + * + * invalidate TLB entries covering the specified range + * + * start: range start address + * end: range end address + */ + .align 5 +ENTRY(cpu_arm926_tlb_invalidate_range) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + + mov r3, #PAGESIZE + sub r3, r3, #1 + bic r0, r0, r3 + bic r1, r1, r3 + +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + add r0, r0, #PAGESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm926_tlb_invalidate_page(page, flags) + * + * invalidate the TLB entries for the specified page. + * + * page: page to invalidate + * flags: non-zero if we include the I TLB + */ + .align 5 +ENTRY(cpu_arm926_tlb_invalidate_page) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + teq r1, #0 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + mov pc, lr + +/* =============================== PageTable ============================== */ + +/* + * cpu_arm926_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_arm926_set_pgd) + mov ip, #0 +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH + /* Any reason why we don't use mcr p15, 0, r0, c7, c7, 0 here? --rmk */ + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else +@ && 'Clean & Invalidate whole DCache' +1: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate + bne 1b +#endif + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_arm926_set_pmd(pmdp, pmd) + * + * Set a level 1 translation table entry, and clean it out of + * any caches such that the MMUs can load it correctly. + * + * pmdp: pointer to PMD entry + * pmd: PMD value to store + */ + .align 5 +ENTRY(cpu_arm926_set_pmd) +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH + eor r2, r1, #0x0a @ C & Section + tst r2, #0x0b + biceq r1, r1, #4 @ clear bufferable bit +#endif + str r1, [r0] +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm926_set_pte(ptep, pte) + * + * Set a PTE and flush it out + */ + .align 5 +ENTRY(cpu_arm926_set_pte) + str r1, [r0], #-1024 @ linux version + + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? + movne r2, #0 + +#ifdef CONFIG_CPU_ARM926_WRITETHROUGH + eor r3, r2, #0x0a @ C & small page? + tst r3, #0x0b + biceq r2, r2, #4 +#endif + str r2, [r0] @ hardware version + mov r0, r0 +#ifndef CONFIG_CPU_ARM926_WRITETHROUGH + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + + +cpu_manu_name: + .asciz "ARM" +ENTRY(cpu_arm926_name) + .ascii "ARM926EJ-S" +#if defined(CONFIG_CPU_ARM926_CPU_IDLE) + .ascii "s" +#endif +#if defined(CONFIG_CPU_ARM926_I_CACHE_ON) + .ascii "i" +#endif +#if defined(CONFIG_CPU_ARM926_D_CACHE_ON) + .ascii "d" +#if defined(CONFIG_CPU_ARM926_WRITETHROUGH) + .ascii "(wt)" +#else + .ascii "(wb)" +#endif +#ifdef CONFIG_CPU_ARM926_ROUND_ROBIN + .ascii "RR" +#endif +#endif + .ascii "\0" + .align + + .section ".text.init", #alloc, #execinstr + +__arm926_setup: + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + + +#if defined(CONFIG_CPU_ARM926_WRITETHROUGH) + mov r0, #4 @ disable write-back on caches explicitly + mcr p15, 7, r0, c15, c0, 0 +#endif + + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 +/* + * Clear out 'unwanted' bits (then put them in if we need them) + */ + @ VI ZFRS BLDP WCAM + bic r0, r0, #0x0e00 + bic r0, r0, #0x0002 + bic r0, r0, #0x000c + bic r0, r0, #0x1000 @ ...0 000. .... 000. +/* + * Turn on what we want + */ + orr r0, r0, #0x0031 + orr r0, r0, #0x2100 @ ..1. ...1 ..11 ...1 + +#ifdef CONFIG_CPU_ARM926_ROUND_ROBIN + orr r0, r0, #0x4000 @ .1.. .... .... .... +#endif +#ifdef CONFIG_CPU_ARM926_D_CACHE_ON + orr r0, r0, #0x0004 @ .... .... .... .1.. +#endif +#ifdef CONFIG_CPU_ARM926_I_CACHE_ON + orr r0, r0, #0x1000 @ ...1 .... .... .... +#endif + mov pc, lr + + .text + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm926_processor_functions, #object +arm926_processor_functions: + .word cpu_arm926_data_abort + .word cpu_arm926_check_bugs + .word cpu_arm926_proc_init + .word cpu_arm926_proc_fin + .word cpu_arm926_reset + .word cpu_arm926_do_idle + + /* cache */ + .word cpu_arm926_cache_clean_invalidate_all + .word cpu_arm926_cache_clean_invalidate_range + .word cpu_arm926_flush_ram_page + + /* dcache */ + .word cpu_arm926_dcache_invalidate_range + .word cpu_arm926_dcache_clean_range + .word cpu_arm926_dcache_clean_page + .word cpu_arm926_dcache_clean_entry + + /* icache */ + .word cpu_arm926_icache_invalidate_range + .word cpu_arm926_icache_invalidate_page + + /* tlb */ + .word cpu_arm926_tlb_invalidate_all + .word cpu_arm926_tlb_invalidate_range + .word cpu_arm926_tlb_invalidate_page + + /* pgtable */ + .word cpu_arm926_set_pgd + .word cpu_arm926_set_pmd + .word cpu_arm926_set_pte + .size arm926_processor_functions, . - arm926_processor_functions + + .type cpu_arm926_info, #object +cpu_arm926_info: + .long cpu_manu_name + .long cpu_arm926_name + .size cpu_arm926_info, . - cpu_arm926_info + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv5EJ" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v5EJ" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __arm926_proc_info,#object +__arm926_proc_info: + .long 0x41009260 + .long 0xff00fff0 + .long 0x00000c1e @ mmuflags + b __arm926_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_arm926_info + .long arm926_processor_functions + .size __arm926_proc_info, . - __arm926_proc_info diff -u --recursive --new-file v2.4.14/linux/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types --- v2.4.14/linux/arch/arm/tools/mach-types Mon Nov 5 15:55:26 2001 +++ linux/arch/arm/tools/mach-types Fri Nov 9 13:58:02 2001 @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Mon Oct 22 09:49:06 2001 +# Last update: Fri Oct 26 17:37:13 2001 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -134,3 +134,6 @@ epsilon1 SA1100_EPSILON1 EPSILON1 123 balloon SA1100_BALLOON BALLOON 124 puppy ARCH_PUPPY PUPPY 125 +elroy SA1100_ELROY ELROY 126 +gms720 ARCH_GMS720 GMS720 127 +s24x ARCH_S24X S24X 128 diff -u --recursive --new-file v2.4.14/linux/arch/cris/defconfig linux/arch/cris/defconfig --- v2.4.14/linux/arch/cris/defconfig Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/defconfig Fri Nov 9 13:58:02 2001 @@ -82,8 +82,9 @@ CONFIG_NET_ETHERNET=y # CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y -C# CONFIG_ETRAX_ETHERNET_LPSLAVE is not set -ONFIG_ETRAX_SERIAL=y +# CONFIG_ETRAX_ETHERNET_LPSLAVE is not set +CONFIG_ETRAX_SERIAL=y +CONFIG_ETRAX_SERIAL_PORT0=y # CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set CONFIG_ETRAX_SERIAL_PORT1=y # CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set diff -u --recursive --new-file v2.4.14/linux/arch/cris/drivers/Config.in linux/arch/cris/drivers/Config.in --- v2.4.14/linux/arch/cris/drivers/Config.in Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/drivers/Config.in Fri Nov 9 13:58:02 2001 @@ -23,6 +23,14 @@ bool 'Serial-port support' CONFIG_ETRAX_SERIAL if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then +# bool ' Use fast timers for DMA flush and RS-485 timing' CONFIG_ETRAX_SERIAL_FAST_TIMER n + define_bool CONFIG_ETRAX_SERIAL_FAST_TIMER n + if [ "$CONFIG_ETRAX_SERIAL_FAST_TIMER" = "n" ]; then + bool ' Fast serial port DMA flush' CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST + if [ "$CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST" = "n" ]; then + int ' Receive flush timeout (ticks) ' CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 + fi + fi bool ' Serial port 0 enabled' CONFIG_ETRAX_SERIAL_PORT0 if [ "$CONFIG_ETRAX_SERIAL_PORT0" = "y" ]; then bool ' Ser0 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB diff -u --recursive --new-file v2.4.14/linux/arch/cris/drivers/axisflashmap.c linux/arch/cris/drivers/axisflashmap.c --- v2.4.14/linux/arch/cris/drivers/axisflashmap.c Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/drivers/axisflashmap.c Fri Nov 9 13:58:02 2001 @@ -11,6 +11,9 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * Revision 1.15 2001/10/19 12:41:04 jonashg + * Name of probe has changed in MTD. + * * Revision 1.14 2001/09/21 07:14:10 jonashg * Made root filesystem (cramfs) use mtdblock driver when booting from flash. * @@ -237,7 +240,9 @@ printk(KERN_NOTICE "Axis flash mapping: %x at %x\n", WINDOW_SIZE, FLASH_CACHED_ADDR); - mymtd = (struct mtd_info *)do_map_probe("cfi", &axis_map); +#ifdef CONFIG_MTD_CFI + mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &axis_map); +#endif #ifdef CONFIG_MTD_AMDSTD if (!mymtd) { diff -u --recursive --new-file v2.4.14/linux/arch/cris/drivers/gpio.c linux/arch/cris/drivers/gpio.c --- v2.4.14/linux/arch/cris/drivers/gpio.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/drivers/gpio.c Fri Nov 9 13:58:02 2001 @@ -1,4 +1,4 @@ -/* $Id: gpio.c,v 1.9 2001/05/04 14:16:07 matsfg Exp $ +/* $Id: gpio.c,v 1.11 2001/10/30 14:39:12 johana Exp $ * * Etrax general port I/O device * @@ -6,9 +6,18 @@ * * Authors: Bjorn Wesen (initial version) * Ola Knutsson (LED handling) - * Johan Adolfsson (read/set directions) + * Johan Adolfsson (read/set directions, write) * * $Log: gpio.c,v $ + * Revision 1.11 2001/10/30 14:39:12 johana + * Added D() around gpio_write printk. + * + * Revision 1.10 2001/10/25 10:24:42 johana + * Added IO_CFG_WRITE_MODE ioctl and write method that can do fast + * bittoggling in the kernel. (This speeds up programming an FPGA with 450kB + * from ~60 seconds to 4 seconds). + * Added save_flags/cli/restore_flags in ioctl. + * * Revision 1.9 2001/05/04 14:16:07 matsfg * Corrected spelling error * @@ -69,6 +78,8 @@ static int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static ssize_t gpio_write(struct file * file, const char * buf, size_t count, + loff_t *off); static int gpio_open(struct inode *inode, struct file *filp); static int gpio_release(struct inode *inode, struct file *filp); static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait); @@ -82,6 +93,9 @@ unsigned char changeable_dir; unsigned char changeable_bits; unsigned char highalarm, lowalarm; + unsigned char clk_mask; + unsigned char data_mask; + unsigned char write_msb; wait_queue_head_t alarm_wq; int minor; }; @@ -139,6 +153,59 @@ return 1; } +static ssize_t gpio_write(struct file * file, const char * buf, size_t count, + loff_t *off) +{ + struct gpio_private *priv = (struct gpio_private *)file->private_data; + unsigned char data, clk_mask, data_mask, write_msb; + unsigned long flags; + ssize_t retval = count; + if (verify_area(VERIFY_READ, buf, count)) + { + return -EFAULT; + } + clk_mask = priv->clk_mask; + data_mask = priv->data_mask; + /* It must have been configured using the IO_CFG_WRITE_MODE */ + /* Perhaps a better error code? */ + if (clk_mask == 0 || data_mask == 0) + { + return -EPERM; + } + write_msb = priv->write_msb; + D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb)); + while (count--) { + int i; + data = *buf++; + if (priv->write_msb) { + for (i = 7; i>=0;i--) { + save_flags(flags); cli(); + *priv->port = *priv->shadow &= ~clk_mask; + if (data & 1<<i) + *priv->port = *priv->shadow |= data_mask; + else + *priv->port = *priv->shadow &= ~data_mask; + /* For FPGA: min 5.0ns (DCC) before CCLK high */ + *priv->port = *priv->shadow |= clk_mask; + restore_flags(flags); + } + } else { + for (i = 0; i<=7;i++) { + save_flags(flags); cli(); + *priv->port = *priv->shadow &= ~clk_mask; + if (data & 1<<i) + *priv->port = *priv->shadow |= data_mask; + else + *priv->port = *priv->shadow &= ~data_mask; + /* For FPGA: min 5.0ns (DCC) before CCLK high */ + *priv->port = *priv->shadow |= clk_mask; + restore_flags(flags); + } + } + } + return retval; +} + static int gpio_open(struct inode *inode, struct file *filp) { @@ -170,6 +237,8 @@ priv->highalarm = 0; priv->lowalarm = 0; + priv->clk_mask = 0; + priv->data_mask = 0; init_waitqueue_head(&priv->alarm_wq); filp->private_data = (void *)priv; @@ -209,8 +278,8 @@ gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + unsigned long flags; struct gpio_private *priv = (struct gpio_private *)file->private_data; - if(_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { return -EINVAL; } @@ -220,14 +289,18 @@ // read the port return *priv->port; case IO_SETBITS: + save_flags(flags); cli(); // set changeable bits with a 1 in arg *priv->port = *priv->shadow |= ((unsigned char)arg & priv->changeable_bits); + restore_flags(flags); break; case IO_CLRBITS: + save_flags(flags); cli(); // clear changeable bits with a 1 in arg *priv->port = *priv->shadow &= ~((unsigned char)arg & priv->changeable_bits); + restore_flags(flags); break; case IO_HIGHALARM: // set alarm when bits with 1 in arg go high @@ -246,14 +319,18 @@ /* Read direction 0=input 1=output */ return *priv->dir_shadow; case IO_SETINPUT: + save_flags(flags); cli(); /* Set direction 0=unchanged 1=input */ *priv->dir = *priv->dir_shadow &= ~((unsigned char)arg & priv->changeable_dir); + restore_flags(flags); return *priv->dir_shadow; case IO_SETOUTPUT: + save_flags(flags); cli(); /* Set direction 0=unchanged 1=output */ *priv->dir = *priv->dir_shadow |= ((unsigned char)arg & priv->changeable_dir); + restore_flags(flags); return *priv->dir_shadow; case IO_SHUTDOWN: SOFT_SHUTDOWN(); @@ -265,6 +342,24 @@ #else return 0; #endif + break; + case IO_CFG_WRITE_MODE: + priv->clk_mask = arg & 0xFF; + priv->data_mask = (arg >> 8) & 0xFF; + priv->write_msb = (arg >> 16) & 0x01; + /* Check if we're allowed to change the bits and + * the direction is correct + */ + if (!((priv->clk_mask & priv->changeable_bits) && + (priv->data_mask & priv->changeable_bits) && + (priv->clk_mask & *priv->dir_shadow) && + (priv->data_mask & *priv->dir_shadow)) ) + { + priv->clk_mask = 0; + priv->data_mask = 0; + return -EPERM; + } + break; default: if(priv->minor == LEDS) return gpio_leds_ioctl(cmd, arg); @@ -301,6 +396,7 @@ owner: THIS_MODULE, poll: gpio_poll, ioctl: gpio_ioctl, + write: gpio_write, open: gpio_open, release: gpio_release, }; @@ -338,7 +434,7 @@ #endif - printk("ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB\n"); + printk("ETRAX 100LX GPIO driver v2.2, (c) 2001 Axis Communications AB\n"); return res; } diff -u --recursive --new-file v2.4.14/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c --- v2.4.14/linux/arch/cris/drivers/serial.c Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/drivers/serial.c Fri Nov 9 13:58:02 2001 @@ -1,4 +1,4 @@ -/* $Id: serial.c,v 1.18 2001/09/24 09:27:22 pkj Exp $ +/* $Id: serial.c,v 1.23 2001/10/30 17:53:26 pkj Exp $ * * Serial port driver for the ETRAX 100LX chip * @@ -7,6 +7,27 @@ * Many, many authors. Based once upon a time on serial.c for 16x50. * * $Log: serial.c,v $ + * Revision 1.23 2001/10/30 17:53:26 pkj + * * Set info->uses_dma to 0 when a port is closed. + * * Mark the timer1 interrupt as a fast one (SA_INTERRUPT). + * * Call start_flush_timer() in start_receive() if + * CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is defined. + * + * Revision 1.22 2001/10/30 17:44:03 pkj + * Use %lu for received and transmitted counters in line_info(). + * + * Revision 1.21 2001/10/30 17:40:34 pkj + * Clean-up. The only change to functionality is that + * CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS(=5) is used instead of + * MAX_FLUSH_TIME(=8). + * + * Revision 1.20 2001/10/30 15:24:49 johana + * Added char_time stuff from 2.0 driver. + * + * Revision 1.19 2001/10/30 15:23:03 johana + * Merged with 1.13.2 branch + fixed indentation + * and changed CONFIG_ETRAX100_XYS to CONFIG_ETRAX_XYZ + * * Revision 1.18 2001/09/24 09:27:22 pkj * Completed ext_baud_table[] in cflag_to_baud() and cflag_to_etrax_baud(). * @@ -26,11 +47,19 @@ * Revision 1.14 2001/08/15 07:31:23 bjarne * Introduced two new members to the e100_serial struct. * configured - Will be set to 1 if the port has been configured in .config - * uses_dma - Should be set to 1 if the port uses DMA. Currently it is set to 1 + * uses_dma - Should be set to 1 if the port uses DMA. Currently it is set + * to 1 * when a port is opened. This is used to limit the DMA interrupt * routines to only manipulate DMA channels actually used by the * serial driver. * + * Revision 1.13.2.2 2001/10/17 13:57:13 starvik + * Receiver was broken by the break fixes + * + * Revision 1.13.2.1 2001/07/20 13:57:39 ronny + * Merge with new stuff from etrax100ser.c. Works but haven't checked stuff + * like break handling. + * * Revision 1.13 2001/05/09 12:40:31 johana * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h * @@ -226,7 +255,7 @@ * */ -static char *serial_version = "$Revision: 1.18 $"; +static char *serial_version = "$Revision: 1.23 $"; #include <linux/config.h> #include <linux/version.h> @@ -284,6 +313,11 @@ #define SERIAL_TYPE_CALLOUT 2 #endif +#define DEBUG_LOG(line, string, value) + +/* Add an x here to log a lot of timer stuff */ +#define TIMERD(x) + /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 @@ -299,8 +333,9 @@ expect the first received event on the serial port to be an error, break or similar. Used to be able to flash IRMA from eLinux */ -//#define SERIAL_HANDLE_EARLY_ERRORS +#define SERIAL_HANDLE_EARLY_ERRORS +#define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10) #ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS /* Default number of timer ticks before flushing rx fifo @@ -310,8 +345,6 @@ #define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 #endif -#define MAX_FLUSH_TIME 8 - #define _INLINE_ inline static void change_speed(struct e100_serial *info); @@ -320,7 +353,7 @@ const unsigned char *buf, int count); #define DEF_BAUD 0x99 /* 115.2 kbit/s */ -#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST ) +#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) #define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */ /* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */ #define DEF_TX 0x80 /* or SERIAL_CTRL_B */ @@ -335,6 +368,22 @@ #define REG_BAUD 3 #define REG_XOFF 4 /* this is a 32 bit register */ +/* The bitfields are the same for all serial ports */ +#define SER_RXD_MASK IO_MASK(R_SERIAL0_STATUS, rxd) +#define SER_DATA_AVAIL_MASK IO_MASK(R_SERIAL0_STATUS, data_avail) +#define SER_FRAMING_ERR_MASK IO_MASK(R_SERIAL0_STATUS, framing_err) +#define SER_PAR_ERR_MASK IO_MASK(R_SERIAL0_STATUS, par_err) +#define SER_OVERRUN_MASK IO_MASK(R_SERIAL0_STATUS, overrun) + +#define SER_ERROR_MASK (SER_OVERRUN_MASK | SER_PAR_ERR_MASK | SER_FRAMING_ERR_MASK) + +/* Values for info->errorcode */ +#define ERRCODE_SET_BREAK (TTY_BREAK) +#define ERRCODE_INSERT 0x100 +#define ERRCODE_INSERT_BREAK (ERRCODE_INSERT | TTY_BREAK) + +#define FORCE_EOP(info) *R_SET_EOP = 1U << info->iseteop; + /* * General note regarding the use of IO_* macros in this file: * @@ -413,6 +462,29 @@ static struct termios *serial_termios[NR_PORTS]; static struct termios *serial_termios_locked[NR_PORTS]; +#ifdef CONFIG_SERIAL_PROC_ENTRY +#define PROCSTAT(x) x +struct ser_statistics_type{ + int overrun_cnt; + int early_errors_cnt; + int ser_ints_ok_cnt; + int errors_cnt; + unsigned long int processing_flip; + unsigned long processing_flip_still_room; + unsigned long int timeout_flush_cnt; + int rx_dma_ints; + int tx_dma_ints; + int rx_tot; + int tx_tot; +}; + +static struct ser_statistics_type ser_stat[NR_PORTS]; + +#else + +#define PROCSTAT(x) + +#endif /* CONFIG_SERIAL_PROC_ENTRY */ /* RS-485 */ #if defined(CONFIG_ETRAX_RS485) @@ -577,10 +649,34 @@ /* enable timer1 irq */ *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); + fast_timer_started = 1; } #endif /* CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST */ +/* Calculate the chartime depending on baudrate, numbor of bits etc. */ +static void update_char_time(struct e100_serial * info) +{ + tcflag_t cflags = info->tty->termios->c_cflag; + int bits; + + /* calc. number of bits / data byte */ + /* databits + startbit and 1 stopbit */ + if ((cflags & CSIZE) == CS7) + bits = 9; + else + bits = 10; + + if (cflags & CSTOPB) /* 2 stopbits ? */ + bits++; + + if (cflags & PARENB) /* parity bit ? */ + bits++; + + /* calc timeout */ + info->char_time_usec = ((bits * 1000000) / info->baud) + 1; +} + /* * This function maps from the Bxxxx defines in asm/termbits.h into real * baud rates. @@ -642,7 +738,8 @@ e100_dtr(struct e100_serial *info, int set) { #ifndef CONFIG_SVINTO_SIM - unsigned char mask = ( 1 << e100_modem_pins[info->line].dtr_bit); + unsigned char mask = (1 << e100_modem_pins[info->line].dtr_bit); + #ifdef SERIAL_DEBUG_IO printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); printk("ser%i shadow before 0x%02X get: %i\n", @@ -651,7 +748,8 @@ #endif /* DTR is active low */ { - unsigned long flags; + unsigned long flags; + save_flags(flags); cli(); *e100_modem_pins[info->line].shadow &= ~mask; @@ -696,8 +794,9 @@ #ifndef CONFIG_SVINTO_SIM /* RI is active low */ { - unsigned char mask = ( 1 << e100_modem_pins[info->line].ri_bit); - unsigned long flags; + unsigned char mask = (1 << e100_modem_pins[info->line].ri_bit); + unsigned long flags; + save_flags(flags); cli(); *e100_modem_pins[info->line].shadow &= ~mask; @@ -718,8 +817,9 @@ #ifndef CONFIG_SVINTO_SIM /* CD is active low */ { - unsigned char mask = ( 1 << e100_modem_pins[info->line].cd_bit); - unsigned long flags; + unsigned char mask = (1 << e100_modem_pins[info->line].cd_bit); + unsigned long flags; + save_flags(flags); cli(); *e100_modem_pins[info->line].shadow &= ~mask; @@ -797,7 +897,7 @@ #ifdef SERIAL_HANDLE_EARLY_ERRORS /* in order to detect and fix errors on the first byte - we have to use the serial interrupts as well. */ + we have to use the serial interrupts as well. */ static inline void e100_disable_serial_data_irq(struct e100_serial *info) @@ -860,7 +960,7 @@ e100_disable_rxdma_irq(info); #endif - if (info->rs485.delay_rts_before_send > 0){ + if (info->rs485.delay_rts_before_send > 0) { current->timeout = jiffies + (info->rs485.delay_rts_before_send * HZ)/1000; current->state = TASK_INTERRUPTIBLE; schedule(); @@ -880,36 +980,38 @@ /* calc. number of bits / data byte */ cflags = info->tty->termios->c_cflag; + /* databits + startbit and 1 stopbit */ - if((cflags & CSIZE) == CS7) - bits = 9; + if ((cflags & CSIZE) == CS7) + bits = 9; else - bits = 10; + bits = 10; - if(cflags & CSTOPB) /* 2 stopbits ? */ - bits++; + if (cflags & CSTOPB) /* 2 stopbits ? */ + bits++; - if(cflags & PARENB) /* parity bit ? */ - bits++; + if (cflags & PARENB) /* parity bit ? */ + bits++; /* calc timeout */ delay_ms = ((bits * size * 1000) / info->baud) + 1; max_j = jiffies + (delay_ms * HZ)/1000 + 10; - while (jiffies < max_j ) { - if (info->port[REG_STATUS] & - IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { - for( i=0 ; i<100; i++ ) {}; - if (info->port[REG_STATUS] & - IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { - /* ~25 for loops per usec */ - stop_delay = 1000000 / info->baud; - if(cflags & CSTOPB) - stop_delay *= 2; - udelay(stop_delay); - break; - } - } + while (jiffies < max_j) { + if (info->port[REG_STATUS] & + IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { + for (i = 0; i < 100; i++) + ; + if (info->port[REG_STATUS] & + IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) { + /* ~25 for loops per usec */ + stop_delay = 1000000 / info->baud; + if (cflags & CSTOPB) + stop_delay *= 2; + udelay(stop_delay); + break; + } + } } e100_rts(info, info->rs485.rts_after_sent); @@ -1004,9 +1106,9 @@ * no-op - transmit_chars would never really be called during sim * since rs_write does not write into the xmit buffer then. */ - if(info->xmit.tail) + if (info->xmit.tail) printk("Error in serial.c:transmit_chars(), tail!=0\n"); - if(info->xmit.head != info->xmit.tail) { + if (info->xmit.head != info->xmit.tail) { SIMCOUT(info->xmit.buf + info->xmit.tail, CIRC_CNT(info->xmit.head, info->xmit.tail, @@ -1022,10 +1124,10 @@ IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); #ifdef SERIAL_DEBUG_INTR - if(info->line == SERIAL_DEBUG_LINE) + if (info->line == SERIAL_DEBUG_LINE) printk("tc\n"); #endif - if(!info->tr_running) { + if (!info->tr_running) { /* weirdo... we shouldn't get here! */ printk("Achtung: transmit_chars with !tr_running\n"); return; @@ -1037,7 +1139,7 @@ and update xmit accordingly */ /* if the stop bit was not set, all data has been sent */ - if(!(descr->status & d_stop)) { + if (!(descr->status & d_stop)) { sentl = descr->sw_len; } else /* otherwise we find the amount of data sent here */ @@ -1060,7 +1162,7 @@ c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); - if(c <= 0) { + if (c <= 0) { /* our job here is done, don't schedule any new DMA transfer */ info->tr_running = 0; @@ -1106,7 +1208,7 @@ start_transmit(struct e100_serial *info) { #if 0 - if(info->line == SERIAL_DEBUG_LINE) + if (info->line == SERIAL_DEBUG_LINE) printk("x\n"); #endif @@ -1118,7 +1220,6 @@ transmit_chars(info); } - static _INLINE_ void receive_chars(struct e100_serial *info) { @@ -1138,79 +1239,128 @@ /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ + // ? *info->iclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); - if(!tty) /* something wrong... */ + if (!tty) /* something wrong... */ return; descr = &info->rec_descr; - + /* find out how many bytes were read */ /* if the eop bit was not set, all data has been received */ - if(!(descr->status & d_eop)) { + if (!(descr->status & d_eop)) { recvl = descr->sw_len; } else { /* otherwise we find the amount of data received here */ recvl = descr->hw_len; } - if(recvl) { - unsigned char *buf; - struct async_icount *icount; - icount = &info->icount; - - /* update stats */ - icount->rx += recvl; + /* read the status register so we can detect errors, + * but we can't really do anything about those errors + * anyway, since we have the DMA in "force eop at error" mode + * the fault characters are not in the buffer anyway. + */ - /* read the status register so we can detect errors */ - rstat = info->port[REG_STATUS]; + rstat = info->port[REG_STATUS]; + + if ((rstat & SER_ERROR_MASK) != 0) { + unsigned char data; + /* if we got an error, we must reset it by reading the + * data_in field + */ + data = info->port[REG_DATA]; + PROCSTAT(ser_stat[info->line].errors_cnt++); + DEBUG_LOG(info->line, " #dERR: s d 0x%04X\n", + ((rstat & SER_ERROR_MASK) << 8) | data); + /* Only handle the saved error code, that indicates that we got + * the last character of a break that looks like it's ok, but + * is not + */ - if(rstat & (IO_MASK(R_SERIAL0_STATUS, overrun) | - IO_MASK(R_SERIAL0_STATUS, par_err) | - IO_MASK(R_SERIAL0_STATUS, framing_err))) { - /* if we got an error, we must reset it by reading the - * data_in field + if (info->errorcode == 0) { + *tty->flip.flag_buf_ptr = TTY_NORMAL; + } else { + unsigned char data; + data = info->port[REG_DATA]; + if (info->errorcode & ERRCODE_INSERT) { + unsigned char *currbuf; + /* Get the current buffer */ + if (tty->flip.buf_num) { + currbuf = tty->flip.char_buf + TTY_FLIPBUF_SIZE; + } else { + currbuf = tty->flip.char_buf; + } + /* We should insert a character in the buffer! */ + if (recvl == 0) { + recvl = 1; + DEBUG_LOG(info->line, "insert to %lu\n", recvl); + } else { + /* Move stuff around.. */ + DEBUG_LOG(info->line, "#insert to %lu!\n", recvl); + if (recvl < TTY_FLIPBUF_SIZE) { + int i; + /* Move the data 1 step right */ + i = recvl; + while (i) { + currbuf[i] = currbuf[i-1]; + i--; + } + recvl++; + } else { + /* We can't move it all! Skip break! */ + /* TODO: Handle full buffer? */ + DEBUG_LOG(info->line, "#BRK skipped! %lu!\n", recvl); + info->errorcode = 0; + } + } + } + + PROCSTAT(ser_stat[info->line].errors_cnt++); + DEBUG_LOG(info->line, " #bERR: s d 0x%04X\n", + ((rstat & SER_ERROR_MASK) << 8) | data); + *tty->flip.flag_buf_ptr = (info->errorcode & 0xFF); + info->errorcode = 0; +#if 0 + printk("SERERR: 0x%02X data: 0x%02X\n", rstat & SER_ERROR_MASK, data); +#endif + /* we only ever write errors into the first byte in + * the flip flag buffer, so we dont have to clear it + * all every time */ - (void)info->port[REG_DATA]; } - - /* we only ever write errors into the first byte in the flip - * flag buffer, so we dont have to clear it all every time - */ + } - if(rstat & 0x04) { - icount->parity++; - *tty->flip.flag_buf_ptr = TTY_PARITY; - } else if(rstat & 0x08) { - icount->overrun++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } else if(rstat & 0x02) { - icount->frame++; - *tty->flip.flag_buf_ptr = TTY_FRAME; - } else - *tty->flip.flag_buf_ptr = 0; + DEBUG_LOG(info->line, "recvl %lu\n", recvl); + + if (recvl) { + unsigned char *buf; + struct async_icount *icount = &info->icount; + + /* update stats */ + icount->rx += recvl; /* use the flip buffer next in turn to restart DMA into */ - + if (tty->flip.buf_num) { buf = tty->flip.char_buf; } else { buf = tty->flip.char_buf + TTY_FLIPBUF_SIZE; } - if(buf == phys_to_virt(descr->buf)) { + if (buf == phys_to_virt(descr->buf)) { printk("ttyS%d flip-buffer overrun!\n", info->line); icount->overrun++; *tty->flip.flag_buf_ptr = TTY_OVERRUN; /* restart old buffer */ } else { descr->buf = virt_to_phys(buf); - + /* schedule or push a flip of the buffer */ - + info->tty->flip.count = recvl; #if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ @@ -1221,9 +1371,9 @@ #endif } } - + /* restart the receiving dma */ - + descr->sw_len = TTY_FLIPBUF_SIZE; descr->ctrl = d_int | d_eol | d_eop; descr->hw_len = 0; @@ -1236,6 +1386,10 @@ e100_enable_serial_data_irq(info); #endif /* input dma should be running now */ + + /* unthrottle if we have throttled */ + if (E100_RTS_GET(info)) + tty->driver.unthrottle(info->tty); } static void @@ -1253,8 +1407,8 @@ /* reset the input dma channel to be sure it works */ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); - while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); descr = &info->rec_descr; @@ -1270,7 +1424,10 @@ *info->ifirstadr = virt_to_phys(descr); *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start); - + +#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST + start_flush_timer(); +#endif } @@ -1313,12 +1470,12 @@ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ - for(i = 0; i < NR_PORTS; i++) { + for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; if (!info->uses_dma) continue; /* check for dma_descr (dont need to check for dma_eop in output dma for serial */ - if(ireg & info->irq) { + if (ireg & info->irq) { /* we can send a new dma bunch. make it so. */ transmit_chars(info); } @@ -1352,12 +1509,12 @@ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ - for(i = 0; i < NR_PORTS; i++) { + for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; if (!info->uses_dma) continue; /* check for both dma_eop and dma_descr for the input dma channel */ - if(ireg & ((info->irq << 2) | (info->irq << 3))) { + if (ireg & ((info->irq << 2) | (info->irq << 3))) { /* we have received something */ receive_chars(info); } @@ -1367,17 +1524,156 @@ } } +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +static int serial_fast_timer_started = 0; +static int serial_fast_timer_expired = 0; +static void flush_timeout_function(unsigned long data); +#define START_FLUSH_FAST_TIMER(info, string) {\ + unsigned long timer_flags; \ + save_flags(timer_flags); \ + cli(); \ + TIMERD(DEBUG_LOG(info->line, "start_timer? %i ", info->line)); \ + if (fast_timers[info->line].function == NULL) { \ + serial_fast_timer_started++; \ + TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \ + TIMERD(DEBUG_LOG(info->line, "num started: %i\n", serial_fast_timer_started)); \ + start_one_shot_timer(&fast_timers[info->line], \ + flush_timeout_function, \ + (unsigned long)info, \ + info->char_time_usec*4, \ + string); \ + } \ + else { \ + /* DEBUG_LOG(info->line, " ## timer %i running ##\n", info->line); */ \ + } \ + restore_flags(timer_flags); \ +} + +#else +#define START_FLUSH_FAST_TIMER(info, string) +#endif + +void _INLINE_ check_flush_timeout(struct e100_serial *info) +{ + unsigned char rstat; + unsigned int magic; + + if (0 /*info->tty->processing_flip*/) { + if (!E100_RTS_GET(info)) { + int left = (*info->ihwswadr >> 16) - (*info->istatusadr & 0x3F); + + if (left < TTY_THROTTLE_LIMIT) + info->tty->driver.throttle(info->tty); + } + + PROCSTAT(ser_stat[info->line].processing_flip++); + START_FLUSH_FAST_TIMER(info, "flip"); + return; + } + + /* We check data_avail bit to determine if data has + * arrived since last time + */ + magic = info->fifo_magic; +#ifdef SERIAL_DEBUG_DATA + if (info->fifo_magic || info->fifo_didmagic) { + DEBUG_LOG(info->line, "timeout_int: did fifo_magic %03X\n", + (info->fifo_didmagic << 8) | info->fifo_magic); + } +#endif + rstat = info->port[REG_STATUS]; + /* error or datavail? */ + if (rstat & SER_ERROR_MASK) { + /* Some error has occured */ + /* If there has been valid data, + * an EOP interrupt will be made automatically. + * If no data, the normal ser_interrupt should be enabled + * and handle it. + * So do nothing! + */ + DEBUG_LOG(info->line, "timeout err: rstat 0x%03X\n", + rstat | (info->line << 8)); + return; + } + if (rstat & SER_DATA_AVAIL_MASK) { + /* Ok data, no error, count it */ + TIMERD(DEBUG_LOG(info->line, "timeout: rstat 0x%03X\n", + rstat | (info->line << 8))); + /* Read data to clear status flags */ + (void)info->port[REG_DATA]; + + magic++; + } + + if (magic != info->fifo_magic) { + info->fifo_magic = magic; + info->fifo_didmagic = 0; + START_FLUSH_FAST_TIMER(info, "magic"); + } else { + /* hit the timeout, force an EOP for the input + * dma channel if we haven't already + */ + if (!info->fifo_didmagic && magic) { + info->fifo_didmagic = 1; + info->fifo_magic = 0; + PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); + DEBUG_LOG(info->line, "timeout EOP %i\n", info->line); + TIMERD(DEBUG_LOG(info->line, "timeout magic %i\n", magic)); + FORCE_EOP(info); + } + } +} /* check_flush_timeout */ + +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +static void flush_timeout_function(unsigned long data) +{ + struct e100_serial *info = (struct e100_serial *)data; + fast_timers[info->line].function = NULL; + serial_fast_timer_expired++; + TIMERD(DEBUG_LOG(info->line, "flush_timout %i ", info->line)); + TIMERD(DEBUG_LOG(info->line, "num expired: %i\n", serial_fast_timer_expired)); + check_flush_timeout(info); +} + +#elif defined(CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST) + +static void +timeout_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct e100_serial *info; + int i; + +#ifdef CONFIG_SVINTO_SIM + /* No receive in the simulator. Will probably be when the rest of + * the serial interface works, and this piece will just be removed. + */ + { + const char *s = "What? timeout_interrupt in simulator??\n"; + SIMCOUT(s,strlen(s)); + } + return; +#endif + + /* acknowledge the timer1 irq */ + *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr); + PROCSTAT(fast_timer_ints++); + + for (i = 0; i < NR_PORTS; i++) { + info = rs_table + i; + if (info->uses_dma) + check_flush_timeout(info); + } +} /* timeout_interrupt */ + +#else + /* dma fifo/buffer timeout handler forces an end-of-packet for the dma input channel if no chars - have been received for CONFIG_ETRAX_RX_TIMEOUT_TICKS/100 s. + have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s. If CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is configured then this handler is instead run at 15360 Hz. */ -#ifndef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST -static int timeout_divider = 0; -#endif - static struct timer_list flush_timer; static void @@ -1391,9 +1687,9 @@ return; #endif - for(i = 0; i < NR_PORTS; i++) { + for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; - if(!info->enabled || !(info->flags & ASYNC_INITIALIZED)) + if (!info->enabled || !(info->flags & ASYNC_INITIALIZED)) continue; /* istatusadr (bit 6-0) hold number of bytes in fifo @@ -1402,33 +1698,32 @@ */ magic = (*info->istatusadr & 0x3f); - magic += ((*info->ihwswadr&0xffff ) - (*info->ihwswadr >> 16)); + magic += ((*info->ihwswadr & 0xffff) - (*info->ihwswadr >> 16)); /* if magic is equal to fifo_magic (magic in previous * timeout_interrupt) then no new data has arrived since last * interrupt and we'll force eop to flush fifo+dma buffers */ - if(magic != info->fifo_magic) { + if (magic != info->fifo_magic) { info->fifo_magic = magic; info->fifo_didmagic = 0; } else { /* hit the timeout, force an EOP for the input * dma channel if we haven't already */ - if(!info->fifo_didmagic && magic) { + if (!info->fifo_didmagic && magic) { info->fifo_didmagic = 1; info->fifo_magic = 0; - *R_SET_EOP = 1U << info->iseteop; + FORCE_EOP(info); } } } /* restart flush timer */ - - mod_timer(&flush_timer, jiffies + MAX_FLUSH_TIME); + mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS); } - +#endif #ifdef SERIAL_HANDLE_EARLY_ERRORS @@ -1439,48 +1734,190 @@ * interrupts off. */ +/* +BREAK handling on ETRAX 100: +ETRAX will generate interrupt although there is no stop bit between the +characters. + +Depending on how long the break sequence is, the end of the breaksequence +will look differently: +| indicates start/end of a character. + +B= Break character (0x00) with framing error. +E= Error byte with parity error received after B characters. +F= "Faked" valid byte received immediatly after B characters. +V= Valid byte + +1. + B BL ___________________________ V +.._|__________|__________| |valid data | + +Multiple frame errors with data == 0x00 (B), +the timing matches up "perfectly" so no extra ending char is detected. +The RXD pin is 1 in the last interrupt, in that case +we set info->errorcode = ERRCODE_INSERT_BREAK, but we can't really +know if another byte will come and this really is case 2. below +(e.g F=0xFF or 0xFE) +If RXD pin is 0 we can expect another character (see 2. below). + + +2. + + B B E or F__________________..__ V +.._|__________|__________|______ | |valid data + "valid" or + parity error + +Multiple frame errors with data == 0x00 (B), +but the part of the break trigs is interpreted as a start bit (and possibly +som 0 bits followed by a number of 1 bits and a stop bit). +Depending on parity settings etc. this last character can be either +a fake "valid" char (F) or have a parity error (E). + +If the character is valid it will be put in the buffer, +we set info->errorcode = ERRCODE_SET_BREAK so the receive interrupt +will set the flags so the tty will handle it, +if it's an error byte it will not be put in the buffer +and we set info->errorcode = ERRCODE_INSERT_BREAK. + +To distinguish a V byte in 1. from an F byte in 2. we keep a timestamp +of the last faulty char (B) and compares it with the current time: +If the time elapsed time is less then 2*char_time_usec we will assume +it's a faked F char and not a Valid char and set +info->errorcode = ERRCODE_SET_BREAK. + +Flaws in the above solution: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We use the timer to distinguish a F character from a V character, +if a V character is to close after the break we might make the wrong decision. + +TODO: The break will be delayed until an F or V character is received. + +*/ + +static void _INLINE_ handle_ser_interrupt(struct e100_serial *info) +{ + unsigned char rstat = info->port[REG_STATUS]; + +#ifdef SERIAL_DEBUG_INTR + printk("Interrupt from serport %d\n", i); +#endif +/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */ + if (rstat & SER_ERROR_MASK) { + unsigned char data; + info->last_rx_active_usec = GET_JIFFIES_USEC(); + info->last_rx_active = jiffies; + /* if we got an error, we must reset it by + * reading the data_in field + */ + data = info->port[REG_DATA]; + + if ((data == 0x00) && (rstat & SER_FRAMING_ERR_MASK)) { + /* Most likely a break, but we get + * interrupts over and over again. + */ + + if (info->break_detected_cnt == 0) { + DEBUG_LOG(info->line, "#BRK start\n", 0); + } + if (rstat & SER_RXD_MASK) { + /* The RX pin is high now, so the break + * must be over, but.... + * we can't really know if we will get another + * last byte ending the break or not. + * And we don't know if the byte (if any) will + * have an error or look valid. + */ + DEBUG_LOG(info->line, "# BL BRK\n", 0); + info->errorcode = ERRCODE_INSERT_BREAK; + } + info->break_detected_cnt++; + } else { + /* Error doesn't look like a break, + * but could be end of a break + */ + if (info->break_detected_cnt) { + DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); + info->errorcode = ERRCODE_INSERT_BREAK; + } + info->break_detected_cnt = 0; + DEBUG_LOG(info->line, "#iERR s d %04X\n", + ((rstat & SER_ERROR_MASK) << 8) | data); + } + PROCSTAT(ser_stat[info->line].early_errors_cnt++); + +#if 0 + /* Reset DMA before starting */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); +#endif + } else { /* it was a valid byte, now let the dma do the rest */ + unsigned char data; + unsigned long curr_time_u = GET_JIFFIES_USEC(); + unsigned long curr_time = jiffies; + + if (info->break_detected_cnt) { + /* Detect if this character is a new + * valid char or the last char in a + * break sequence: + * If LSBits are 0 and MSBits are high + * AND the time is close to the + * previous interrupt we should discard + * it. + */ + long elapsed_usec = + (curr_time - info->last_rx_active) * (1000000/HZ) + + curr_time_u - info->last_rx_active_usec; + if (elapsed_usec<2*info->char_time_usec) { + DEBUG_LOG(info->line, "FBRK %i\n", info->line); + /* Report as BREAK (error) and + * let receive_chars handle it + */ + info->errorcode = ERRCODE_SET_BREAK; + } else { + DEBUG_LOG(info->line, "Not end of BRK (V)%i\n", info->line); + } + DEBUG_LOG(info->line, "num brk %i\n", info->break_detected_cnt); + } + /* Reset data_avail by + * reading the data_in field + */ + data = info->port[REG_DATA]; + info->break_detected_cnt = 0; + info->fifo_magic++; /* Count received chars */ +#ifdef SERIAL_DEBUG_INTR + printk("** OK, disabling ser_interupts\n"); +#endif + PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); + DEBUG_LOG(info->line, " ser_int OK %03X\n", + (info->line << 8) | data); + e100_disable_serial_data_irq(info); + } + + /* restart the DMA never hurts */ + *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); + START_FLUSH_FAST_TIMER(info, "ser_int"); +} /* handle_ser_interrupt */ + static void ser_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct e100_serial *info; int i; - unsigned char rstat; - for(i = 0; i < NR_PORTS; i++) { + for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; + if (!info->uses_dma) continue; - rstat = info->port[REG_STATUS]; - - if(*R_IRQ_MASK1_RD & (1U << (8+2*info->line))) { /* This line caused the irq */ -#ifdef SERIAL_DEBUG_INTR - printk("Interrupt from serport %d\n", i); -#endif - if(rstat & 0x0e) { - /* FIXME: This is weird, but if this delay is - * not present then irmaflash does not work... - */ - udelay(2300); - /* if we got an error, we must reset it by - * reading the data_in field - */ - (void)info->port[REG_DATA]; - - PROCSTAT(early_errors_cnt[info->line]++); - - /* restart the DMA */ - *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); - } - else { /* it was a valid byte, now let the dma do the rest */ -#ifdef SERIAL_DEBUG_INTR - printk("** OK, disabling ser_interrupts\n"); -#endif - e100_disable_serial_data_irq(info); - } + /* Which line caused the irq? */ + if (*R_IRQ_MASK1_RD & (1U << (8+2*info->line))) { + handle_ser_interrupt(info); } } -} +} /* ser_interrupt */ #endif /* @@ -1573,7 +2010,7 @@ printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit.buf); #endif - if(info->tty) { + if (info->tty) { /* clear the tty flip flag buffer since we will not * be using it (we only use the first byte..) @@ -1612,11 +2049,11 @@ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); /* wait until reset cycle is complete */ - while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); - while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == - IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); *info->iclrintradr = IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | @@ -1697,6 +2134,7 @@ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + info->uses_dma = 0; #endif /* CONFIG_SVINTO_SIM */ @@ -1740,7 +2178,7 @@ /* first some safety checks */ - if(!info->tty || !info->tty->termios) + if (!info->tty || !info->tty->termios) return; if (!info->port) return; @@ -1807,9 +2245,10 @@ info->port[REG_TR_CTRL] = info->tx_ctrl; info->port[REG_REC_CTRL] = info->rx_ctrl; *((unsigned long *)&info->port[REG_XOFF]) = 0; +#endif /* !CONFIG_SVINTO_SIM */ -#endif /* CONFIG_SVINTO_SIM */ -} + update_char_time(info); +} /* change_speed */ /* start transmitting chars NOW */ @@ -1852,7 +2291,7 @@ return 0; #ifdef SERIAL_DEBUG_DATA - if(info->line == SERIAL_DEBUG_LINE) + if (info->line == SERIAL_DEBUG_LINE) printk("rs_write (%d), status %d\n", count, info->port[REG_STATUS]); #endif @@ -1871,7 +2310,7 @@ * atomic operation... this could perhaps be avoided by more clever * design. */ - if(from_user) { + if (from_user) { down(&tmp_buf_sem); while (1) { int c1; @@ -1906,7 +2345,7 @@ up(&tmp_buf_sem); } else { cli(); - while(1) { + while (1) { c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); @@ -1931,10 +2370,10 @@ * the IRQ's are not running anyway for this port. */ - if(info->xmit.head != info->xmit.tail - && !tty->stopped && - !tty->hw_stopped && - !info->tr_running) { + if (info->xmit.head != info->xmit.tail + && !tty->stopped && + !tty->hw_stopped && + !info->tr_running) { start_transmit(info); } @@ -2107,11 +2546,11 @@ old_info = *info; - if(!capable(CAP_SYS_ADMIN)) { - if((new_serial.type != info->type) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (info->flags & ~ASYNC_USR_MASK))) + if (!capable(CAP_SYS_ADMIN)) { + if ((new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (info->flags & ~ASYNC_USR_MASK))) return -EPERM; info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); @@ -2136,7 +2575,7 @@ #endif check_and_exit: - if(info->flags & ASYNC_INITIALIZED) { + if (info->flags & ASYNC_INITIALIZED) { change_speed(info); } else retval = startup(info); @@ -2156,16 +2595,18 @@ static int get_lsr_info(struct e100_serial * info, unsigned int *value) { - unsigned int result; + unsigned int result = TIOCSER_TEMT; +#ifndef CONFIG_SVINTO_SIM + unsigned long curr_time = jiffies; + unsigned long curr_time_usec = GET_JIFFIES_USEC(); + unsigned long elapsed_usec = + (curr_time - info->last_tx_active) * 1000000/HZ + + curr_time_usec - info->last_tx_active_usec; -#ifdef CONFIG_SVINTO_SIM - /* Always open. */ - result = TIOCSER_TEMT; -#else - if (*info->ostatusadr & 0x007F) /* something in fifo */ + if (info->xmit.head != info->xmit.tail || + elapsed_usec < 2*info->char_time_usec) { result = 0; - else - result = TIOCSER_TEMT; + } #endif if (copy_to_user(value, &result, sizeof(int))) @@ -2178,10 +2619,9 @@ { int state; const char *str; - }; -const struct state_str control_state_str[]={ +const struct state_str control_state_str[] = { {TIOCM_DTR, "DTR" }, {TIOCM_RTS, "RTS"}, {TIOCM_ST, "ST?" }, @@ -2612,20 +3052,31 @@ { unsigned long orig_jiffies; struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long curr_time = jiffies; + unsigned long curr_time_usec = GET_JIFFIES_USEC(); + long elapsed_usec = + (curr_time - info->last_tx_active) * (1000000/HZ) + + curr_time_usec - info->last_tx_active_usec; /* * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k) */ orig_jiffies = jiffies; - while(info->xmit.head != info->xmit.tail || /* More in send queue */ - (*info->ostatusadr & 0x007f)) { /* more in FIFO */ + while (info->xmit.head != info->xmit.tail || /* More in send queue */ + (*info->ostatusadr & 0x007f) || /* more in FIFO */ + (elapsed_usec < 2*info->char_time_usec)) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; + curr_time = jiffies; + curr_time_usec = GET_JIFFIES_USEC(); + elapsed_usec = + (curr_time - info->last_tx_active) * (1000000/HZ) + + curr_time_usec - info->last_tx_active_usec; } set_current_state(TASK_RUNNING); } @@ -2809,10 +3260,11 @@ return -ENODEV; /* find the corresponding e100_serial struct in the table */ - info = rs_table + line; - /* dont allow the opening of ports that are not enabled in the HW config */ - if (!info->enabled) return -ENODEV; + + /* don't allow the opening of ports that are not enabled in the HW config */ + if (!info->enabled) + return -ENODEV; #ifdef SERIAL_DEBUG_OPEN printk("[%d] rs_open %s%d, count = %d\n", current->pid, @@ -2923,20 +3375,20 @@ ret += sprintf(buf+ret, " baud:%d", info->baud); - ret += sprintf(buf+ret, " tx:%d rx:%d", - info->icount.tx, info->icount.rx); + ret += sprintf(buf+ret, " tx:%lu rx:%lu", + info->icount.tx, info->icount.rx); if (info->icount.frame) - ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + ret += sprintf(buf+ret, " fe:%lu", info->icount.frame); if (info->icount.parity) - ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + ret += sprintf(buf+ret, " pe:%lu", info->icount.parity); if (info->icount.brk) - ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + ret += sprintf(buf+ret, " brk:%lu", info->icount.brk); if (info->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + ret += sprintf(buf+ret, " oe:%lu", info->icount.overrun); /* * Last thing is the RS-232 status lines @@ -2996,9 +3448,11 @@ /* Setup the timed flush handler system */ +#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER) && !defined(CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST) init_timer(&flush_timer); flush_timer.function = timed_flush_handler; - mod_timer(&flush_timer, jiffies + MAX_FLUSH_TIME); + mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS); +#endif /* Initialize the tty_driver structure */ @@ -3089,6 +3543,7 @@ init_waitqueue_head(&info->close_wait); info->xmit.buf = 0; info->xmit.tail = info->xmit.head = 0; + if (info->enabled) { printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n", serial_driver.name, info->line, (unsigned int)info->port); @@ -3099,38 +3554,38 @@ /* Not needed in simulator. May only complicate stuff. */ /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ #ifdef CONFIG_ETRAX_SERIAL_PORT0 - if(request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL)) + if (request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL)) panic("irq22"); - if(request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL)) + if (request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL)) panic("irq23"); #endif #ifdef SERIAL_HANDLE_EARLY_ERRORS - if(request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) + if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) panic("irq8"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT1 - if(request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL)) + if (request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL)) panic("irq24"); - if(request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL)) + if (request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL)) panic("irq25"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT2 /* DMA Shared with par0 (and SCSI0 and ATA) */ - if(request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL)) + if (request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL)) panic("irq18"); - if(request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL)) + if (request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL)) panic("irq19"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT3 /* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */ - if(request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL)) + if (request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL)) panic("irq20"); - if(request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL)) + if (request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL)) panic("irq21"); #endif + #ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST - /* TODO: a timeout_interrupt needs to be written that calls timeout_handler */ - if(request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ, + if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ | SA_INTERRUPT, "fast serial dma timeout", NULL)) { printk("err: timer1 irq\n"); } diff -u --recursive --new-file v2.4.14/linux/arch/cris/drivers/serial.h linux/arch/cris/drivers/serial.h --- v2.4.14/linux/arch/cris/drivers/serial.h Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/drivers/serial.h Fri Nov 9 13:58:02 2001 @@ -87,6 +87,15 @@ struct wait_queue *close_wait; #endif + unsigned long char_time_usec; /* The time for 1 char, in usecs */ + unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */ + unsigned long last_tx_active; /* Last tx time in jiffies */ + unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */ + unsigned long last_rx_active; /* Last rx time in jiffies */ + + int break_detected_cnt; + int errorcode; + #ifdef CONFIG_RS485 struct rs485_control rs485; /* RS-485 support */ #endif diff -u --recursive --new-file v2.4.14/linux/arch/cris/kernel/Makefile linux/arch/cris/kernel/Makefile --- v2.4.14/linux/arch/cris/kernel/Makefile Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/kernel/Makefile Fri Nov 9 13:58:02 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.8 2001/10/01 14:44:07 bjornw Exp $ +# $Id: Makefile,v 1.9 2001/10/22 13:10:21 pkj Exp $ # # Makefile for the linux kernel. # @@ -16,6 +16,9 @@ all: kernel.o head.o O_TARGET := kernel.o + +export-objs := ksyms.o + obj-y := process.o signal.o entry.o traps.o irq.o \ ptrace.o setup.o time.o sys_cris.o shadows.o \ debugport.o semaphore.o diff -u --recursive --new-file v2.4.14/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S --- v2.4.14/linux/arch/cris/kernel/entry.S Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/kernel/entry.S Fri Nov 9 13:58:02 2001 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.34 2001/10/01 14:45:03 bjornw Exp $ +/* $Id: entry.S,v 1.35 2001/10/30 17:10:15 bjornw Exp $ * * linux/arch/cris/entry.S * @@ -7,6 +7,9 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.35 2001/10/30 17:10:15 bjornw + * Add some syscalls + * * Revision 1.34 2001/10/01 14:45:03 bjornw * Removed underscores and added register prefixes * @@ -981,6 +984,9 @@ .long SYMBOL_NAME(sys_getdents64) /* 220 */ .long SYMBOL_NAME(sys_fcntl64) .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ + .long SYMBOL_NAME(sys_ni_syscall) /* Reserved for Security */ + .long SYMBOL_NAME(sys_gettid) + .long SYMBOL_NAME(sys_readahead) /* 225 */ /* * NOTE!! This doesn't have to be exact - we just have @@ -989,7 +995,7 @@ * been shrunk every time we add a new system call. */ - .rept NR_syscalls-222 + .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.4.14/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S --- v2.4.14/linux/arch/cris/kernel/head.S Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/kernel/head.S Fri Nov 9 13:58:02 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.40 2001/10/03 14:59:57 pkj Exp $ +/* $Id: head.S,v 1.41 2001/10/29 14:55:58 pkj Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,9 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.41 2001/10/29 14:55:58 pkj + * Corrected pa$r0 to par0. + * * Revision 1.40 2001/10/03 14:59:57 pkj * Added support for resetting the Bluetooth hardware. * @@ -520,7 +523,7 @@ moveq 0,$r0 #if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \ && !defined(CONFIG_DMA_MEMCPY) - ; DMA channels 6 and 7 to se$r0, kgdb doesnt want DMA + ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA or.d IO_STATE (R_GEN_CONFIG, dma7, serial0) \ | IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0 #endif @@ -554,7 +557,7 @@ #endif #if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) ; parport 0 enabled using DMA 2/3 - or.w IO_STATE (R_GEN_CONFIG, pa$r0, select),$r0 + or.w IO_STATE (R_GEN_CONFIG, par0, select),$r0 #endif #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) ; parport 1 enabled using DMA 4/5 diff -u --recursive --new-file v2.4.14/linux/arch/cris/kernel/kgdb.c linux/arch/cris/kernel/kgdb.c --- v2.4.14/linux/arch/cris/kernel/kgdb.c Tue May 1 16:04:56 2001 +++ linux/arch/cris/kernel/kgdb.c Fri Nov 9 13:58:02 2001 @@ -18,6 +18,9 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ +*! Revision 1.6 2001/10/09 13:10:03 matsfg +*! Added $ on registers and removed some underscores +*! *! Revision 1.5 2001/04/17 13:58:39 orjanf *! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. *! @@ -52,7 +55,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.5 2001/04/17 13:58:39 orjanf Exp $ +*! $Id: kgdb.c,v 1.6 2001/10/09 13:10:03 matsfg Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -1343,90 +1346,90 @@ void kgdb_handle_breakpoint(void); asm (" - .global _kgdb_handle_breakpoint -_kgdb_handle_breakpoint: + .global kgdb_handle_breakpoint +kgdb_handle_breakpoint: ;; ;; Response to the break-instruction ;; ;; Create a register image of the caller ;; - move dccr,[_reg+0x5E] ; Save the flags in DCCR before disable interrupts + move $dccr,[reg+0x5E] ; Save the flags in DCCR before disable interrupts di ; Disable interrupts - move.d r0,[_reg] ; Save R0 - move.d r1,[_reg+0x04] ; Save R1 - move.d r2,[_reg+0x08] ; Save R2 - move.d r3,[_reg+0x0C] ; Save R3 - move.d r4,[_reg+0x10] ; Save R4 - move.d r5,[_reg+0x14] ; Save R5 - move.d r6,[_reg+0x18] ; Save R6 - move.d r7,[_reg+0x1C] ; Save R7 - move.d r8,[_reg+0x20] ; Save R8 - move.d r9,[_reg+0x24] ; Save R9 - move.d r10,[_reg+0x28] ; Save R10 - move.d r11,[_reg+0x2C] ; Save R11 - move.d r12,[_reg+0x30] ; Save R12 - move.d r13,[_reg+0x34] ; Save R13 - move.d sp,[_reg+0x38] ; Save SP (R14) + move.d $r0,[reg] ; Save R0 + move.d $r1,[reg+0x04] ; Save R1 + move.d $r2,[reg+0x08] ; Save R2 + move.d $r3,[reg+0x0C] ; Save R3 + move.d $r4,[reg+0x10] ; Save R4 + move.d $r5,[reg+0x14] ; Save R5 + move.d $r6,[reg+0x18] ; Save R6 + move.d $r7,[reg+0x1C] ; Save R7 + move.d $r8,[reg+0x20] ; Save R8 + move.d $r9,[reg+0x24] ; Save R9 + move.d $r10,[reg+0x28] ; Save R10 + move.d $r11,[reg+0x2C] ; Save R11 + move.d $r12,[reg+0x30] ; Save R12 + move.d $r13,[reg+0x34] ; Save R13 + move.d $sp,[reg+0x38] ; Save SP (R14) ;; Due to the old assembler-versions BRP might not be recognized - .word 0xE670 ; move brp,r0 - subq 2,r0 ; Set to address of previous instruction. - move.d r0,[_reg+0x3c] ; Save the address in PC (R15) - clear.b [_reg+0x40] ; Clear P0 - move vr,[_reg+0x41] ; Save special register P1 - clear.w [_reg+0x42] ; Clear P4 - move ccr,[_reg+0x44] ; Save special register CCR - move mof,[_reg+0x46] ; P7 - clear.d [_reg+0x4A] ; Clear P8 - move ibr,[_reg+0x4E] ; P9, - move irp,[_reg+0x52] ; P10, - move srp,[_reg+0x56] ; P11, - move dtp0,[_reg+0x5A] ; P12, register BAR, assembler might not know BAR + .word 0xE670 ; move brp,$r0 + subq 2,$r0 ; Set to address of previous instruction. + move.d $r0,[reg+0x3c] ; Save the address in PC (R15) + clear.b [reg+0x40] ; Clear P0 + move $vr,[reg+0x41] ; Save special register P1 + clear.w [reg+0x42] ; Clear P4 + move $ccr,[reg+0x44] ; Save special register CCR + move $mof,[reg+0x46] ; P7 + clear.d [reg+0x4A] ; Clear P8 + move $ibr,[reg+0x4E] ; P9, + move $irp,[reg+0x52] ; P10, + move $srp,[reg+0x56] ; P11, + move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR ; P13, register DCCR already saved ;; Due to the old assembler-versions BRP might not be recognized .word 0xE670 ; move brp,r0 ;; Static (compiled) breakpoints must return to the next instruction in order ;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction ;; in order to execute it when execution is continued. - test.b [_is_dyn_brkp] ; Is this a dynamic breakpoint? + test.b [is_dyn_brkp] ; Is this a dynamic breakpoint? beq is_static ; No, a static breakpoint nop - subq 2,r0 ; rerun the instruction the break replaced + subq 2,$r0 ; rerun the instruction the break replaced is_static: - moveq 1,r1 - move.b r1,[_is_dyn_brkp] ; Set the state variable to dynamic breakpoint - move.d r0,[_reg+0x62] ; Save the return address in BRP - move usp,[_reg+0x66] ; USP + moveq 1,$r1 + move.b $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint + move.d $r0,[reg+0x62] ; Save the return address in BRP + move $usp,[reg+0x66] ; USP ;; ;; Handle the communication ;; - move.d _internal_stack+1020,sp ; Use the internal stack which grows upward - moveq 5,r10 ; SIGTRAP - jsr _handle_exception ; Interactive routine + move.d internal_stack+1020,$sp ; Use the internal stack which grows upward + moveq 5,$r10 ; SIGTRAP + jsr handle_exception ; Interactive routine ;; ;; Return to the caller ;; - move.d [_reg],r0 ; Restore R0 - move.d [_reg+0x04],r1 ; Restore R1 - move.d [_reg+0x08],r2 ; Restore R2 - move.d [_reg+0x0C],r3 ; Restore R3 - move.d [_reg+0x10],r4 ; Restore R4 - move.d [_reg+0x14],r5 ; Restore R5 - move.d [_reg+0x18],r6 ; Restore R6 - move.d [_reg+0x1C],r7 ; Restore R7 - move.d [_reg+0x20],r8 ; Restore R8 - move.d [_reg+0x24],r9 ; Restore R9 - move.d [_reg+0x28],r10 ; Restore R10 - move.d [_reg+0x2C],r11 ; Restore R11 - move.d [_reg+0x30],r12 ; Restore R12 - move.d [_reg+0x34],r13 ; Restore R13 + move.d [reg],$r0 ; Restore R0 + move.d [reg+0x04],$r1 ; Restore R1 + move.d [reg+0x08],$r2 ; Restore R2 + move.d [reg+0x0C],$r3 ; Restore R3 + move.d [reg+0x10],$r4 ; Restore R4 + move.d [reg+0x14],$r5 ; Restore R5 + move.d [reg+0x18],$r6 ; Restore R6 + move.d [reg+0x1C],$r7 ; Restore R7 + move.d [reg+0x20],$r8 ; Restore R8 + move.d [reg+0x24],$r9 ; Restore R9 + move.d [reg+0x28],$r10 ; Restore R10 + move.d [reg+0x2C],$r11 ; Restore R11 + move.d [reg+0x30],$r12 ; Restore R12 + move.d [reg+0x34],$r13 ; Restore R13 ;; ;; FIXME: Which registers should be restored? ;; - move.d [_reg+0x38],sp ; Restore SP (R14) - move [_reg+0x56],srp ; Restore the subroutine return pointer. - move [_reg+0x5E],dccr ; Restore DCCR - move [_reg+0x66],usp ; Restore USP - jump [_reg+0x62] ; A jump to the content in register BRP works. + move.d [reg+0x38],$sp ; Restore SP (R14) + move [reg+0x56],$srp ; Restore the subroutine return pointer. + move [reg+0x5E],$dccr ; Restore DCCR + move [reg+0x66],$usp ; Restore USP + jump [reg+0x62] ; A jump to the content in register BRP works. nop ; "); @@ -1440,85 +1443,85 @@ void kgdb_handle_serial(void); asm (" - .global _kgdb_handle_serial -_kgdb_handle_serial: + .global kgdb_handle_serial +kgdb_handle_serial: ;; ;; Response to a serial interrupt ;; - move dccr,[_reg+0x5E] ; Save the flags in DCCR + move $dccr,[reg+0x5E] ; Save the flags in DCCR di ; Disable interrupts - move.d r0,[_reg] ; Save R0 - move.d r1,[_reg+0x04] ; Save R1 - move.d r2,[_reg+0x08] ; Save R2 - move.d r3,[_reg+0x0C] ; Save R3 - move.d r4,[_reg+0x10] ; Save R4 - move.d r5,[_reg+0x14] ; Save R5 - move.d r6,[_reg+0x18] ; Save R6 - move.d r7,[_reg+0x1C] ; Save R7 - move.d r8,[_reg+0x20] ; Save R8 - move.d r9,[_reg+0x24] ; Save R9 - move.d r10,[_reg+0x28] ; Save R10 - move.d r11,[_reg+0x2C] ; Save R11 - move.d r12,[_reg+0x30] ; Save R12 - move.d r13,[_reg+0x34] ; Save R13 - move.d sp,[_reg+0x38] ; Save SP (R14) - move irp,[_reg+0x3c] ; Save the address in PC (R15) - clear.b [_reg+0x40] ; Clear P0 - move vr,[_reg+0x41] ; Save special register P1, - clear.w [_reg+0x42] ; Clear P4 - move ccr,[_reg+0x44] ; Save special register CCR - move mof,[_reg+0x46] ; P7 - clear.d [_reg+0x4A] ; Clear P8 - move ibr,[_reg+0x4E] ; P9, - move irp,[_reg+0x52] ; P10, - move srp,[_reg+0x56] ; P11, - move dtp0,[_reg+0x5A] ; P12, register BAR, assembler might not know BAR + move.d $r0,[reg] ; Save R0 + move.d $r1,[reg+0x04] ; Save R1 + move.d $r2,[reg+0x08] ; Save R2 + move.d $r3,[reg+0x0C] ; Save R3 + move.d $r4,[reg+0x10] ; Save R4 + move.d $r5,[reg+0x14] ; Save R5 + move.d $r6,[reg+0x18] ; Save R6 + move.d $r7,[reg+0x1C] ; Save R7 + move.d $r8,[reg+0x20] ; Save R8 + move.d $r9,[reg+0x24] ; Save R9 + move.d $r10,[reg+0x28] ; Save R10 + move.d $r11,[reg+0x2C] ; Save R11 + move.d $r12,[reg+0x30] ; Save R12 + move.d $r13,[reg+0x34] ; Save R13 + move.d $sp,[reg+0x38] ; Save SP (R14) + move $irp,[reg+0x3c] ; Save the address in PC (R15) + clear.b [reg+0x40] ; Clear P0 + move $vr,[reg+0x41] ; Save special register P1, + clear.w [reg+0x42] ; Clear P4 + move $ccr,[reg+0x44] ; Save special register CCR + move $mof,[reg+0x46] ; P7 + clear.d [reg+0x4A] ; Clear P8 + move $ibr,[reg+0x4E] ; P9, + move $irp,[reg+0x52] ; P10, + move $srp,[reg+0x56] ; P11, + move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR ; P13, register DCCR already saved ;; Due to the old assembler-versions BRP might not be recognized .word 0xE670 ; move brp,r0 - move.d r0,[_reg+0x62] ; Save the return address in BRP - move usp,[_reg+0x66] ; USP + move.d $r0,[reg+0x62] ; Save the return address in BRP + move $usp,[reg+0x66] ; USP ;; get the serial character (from debugport.c) and check if its a ctrl-c - jsr _getDebugChar - cmp.b 3, r10 + jsr getDebugChar + cmp.b 3, $r10 bne goback nop ;; ;; Handle the communication ;; - move.d _internal_stack+1020,sp ; Use the internal stack - moveq 2,r10 ; SIGINT - jsr _handle_exception ; Interactive routine + move.d internal_stack+1020,$sp ; Use the internal stack + moveq 2,$r10 ; SIGINT + jsr handle_exception ; Interactive routine goback: ;; ;; Return to the caller ;; - move.d [_reg],r0 ; Restore R0 - move.d [_reg+0x04],r1 ; Restore R1 - move.d [_reg+0x08],r2 ; Restore R2 - move.d [_reg+0x0C],r3 ; Restore R3 - move.d [_reg+0x10],r4 ; Restore R4 - move.d [_reg+0x14],r5 ; Restore R5 - move.d [_reg+0x18],r6 ; Restore R6 - move.d [_reg+0x1C],r7 ; Restore R7 - move.d [_reg+0x20],r8 ; Restore R8 - move.d [_reg+0x24],r9 ; Restore R9 - move.d [_reg+0x28],r10 ; Restore R10 - move.d [_reg+0x2C],r11 ; Restore R11 - move.d [_reg+0x30],r12 ; Restore R12 - move.d [_reg+0x34],r13 ; Restore R13 + move.d [reg],$r0 ; Restore R0 + move.d [reg+0x04],$r1 ; Restore R1 + move.d [reg+0x08],$r2 ; Restore R2 + move.d [reg+0x0C],$r3 ; Restore R3 + move.d [reg+0x10],$r4 ; Restore R4 + move.d [reg+0x14],$r5 ; Restore R5 + move.d [reg+0x18],$r6 ; Restore R6 + move.d [reg+0x1C],$r7 ; Restore R7 + move.d [reg+0x20],$r8 ; Restore R8 + move.d [reg+0x24],$r9 ; Restore R9 + move.d [reg+0x28],$r10 ; Restore R10 + move.d [reg+0x2C],$r11 ; Restore R11 + move.d [reg+0x30],$r12 ; Restore R12 + move.d [reg+0x34],$r13 ; Restore R13 ;; ;; FIXME: Which registers should be restored? ;; - move.d [_reg+0x38],sp ; Restore SP (R14) - move [_reg+0x56],srp ; Restore the subroutine return pointer. - move [_reg+0x5E],dccr ; Restore DCCR - move [_reg+0x66],usp ; Restore USP + move.d [reg+0x38],$sp ; Restore SP (R14) + move [reg+0x56],$srp ; Restore the subroutine return pointer. + move [reg+0x5E],$dccr ; Restore DCCR + move [reg+0x66],$usp ; Restore USP reti ; Return from the interrupt routine nop "); diff -u --recursive --new-file v2.4.14/linux/arch/cris/kernel/ksyms.c linux/arch/cris/kernel/ksyms.c --- v2.4.14/linux/arch/cris/kernel/ksyms.c Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/kernel/ksyms.c Fri Nov 9 13:58:02 2001 @@ -24,6 +24,7 @@ extern void dump_thread(struct pt_regs *, struct user *); extern unsigned long get_cmos_time(void); extern void __ashrdi3(void); +extern void iounmap(void *addr); /* platform dependent support */ @@ -44,6 +45,19 @@ EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(__ashrdi3); + +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); + +/* export shadow registers for the CPU I/O pins */ + +EXPORT_SYMBOL(genconfig_shadow); +EXPORT_SYMBOL(port_pa_data_shadow); +EXPORT_SYMBOL(port_pa_dir_shadow); +EXPORT_SYMBOL(port_pb_data_shadow); +EXPORT_SYMBOL(port_pb_dir_shadow); +EXPORT_SYMBOL(port_pb_config_shadow); +EXPORT_SYMBOL(port_g_data_shadow); /* other stuff */ diff -u --recursive --new-file v2.4.14/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c --- v2.4.14/linux/arch/cris/kernel/process.c Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/kernel/process.c Fri Nov 9 13:58:02 2001 @@ -77,6 +77,7 @@ * setup. */ +static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; diff -u --recursive --new-file v2.4.14/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c --- v2.4.14/linux/arch/cris/kernel/setup.c Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/kernel/setup.c Fri Nov 9 13:58:02 2001 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.21 2001/10/01 14:45:35 bjornw Exp $ +/* $Id: setup.c,v 1.22 2001/10/23 17:42:58 pkj Exp $ * * linux/arch/cris/kernel/setup.c * @@ -202,32 +202,58 @@ } cpu_info[] = { /* The first four models will never ever run this code and are only here for display. */ - { "ETRAX 1", 0, 0 }, - { "ETRAX 2", 0, 0 }, - { "ETRAX 3", 0, HAS_TOKENRING }, - { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, - { "Unknown", 0, 0 }, - { "Unknown", 0, 0 }, - { "Unknown", 0, 0 }, - { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, - { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, - { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, - { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, + { "ETRAX 1", 0, 0 }, + { "ETRAX 2", 0, 0 }, + { "ETRAX 3", 0, HAS_TOKENRING }, + { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, + { "Unknown", 0, 0 }, + { "Unknown", 0, 0 }, + { "Unknown", 0, 0 }, + { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, + { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, + { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, + { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, - { "Unknown", 0, 0 }, + { "Unknown", 0, 0 } /* This entry MUST be the last */ }; /* - * BUFFER is PAGE_SIZE bytes long. + * get_cpuinfo - Get information on one CPU for use by the procfs. + * + * Prints info on the next CPU into buffer. Beware, doesn't check for + * buffer overflow. Current implementation of procfs assumes that the + * resulting data is <= 1K. + * + * BUFFER is PAGE_SIZE - 1K bytes long. + * + * Args: + * buffer -- you guessed it, the data buffer + * cpu_np -- Input: next cpu to get (start at 0). Output: Updated. + * + * Returns number of bytes written to buffer. */ -int get_cpuinfo(char *buffer) +int get_cpuinfo(char *buffer, unsigned *cpu_np) { int revision; + struct cpu_info *info; + unsigned n; /* read the version register in the CPU and print some stuff */ revision = rdvr(); + if (revision < 0 || revision >= sizeof cpu_info/sizeof *cpu_info) { + info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1]; + } else + info = &cpu_info[revision]; + + /* No SMP at the moment, so just toggle 0/1 */ + n = *cpu_np; + *cpu_np = 1; + if (n != 0) { + return (0); + } + return sprintf(buffer, "cpu\t\t: CRIS\n" "cpu revision\t: %d\n" @@ -244,16 +270,16 @@ "bogomips\t: %lu.%02lu\n", revision, - cpu_info[revision].model, - cpu_info[revision].cache, - cpu_info[revision].flags & HAS_FPU ? "yes" : "no", - cpu_info[revision].flags & HAS_MMU ? "yes" : "no", - cpu_info[revision].flags & HAS_MMU_BUG ? "yes" : "no", - cpu_info[revision].flags & HAS_ETHERNET100 ? "10/100" : "10", - cpu_info[revision].flags & HAS_TOKENRING ? "4/16 Mbps" : "no", - cpu_info[revision].flags & HAS_SCSI ? "yes" : "no", - cpu_info[revision].flags & HAS_ATA ? "yes" : "no", - cpu_info[revision].flags & HAS_USB ? "yes" : "no", + info->model, + info->cache, + info->flags & HAS_FPU ? "yes" : "no", + info->flags & HAS_MMU ? "yes" : "no", + info->flags & HAS_MMU_BUG ? "yes" : "no", + info->flags & HAS_ETHERNET100 ? "10/100" : "10", + info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no", + info->flags & HAS_SCSI ? "yes" : "no", + info->flags & HAS_ATA ? "yes" : "no", + info->flags & HAS_USB ? "yes" : "no", (loops_per_jiffy * HZ + 500) / 500000, ((loops_per_jiffy * HZ + 500) / 5000) % 100); } diff -u --recursive --new-file v2.4.14/linux/arch/cris/kernel/time.c linux/arch/cris/kernel/time.c --- v2.4.14/linux/arch/cris/kernel/time.c Sun Aug 12 13:27:58 2001 +++ linux/arch/cris/kernel/time.c Fri Nov 9 13:58:02 2001 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.8 2001/07/18 14:01:03 bjornw Exp $ +/* $Id: time.c,v 1.9 2001/10/25 10:26:37 johana Exp $ * * linux/arch/cris/kernel/time.c * @@ -51,6 +51,11 @@ extern int setup_etrax_irq(int, struct irqaction *); +/* Lookup table to convert *R_TIMER0 to microseconds (us) + * Timer goes from TIMER0_DIV down to 1 meaning 0-10000us in step of approx 52us + */ +unsigned short cris_timer0_value_us[TIMER0_DIV+1]; + #define TICK_SIZE tick static unsigned long do_slow_gettimeoffset(void) @@ -380,6 +385,7 @@ void __init time_init(void) { + int i; /* probe for the RTC and read it if it exists */ if(RTC_INIT() < 0) { @@ -442,6 +448,13 @@ IO_STATE(R_TIMER_CTRL, tm0, run) | IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz); #endif + + for (i=0; i <= TIMER0_DIV; i++) { + /* We must be careful not to get overflow... */ + cris_timer0_value_us[TIMER0_DIV-i] = + (unsigned short)((unsigned long) + ((i*(1000000/HZ))/TIMER0_DIV)&0x0000FFFFL); + } *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ diff -u --recursive --new-file v2.4.14/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c --- v2.4.14/linux/arch/cris/kernel/traps.c Tue Oct 9 17:06:51 2001 +++ linux/arch/cris/kernel/traps.c Fri Nov 9 13:58:02 2001 @@ -138,8 +138,8 @@ register. */ unsigned long usp = rdusp(); - printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx %s\n", - regs->irp, regs->srp, regs->dccr, usp, regs->mof, print_tainted()); + printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", + regs->irp, regs->srp, regs->dccr, usp, regs->mof ); printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", regs->r0, regs->r1, regs->r2, regs->r3); printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", diff -u --recursive --new-file v2.4.14/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S --- v2.4.14/linux/arch/i386/boot/bootsect.S Sun Sep 23 11:40:55 2001 +++ linux/arch/i386/boot/bootsect.S Fri Nov 9 13:58:02 2001 @@ -395,9 +395,15 @@ # NOTE: Doesn't save %ax or %dx; do it yourself if you need to. kill_motor: +#if 1 + xorw %ax, %ax # reset FDC + xorb %dl, %dl + int $0x13 +#else movw $0x3f2, %dx xorb %al, %al outb %al, %dx +#endif ret sectors: .word 0 diff -u --recursive --new-file v2.4.14/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.4.14/linux/arch/i386/boot/setup.S Sun Aug 12 13:27:58 2001 +++ linux/arch/i386/boot/setup.S Fri Nov 9 13:58:02 2001 @@ -232,8 +232,8 @@ # Move rest of setup code/data to here movw $2048, %di # four sectors loaded by LILO subw %si, %si - movw %cs, %ax # aka SETUPSEG - movw %ax, %es + pushw %cs + popw %es movw $SYSSEG, %ax movw %ax, %ds rep @@ -253,6 +253,7 @@ call prtstr no_sig_loop: + hlt jmp no_sig_loop good_sig: @@ -641,18 +642,40 @@ movw %ax, %ds movw %dx, %ss end_move_self: # now we are at the right place - lidt idt_48 # load idt with 0,0 - xorl %eax, %eax # Compute gdt_base - movw %ds, %ax # (Convert %ds:gdt to a linear ptr) - shll $4, %eax - addl $gdt, %eax - movl %eax, (gdt_48+2) - lgdt gdt_48 # load gdt with whatever is - # appropriate -# that was painless, now we enable a20 +# +# Enable A20. This is at the very best an annoying procedure. +# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin. +# + +A20_TEST_LOOPS = 32 # Iterations per wait +A20_ENABLE_LOOPS = 255 # Total loops to try + + +a20_try_loop: + + # First, see if we are on a system with no A20 gate. +a20_none: + call a20_test + jnz a20_done + + # Next, try the BIOS (INT 0x15, AX=0x2401) +a20_bios: + movw $0x2401, %ax + pushfl # Be paranoid about flags + int $0x15 + popfl + + call a20_test + jnz a20_done + + # Try enabling A20 through the keyboard controller +a20_kbc: call empty_8042 + call a20_test # Just in case the BIOS worked + jnz a20_done # but had a delayed reaction. + movb $0xD1, %al # command write outb %al, $0x64 call empty_8042 @@ -661,29 +684,62 @@ outb %al, $0x60 call empty_8042 -# -# You must preserve the other bits here. Otherwise embarrasing things -# like laptops powering off on boot happen. Corrected version by Kira -# Brown from Linux 2.2 -# - inb $0x92, %al # - orb $02, %al # "fast A20" version - outb %al, $0x92 # some chips have only this - -# wait until a20 really *is* enabled; it can take a fair amount of -# time on certain systems; Toshiba Tecras are known to have this -# problem. The memory location used here (0x200) is the int 0x80 -# vector, which should be safe to use. - - xorw %ax, %ax # segment 0x0000 - movw %ax, %fs - decw %ax # segment 0xffff (HMA) - movw %ax, %gs -a20_wait: - incw %ax # unused memory location <0xfff0 - movw %ax, %fs:(0x200) # we use the "int 0x80" vector - cmpw %gs:(0x210), %ax # and its corresponding HMA addr - je a20_wait # loop until no longer aliased + # Wait until a20 really *is* enabled; it can take a fair amount of + # time on certain systems; Toshiba Tecras are known to have this + # problem. +a20_kbc_wait: + xorw %cx, %cx +a20_kbc_wait_loop: + call a20_test + jnz a20_done + loop a20_kbc_wait_loop + + # Final attempt: use "configuration port A" +a20_fast: + inb $0x92, %al # Configuration Port A + orb $0x02, %al # "fast A20" version + andb $0xFE, %al # don't accidentally reset + outb %al, $0x92 + + # Wait for configuration port A to take effect +a20_fast_wait: + xorw %cx, %cx +a20_fast_wait_loop: + call a20_test + jnz a20_done + loop a20_fast_wait_loop + + # A20 is still not responding. Try frobbing it again. + # + decb (a20_tries) + jnz a20_try_loop + + movw $a20_err_msg, %si + call prtstr + +a20_die: + hlt + jmp a20_die + +a20_tries: + .byte A20_ENABLE_LOOPS + +a20_err_msg: + .ascii "linux: fatal error: A20 gate not responding!" + .byte 13, 10, 0 + + # If we get here, all is good +a20_done: + +# set up gdt and idt + lidt idt_48 # load idt with 0,0 + xorl %eax, %eax # Compute gdt_base + movw %ds, %ax # (Convert %ds:gdt to a linear ptr) + shll $4, %eax + addl $gdt, %eax + movl %eax, (gdt_48+2) + lgdt gdt_48 # load gdt with whatever is + # appropriate # make sure any possible coprocessor is properly reset.. xorw %ax, %ax @@ -839,6 +895,37 @@ bootsect_panic_mess: .string "INT15 refuses to access high mem, giving up." + + +# This routine tests whether or not A20 is enabled. If so, it +# exits with zf = 0. +# +# The memory address used, 0x200, is the int $0x80 vector, which +# should be safe. + +A20_TEST_ADDR = 4*0x80 + +a20_test: + pushw %cx + pushw %ax + xorw %cx, %cx + movw %cx, %fs # Low memory + decw %cx + movw %cx, %gs # High memory area + movw $A20_TEST_LOOPS, %cx + movw %fs:(A20_TEST_ADDR), %ax + pushw %ax +a20_test_wait: + incw %ax + movw %ax, %fs:(A20_TEST_ADDR) + call delay # Serialize and make delay constant + cmpw %gs:(A20_TEST_ADDR+0x10), %ax + loope a20_test_wait + + popw %fs:(A20_TEST_ADDR) + popw %ax + popw %cx + ret # This routine checks that the keyboard command queue is empty # (after emptying the output buffers) diff -u --recursive --new-file v2.4.14/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.14/linux/arch/i386/defconfig Mon Nov 5 15:55:26 2001 +++ linux/arch/i386/defconfig Fri Nov 9 14:45:33 2001 @@ -597,11 +597,15 @@ CONFIG_AUTOFS4_FS=y # CONFIG_REISERFS_FS is not set # CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set diff -u --recursive --new-file v2.4.14/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v2.4.14/linux/arch/i386/kernel/Makefile Sun Sep 23 11:40:55 2001 +++ linux/arch/i386/kernel/Makefile Fri Nov 9 14:21:21 2001 @@ -38,7 +38,7 @@ obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o -obj-$(CONFIG_X86_IO_APIC) += io_apic.o +obj-$(CONFIG_X86_IO_APIC) += io_apic.o acpitable.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.14/linux/arch/i386/kernel/acpitable.c linux/arch/i386/kernel/acpitable.c --- v2.4.14/linux/arch/i386/kernel/acpitable.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/kernel/acpitable.c Fri Nov 9 15:02:20 2001 @@ -0,0 +1,897 @@ +/* + * acpitable.c - IA32-specific ACPI boot-time initialization (Revision: 1) + * + * Copyright (C) 1999 Andrew Henroid + * Copyright (C) 2001 Richard Schaal + * Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> + * Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com> + * Copyright (C) 2001 Arjan van de Ven <arjanv@redhat.com> + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/stddef.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <asm/mpspec.h> +#include <asm/io.h> +#include <asm/apic.h> +#include <asm/apicdef.h> +#include <asm/page.h> +#include <asm/pgtable.h> + +#define SELF_CONTAINED_ACPI + +#ifdef SELF_CONTAINED_ACPI +/* + * The following codes are cut&pasted from drivers/acpi. Part of the code + * there can be not updated or delivered yet. + * To avoid conflicts when CONFIG_ACPI is defined, the following codes are + * modified so that they are self-contained in this file. + * -- jun + */ +#define dprintk printk +typedef unsigned int ACPI_TBLPTR; + +#define AE_CODE_ENVIRONMENTAL 0x0000 +#define AE_OK (u32) 0x0000 +#define AE_ERROR (u32) (0x0001 | AE_CODE_ENVIRONMENTAL) +#define AE_NO_ACPI_TABLES (u32) (0x0002 | AE_CODE_ENVIRONMENTAL) +#define AE_NOT_FOUND (u32) (0x0005 | AE_CODE_ENVIRONMENTAL) + +typedef struct { /* ACPI common table header */ + char signature[4]; /* identifies type of table */ + u32 length; /* length of table, + in bytes, * including header */ + u8 revision; /* specification minor version # */ + u8 checksum; /* to make sum of entire table == 0 */ + char oem_id[6]; /* OEM identification */ + char oem_table_id[8]; /* OEM table identification */ + u32 oem_revision; /* OEM revision number */ + char asl_compiler_id[4]; /* ASL compiler vendor ID */ + u32 asl_compiler_revision; /* ASL compiler revision number */ +} acpi_table_header __attribute__ ((packed));; + +enum { + ACPI_APIC = 0, + ACPI_BOOT, + ACPI_DBGP, + ACPI_DSDT, + ACPI_ECDT, + ACPI_ETDT, + ACPI_FACP, + ACPI_FACS, + ACPI_OEMX, + ACPI_PSDT, + ACPI_SBST, + ACPI_SLIT, + ACPI_SPCR, + ACPI_SRAT, + ACPI_SSDT, + ACPI_SPMI, + ACPI_XSDT, + ACPI_TABLE_COUNT +}; + +static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { + "APIC", + "BOOT", + "DBGP", + "DSDT", + "ECDT", + "ETDT", + "FACP", + "FACS", + "OEM", + "PSDT", + "SBST", + "SLIT", + "SPCR", + "SRAT", + "SSDT", + "SPMI", + "XSDT" +}; + +struct acpi_table_madt { + acpi_table_header header; + u32 lapic_address; + struct { + u32 pcat_compat:1; + u32 reserved:31; + } flags __attribute__ ((packed)); +} __attribute__ ((packed));; + +enum { + ACPI_MADT_LAPIC = 0, + ACPI_MADT_IOAPIC, + ACPI_MADT_INT_SRC_OVR, + ACPI_MADT_NMI_SRC, + ACPI_MADT_LAPIC_NMI, + ACPI_MADT_LAPIC_ADDR_OVR, + ACPI_MADT_IOSAPIC, + ACPI_MADT_LSAPIC, + ACPI_MADT_PLAT_INT_SRC, + ACPI_MADT_ENTRY_COUNT +}; + +#define RSDP_SIG "RSD PTR " +#define RSDT_SIG "RSDT" + +#define ACPI_DEBUG_PRINT(pl) + +#define ACPI_MEMORY_MODE 0x01 +#define ACPI_LOGICAL_ADDRESSING 0x00 +#define ACPI_PHYSICAL_ADDRESSING 0x01 + +#define LO_RSDP_WINDOW_BASE 0 /* Physical Address */ +#define HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */ +#define LO_RSDP_WINDOW_SIZE 0x400 +#define HI_RSDP_WINDOW_SIZE 0x20000 +#define RSDP_SCAN_STEP 16 +#define RSDP_CHECKSUM_LENGTH 20 + +typedef int (*acpi_table_handler) (acpi_table_header * header, unsigned long); + +static acpi_table_handler acpi_boot_ops[ACPI_TABLE_COUNT]; + +struct acpi_table_rsdp { + char signature[8]; + u8 checksum; + char oem_id[6]; + u8 revision; + u32 rsdt_address; +} __attribute__ ((packed)); + +struct acpi_table_rsdt { + acpi_table_header header; + u32 entry[ACPI_TABLE_COUNT]; +} __attribute__ ((packed)); + +typedef struct { + u8 type; + u8 length; +} acpi_madt_entry_header __attribute__ ((packed)); + +typedef struct { + u16 polarity:2; + u16 trigger:2; + u16 reserved:12; +} acpi_madt_int_flags __attribute__ ((packed)); + +struct acpi_table_lapic { + acpi_madt_entry_header header; + u8 acpi_id; + u8 id; + struct { + u32 enabled:1; + u32 reserved:31; + } flags __attribute__ ((packed)); +} __attribute__ ((packed)); + +struct acpi_table_ioapic { + acpi_madt_entry_header header; + u8 id; + u8 reserved; + u32 address; + u32 global_irq_base; +} __attribute__ ((packed)); + +struct acpi_table_int_src_ovr { + acpi_madt_entry_header header; + u8 bus; + u8 bus_irq; + u32 global_irq; + acpi_madt_int_flags flags; +} __attribute__ ((packed)); + +struct acpi_table_nmi_src { + acpi_madt_entry_header header; + acpi_madt_int_flags flags; + u32 global_irq; +} __attribute__ ((packed)); + +struct acpi_table_lapic_nmi { + acpi_madt_entry_header header; + u8 acpi_id; + acpi_madt_int_flags flags; + u8 lint; +} __attribute__ ((packed)); + +struct acpi_table_lapic_addr_ovr { + acpi_madt_entry_header header; + u8 reserved[2]; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_iosapic { + acpi_madt_entry_header header; + u8 id; + u8 reserved; + u32 global_irq_base; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_lsapic { + acpi_madt_entry_header header; + u8 acpi_id; + u8 id; + u8 eid; + u8 reserved[3]; + struct { + u32 enabled:1; + u32 reserved:31; + } flags; +} __attribute__ ((packed)); + +struct acpi_table_plat_int_src { + acpi_madt_entry_header header; + acpi_madt_int_flags flags; + u8 type; + u8 id; + u8 eid; + u8 iosapic_vector; + u32 global_irq; + u32 reserved; +} __attribute__ ((packed)); + +/* + * ACPI Table Descriptor. One per ACPI table + */ +typedef struct acpi_table_desc { + struct acpi_table_desc *prev; + struct acpi_table_desc *next; + struct acpi_table_desc *installed_desc; + acpi_table_header *pointer; + void *base_pointer; + u8 *aml_pointer; + u64 physical_address; + u32 aml_length; + u32 length; + u32 count; + u16 table_id; + u8 type; + u8 allocation; + u8 loaded_into_namespace; + +} acpi_table_desc __attribute__ ((packed));; + +static unsigned char __init +acpi_tb_checksum(void *buffer, int length) +{ + int i; + unsigned char *bytebuffer; + unsigned char sum = 0; + + if (!buffer || length <= 0) + return 0; + + bytebuffer = (unsigned char *) buffer; + + for (i = 0; i < length; i++) + sum += *(bytebuffer++); + + return sum; +} + +static int __init +acpi_table_checksum(acpi_table_header * header) +{ + u8 *p = (u8 *) header; + int length = 0; + int sum = 0; + + if (!header) + return -EINVAL; + + length = header->length; + + while (length--) + sum += *p++; + + return sum & 0xFF; +} + +static void __init +acpi_print_table_header(acpi_table_header * header) +{ + if (!header) + return; + + printk(KERN_INFO "ACPI table found: %.4s v%d [%.6s %.8s %d.%d]\n", + header->signature, header->revision, header->oem_id, + header->oem_table_id, header->oem_revision >> 16, + header->oem_revision & 0xffff); + + return; +} + +/******************************************************************************* + * + * FUNCTION: Acpi_tb_scan_memory_for_rsdp + * + * PARAMETERS: Start_address - Starting pointer for search + * Length - Maximum length to search + * + * RETURN: Pointer to the RSDP if found, otherwise NULL. + * + * DESCRIPTION: Search a block of memory for the RSDP signature + * + ******************************************************************************/ + +static unsigned char *__init +acpi_tb_scan_memory_for_rsdp(unsigned char *address, int length) +{ + u32 offset; + + if (length <= 0) + return NULL; + + /* Search from given start addr for the requested length */ + + offset = 0; + + while (offset < length) { + /* The signature must match and the checksum must be correct */ + if (strncmp(address, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0 && + acpi_tb_checksum(address, RSDP_CHECKSUM_LENGTH) == 0) { + /* If so, we have found the RSDP */ + printk(KERN_INFO + "ACPI: RSDP located at physical address %p\n", + address); + return address; + } + offset += RSDP_SCAN_STEP; + address += RSDP_SCAN_STEP; + } + + /* Searched entire block, no RSDP was found */ + printk(KERN_INFO "ACPI: Searched entire block, no RSDP was found.\n"); + return NULL; +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_find_rsdp + * + * PARAMETERS: *Table_info - Where the table info is returned + * Flags - Current memory mode (logical vs. + * physical addressing) + * + * RETURN: Status + * + * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor + * pointer structure. If it is found, set *RSDP to point to it. + * + * NOTE: The RSDP must be either in the first 1_k of the Extended + * BIOS Data Area or between E0000 and FFFFF (ACPI 1.0 section + * 5.2.2; assertion #421). + * + ******************************************************************************/ + +static int __init +acpi_tb_find_rsdp(acpi_table_desc * table_info, u32 flags) +{ + unsigned char *address; + + /* + * Physical address is given. + */ + /* + * Region 1) Search EBDA (low memory) paragraphs + */ + address = + acpi_tb_scan_memory_for_rsdp(__va(LO_RSDP_WINDOW_BASE), + LO_RSDP_WINDOW_SIZE); + + if (address) { + /* Found it, return the physical address */ + table_info->physical_address = (ACPI_TBLPTR) __pa(address); + return AE_OK; + } + + /* + * Region 2) Search upper memory: 16-byte boundaries in E0000h-F0000h + */ + address = acpi_tb_scan_memory_for_rsdp(__va(HI_RSDP_WINDOW_BASE), + HI_RSDP_WINDOW_SIZE); + if (address) { + /* Found it, return the physical address */ + table_info->physical_address = (ACPI_TBLPTR) __pa(address); + return AE_OK; + } + + /* RSDP signature was not found */ + return AE_NOT_FOUND; +} + +static unsigned long __init +acpi_find_root_pointer(u32 flags) +{ + acpi_table_desc table_info; + int status; + + /* Get the RSDP */ + + status = acpi_tb_find_rsdp(&table_info, flags); + if (status) + return 0; + + return table_info.physical_address; +} + +static unsigned long __init +acpi_os_get_root_pointer(u32 flags) +{ + unsigned long address; + +#ifndef CONFIG_ACPI_EFI + + address = acpi_find_root_pointer(flags); + +#else + if (efi.acpi20) + address = (unsigned long) efi.acpi20; + else if (efi.acpi) + address = (unsigned long) efi.acpi; + else + address = 0; +#endif /*CONFIG_ACPI_EFI */ + + if (address == 0) + printk(KERN_ERR "ACPI: System description tables not found\n"); + + return address; +} + +/* + * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_0, + * to map the target physical address. The problem is that set_fixmap() + * provides a single page, and it is possible that the page is not + * sufficient. + * By using this area, we can map up to MAX_IO_APICS pages temporarily, + * i.e. until the next __va_range() call. + */ +static __inline__ char * +__va_range(unsigned long phys, unsigned long size) +{ + unsigned long base, offset, mapped_size, mapped_phys = phys; + int idx = FIX_IO_APIC_BASE_0; + + offset = phys & (PAGE_SIZE - 1); + mapped_size = PAGE_SIZE - offset; + set_fixmap(idx, mapped_phys); + base = fix_to_virt(FIX_IO_APIC_BASE_0); + + /* + * Most cases can be covered by the below. + */ + if (mapped_size >= size) + return ((unsigned char *) base + offset); + + dprintk("__va_range: mapping more than a single page, size = 0x%lx\n", + size); + + do { + if (idx++ == FIX_IO_APIC_BASE_END) + return 0; /* cannot handle this */ + mapped_phys = mapped_phys + PAGE_SIZE; + set_fixmap(idx, mapped_phys); + mapped_size = mapped_size + PAGE_SIZE; + } while (mapped_size < size); + + return ((unsigned char *) base + offset); +} + +static int __init acpi_tables_init(void) +{ + int result = -ENODEV; + int status = AE_OK; + unsigned long rsdp_addr = 0; + acpi_table_header *header = NULL; + struct acpi_table_rsdp *rsdp = NULL; +#ifndef CONFIG_IA64 + struct acpi_table_rsdt *rsdt = NULL; + struct acpi_table_rsdt saved_rsdt; +#else + struct acpi071_table_rsdt *rsdt = NULL; +#endif + int tables = 0; + int type = 0; + int i = 0; + + rsdp_addr = acpi_os_get_root_pointer(ACPI_PHYSICAL_ADDRESSING); + + if (!rsdp_addr) + return -ENODEV; + + rsdp = (struct acpi_table_rsdp *) rsdp_addr; + + printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision, + rsdp->oem_id); + if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) { + printk(KERN_WARNING "RSDP table signature incorrect\n"); + return -EINVAL; + } + + rsdt = (struct acpi_table_rsdt *) + __va_range(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt)); + + if (rsdt) { + header = (acpi_table_header *) & rsdt->header; + acpi_print_table_header(header); + if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) { + printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); + rsdt = NULL; + } else { + /* + * The number of tables is computed by taking the + * size of all entries (header size minus total + * size of RSDT) divided by the size of each entry + * (4-byte table pointers). + */ + tables = + (header->length - sizeof(acpi_table_header)) / 4; + } + } + + if (!rsdt) { + printk(KERN_WARNING + "ACPI: Invalid root system description tables (RSDT)\n"); + return -ENODEV; + } + + memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt)); + + if (saved_rsdt.header.length > sizeof(saved_rsdt)) { + printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", + saved_rsdt.header.length); + return -ENODEV; + } + + for (i = 0; i < tables; i++) { + + if (rsdt) { + header = (acpi_table_header *) + __va_range(saved_rsdt.entry[i], + sizeof(acpi_table_header)); + } + + if (!header) + break; + + acpi_print_table_header(header); + + for (type = 0; type < ACPI_TABLE_COUNT; type++) + if (!strncmp + ((char *) &header->signature, + acpi_table_signatures[type],strlen(acpi_table_signatures[type]))) + break; + + if (type >= ACPI_TABLE_COUNT) { + printk(KERN_WARNING "ACPI: Unsupported table %.4s\n", + header->signature); + continue; + } + + if (acpi_table_checksum(header)) { + printk(KERN_WARNING "ACPI %s has invalid checksum\n", + acpi_table_signatures[i]); + continue; + } + + if (acpi_boot_ops && acpi_boot_ops[type]) + result = + acpi_boot_ops[type] (header, + (unsigned long) saved_rsdt. + entry[i]); + } + + return result; +} +#endif /* SELF_CONTAINED_ACPI */ + +static int total_cpus __initdata = 0; +int have_acpi_tables; + +extern void __init MP_processor_info(struct mpc_config_processor *); + +static void __init +acpi_parse_lapic(struct acpi_table_lapic *local_apic) +{ + struct mpc_config_processor proc_entry; + int ix = 0; + + if (!local_apic) + return; + + dprintk(KERN_INFO "LAPIC (acpi_id[0x%04x] id[0x%x] enabled[%d])\n", + local_apic->acpi_id, local_apic->id, local_apic->flags.enabled); + + dprintk("CPU %d (0x%02x00)", total_cpus, local_apic->id); + + if (local_apic->flags.enabled) { + printk(" enabled"); + ix = local_apic->id; + if (ix >= MAX_APICS) { + printk(KERN_WARNING + "Processor #%d INVALID - (Max ID: %d).\n", ix, + MAX_APICS); + return; + } + /* + * Fill in the info we want to save. Not concerned about + * the processor ID. Processor features aren't present in + * the table. + */ + proc_entry.mpc_type = MP_PROCESSOR; + proc_entry.mpc_apicid = local_apic->id; + proc_entry.mpc_cpuflag = CPU_ENABLED; + if (proc_entry.mpc_apicid == boot_cpu_physical_apicid) { + printk(" (BSP)"); + proc_entry.mpc_cpuflag |= CPU_BOOTPROCESSOR; + } + proc_entry.mpc_cpufeature = + (boot_cpu_data.x86 << 8) | (boot_cpu_data. + x86_model << 4) | boot_cpu_data. + x86_mask; + proc_entry.mpc_featureflag = boot_cpu_data.x86_capability[0]; + proc_entry.mpc_reserved[0] = 0; + proc_entry.mpc_reserved[1] = 0; + proc_entry.mpc_apicver = 0x10; /* integrated APIC */ + MP_processor_info(&proc_entry); + } else { + printk(" disabled"); + } + printk("\n"); + + total_cpus++; + return; +} + +static void __init +acpi_parse_ioapic(struct acpi_table_ioapic *ioapic) +{ + + if (!ioapic) + return; + + printk(KERN_INFO + "IOAPIC (id[0x%x] address[0x%x] global_irq_base[0x%x])\n", + ioapic->id, ioapic->address, ioapic->global_irq_base); + + if (nr_ioapics >= MAX_IO_APICS) { + printk(KERN_WARNING + "Max # of I/O APICs (%d) exceeded (found %d).\n", + MAX_IO_APICS, nr_ioapics); + panic("Recompile kernel with bigger MAX_IO_APICS!\n"); + } +} + +static void __init +acpi_parse_int_src_ovr(struct acpi_table_int_src_ovr *intsrc) +{ + /* + static int first_time_switch = 0; + struct mpc_config_intsrc my_intsrc; + int i; + */ + if (!intsrc) + return; + + printk(KERN_INFO + "INT_SRC_OVR (bus[%d] irq[0x%x] global_irq[0x%x] polarity[0x%x] trigger[0x%x])\n", + intsrc->bus, intsrc->bus_irq, intsrc->global_irq, + intsrc->flags.polarity, intsrc->flags.trigger); +} + +/* + * At this point, we look at the interrupt assignment entries in the MPS + * table. + */ + +static void __init acpi_parse_nmi_src(struct acpi_table_nmi_src *nmisrc) +{ + if (!nmisrc) + return; + + printk(KERN_INFO + "NMI_SRC (polarity[0x%x] trigger[0x%x] global_irq[0x%x])\n", + nmisrc->flags.polarity, nmisrc->flags.trigger, + nmisrc->global_irq); + +} +static void __init +acpi_parse_lapic_nmi(struct acpi_table_lapic_nmi *localnmi) +{ + if (!localnmi) + return; + + printk(KERN_INFO + "LAPIC_NMI (acpi_id[0x%04x] polarity[0x%x] trigger[0x%x] lint[0x%x])\n", + localnmi->acpi_id, localnmi->flags.polarity, + localnmi->flags.trigger, localnmi->lint); +} +static void __init +acpi_parse_lapic_addr_ovr(struct acpi_table_lapic_addr_ovr *lapic_addr_ovr) +{ + if (!lapic_addr_ovr) + return; + + printk(KERN_INFO "LAPIC_ADDR_OVR (address[0x%lx])\n", + (unsigned long) lapic_addr_ovr->address); + +} + +#ifdef CONFIG_IA64 +static void __init +acpi_parse_iosapic(struct acpi_table_iosapic *iosapic) +{ + if (!iosapic) + return; + + printk(KERN_INFO "IOSAPIC (id[%x] global_irq_base[%x] address[%lx])\n", + iosapic->id, iosapic->global_irq_base, + (unsigned long) iosapic->address); + + return 0; +} +static void __init +acpi_parse_lsapic(struct acpi_table_lsapic *lsapic) +{ + if (!lsapic) + return; + + printk(KERN_INFO + "LSAPIC (acpi_id[0x%04x] id[0x%x] eid[0x%x] enabled[%d])\n", + lsapic->acpi_id, lsapic->id, lsapic->eid, lsapic->flags.enabled); + + if (!lsapic->flags.enabled) + return; +} +#endif +static void __init +acpi_parse_plat_int_src(struct acpi_table_plat_int_src *plintsrc) +{ + if (!plintsrc) + return; + + printk(KERN_INFO + "PLAT_INT_SRC (polarity[0x%x] trigger[0x%x] type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", + plintsrc->flags.polarity, plintsrc->flags.trigger, + plintsrc->type, plintsrc->id, plintsrc->eid, + plintsrc->iosapic_vector, plintsrc->global_irq); +} +static int __init +acpi_parse_madt(acpi_table_header * header, unsigned long phys) +{ + + struct acpi_table_madt *madt = + (struct acpi_table_madt *) __va_range(phys, header->length); + acpi_madt_entry_header *entry_header = NULL; + int table_size = 0; + + if (!madt) + return -EINVAL; + + table_size = (int) (header->length - sizeof(*madt)); + entry_header = + (acpi_madt_entry_header *) ((void *) madt + sizeof(*madt)); + + while (entry_header && (table_size > 0)) { + switch (entry_header->type) { + case ACPI_MADT_LAPIC: + acpi_parse_lapic((struct acpi_table_lapic *) + entry_header); + break; + case ACPI_MADT_IOAPIC: + acpi_parse_ioapic((struct acpi_table_ioapic *) + entry_header); + break; + case ACPI_MADT_INT_SRC_OVR: + acpi_parse_int_src_ovr((struct acpi_table_int_src_ovr *) + entry_header); + break; + case ACPI_MADT_NMI_SRC: + acpi_parse_nmi_src((struct acpi_table_nmi_src *) + entry_header); + break; + case ACPI_MADT_LAPIC_NMI: + acpi_parse_lapic_nmi((struct acpi_table_lapic_nmi *) + entry_header); + break; + case ACPI_MADT_LAPIC_ADDR_OVR: + acpi_parse_lapic_addr_ovr((struct + acpi_table_lapic_addr_ovr *) + entry_header); + break; +#ifdef CONFIG_IA64 + case ACPI_MADT_IOSAPIC: + acpi_parse_iosapic((struct acpi_table_iosapic *) + entry_header); + break; + case ACPI_MADT_LSAPIC: + acpi_parse_lsapic((struct acpi_table_lsapic *) + entry_header); + break; +#endif + case ACPI_MADT_PLAT_INT_SRC: + acpi_parse_plat_int_src((struct acpi_table_plat_int_src + *) entry_header); + break; + default: + printk(KERN_WARNING + "Unsupported MADT entry type 0x%x\n", + entry_header->type); + break; + } + table_size -= entry_header->length; + entry_header = + (acpi_madt_entry_header *) ((void *) entry_header + + entry_header->length); + } + + if (!total_cpus) { + printk("ACPI: No Processors found in the APCI table.\n"); + return -EINVAL; + } + + printk(KERN_INFO "%d CPUs total\n", total_cpus); + + if (madt->lapic_address) + mp_lapic_addr = madt->lapic_address; + else + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + + printk(KERN_INFO "Local APIC address %x\n", madt->lapic_address); + + return 0; +} + +extern int enable_acpi_smp_table; + +/* + * Configure the processor info using MADT in the ACPI tables. If we fail to + * configure that, then we use the MPS tables. + */ +void __init +config_acpi_tables(void) +{ + int result = 0; + + /* + * Only do this when requested, either because of CPU/Bios type or from the command line + */ + if (!enable_acpi_smp_table) { + return; + } + + memset(&acpi_boot_ops, 0, sizeof(acpi_boot_ops)); + acpi_boot_ops[ACPI_APIC] = acpi_parse_madt; + result = acpi_tables_init(); + + if (!result) { + have_acpi_tables = 1; + printk("Enabling the CPU's according to the ACPI table\n"); + } +} diff -u --recursive --new-file v2.4.14/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c --- v2.4.14/linux/arch/i386/kernel/apic.c Mon Nov 5 15:55:26 2001 +++ linux/arch/i386/kernel/apic.c Fri Nov 9 14:12:55 2001 @@ -575,7 +575,6 @@ static int __init detect_init_APIC (void) { u32 h, l, features; - int needs_pm = 0; extern void get_cpu_vendor(struct cpuinfo_x86*); /* Workaround for us being called before identify_cpu(). */ @@ -608,7 +607,6 @@ l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; wrmsr(MSR_IA32_APICBASE, l, h); - needs_pm = 1; } } /* @@ -628,8 +626,7 @@ printk("Found and enabled local APIC!\n"); - if (needs_pm) - apic_pm_init1(); + apic_pm_init1(); return 0; diff -u --recursive --new-file v2.4.14/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.4.14/linux/arch/i386/kernel/apm.c Tue Oct 23 22:48:49 2001 +++ linux/arch/i386/kernel/apm.c Fri Nov 9 13:58:02 2001 @@ -1471,7 +1471,7 @@ as = filp->private_data; if (check_apm_user(as, "ioctl")) return -EIO; - if (!as->suser) + if ((!as->suser) || (!as->writer)) return -EPERM; switch (cmd) { case APM_IOC_STANDBY: diff -u --recursive --new-file v2.4.14/linux/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c --- v2.4.14/linux/arch/i386/kernel/dmi_scan.c Tue Oct 23 22:48:49 2001 +++ linux/arch/i386/kernel/dmi_scan.c Fri Nov 9 15:02:20 2001 @@ -7,10 +7,12 @@ #include <linux/slab.h> #include <asm/io.h> #include <linux/pm.h> -#include <linux/keyboard.h> #include <asm/keyboard.h> +#include <asm/system.h> +unsigned long dmi_broken; int is_sony_vaio_laptop; +int enable_acpi_smp_table; struct dmi_header { @@ -87,7 +89,7 @@ } -int __init dmi_iterate(void (*decode)(struct dmi_header *)) +static int __init dmi_iterate(void (*decode)(struct dmi_header *)) { unsigned char buf[20]; long fp=0xE0000L; @@ -98,7 +100,7 @@ * Skip on x86/64 with simnow. Will eventually go away * If you see this ifdef in 2.6pre mail me ! */ - return; + return -1; #endif while( fp < 0xFFFFF) @@ -315,15 +317,14 @@ return 0; } -#if defined(CONFIG_SONYPI) || defined(CONFIG_SONYPI_MODULE) /* - * Check for a Sony Vaio system in order to enable the use of - * the sonypi driver (we don't want this driver to be used on - * other systems, even if they have the good PCI IDs). + * Check for a Sony Vaio system * - * This one isn't a bug detect for those who asked, we simply want to - * activate Sony specific goodies like the camera and jogdial.. + * On a Sony system we want to enable the use of the sonypi + * driver for Sony-specific goodies like the camera and jogdial. + * We also want to avoid using certain functions of the PnP BIOS. */ + static __init int sony_vaio_laptop(struct dmi_blacklist *d) { if (is_sony_vaio_laptop == 0) @@ -333,7 +334,6 @@ } return 0; } -#endif /* * This bios swaps the APM minute reporting bytes over (Many sony laptops @@ -359,18 +359,49 @@ printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n"); printk(KERN_INFO " *** Many BIOSes matching this signature have incorrect IRQ routing tables.\n"); printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n"); - printk(KERN_INFO " *** contact your vendor and ask about updates.\n"); + printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n"); printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n"); return 0; } /* + * ASUS K7V-RM has broken ACPI table defining sleep modes + */ + +static __init int broken_acpi_Sx(struct dmi_blacklist *d) +{ + printk(KERN_WARNING "Detected ASUS mainboard with broken ACPI sleep table\n"); + dmi_broken |= BROKEN_ACPI_Sx; + return 0; +} + +/* + * Toshiba keyboard likes to repeat keys when they are not repeated. + */ + +static __init int broken_toshiba_keyboard(struct dmi_blacklist *d) +{ + printk(KERN_WARNING "Toshiba with broken keyboard detected. If your keyboard sometimes generates 3 keypresses instead of one, contact pavel@ucw.cz\n"); + return 0; +} + +/* + * Toshiba fails to preserve interrupts over S1 + */ + +static __init int init_ints_after_s1(struct dmi_blacklist *d) +{ + printk(KERN_WARNING "Toshiba with broken S1 detected.\n"); + dmi_broken |= BROKEN_INIT_AFTER_S1; + return 0; +} + +/* * Some Bioses enable the PS/2 mouse (touchpad) at resume, even if it * was disabled before the suspend. Linux gets terribly confused by that. */ typedef void (pm_kbd_func) (void); -extern pm_kbd_func *pm_kbd_request_override; static __init int broken_ps2_resume(struct dmi_blacklist *d) { @@ -380,11 +411,20 @@ pm_kbd_request_override = pckbd_pm_resume; printk(KERN_INFO "%s machine detected. Mousepad Resume Bug workaround enabled.\n", d->ident); } -#endif +#endif return 0; } +/* + * Simple "print if true" callback + */ + +static __init int print_if_true(struct dmi_blacklist *d) +{ + printk("%s\n", d->ident); + return 0; +} /* * Process the DMI blacklists @@ -428,10 +468,6 @@ MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"), NO_MATCH, NO_MATCH } }, - { set_apm_ints, "IBM", { /* Allow interrupts during suspend on IBM laptops */ - MATCH(DMI_SYS_VENDOR, "IBM"), - NO_MATCH, NO_MATCH, NO_MATCH - } }, { set_apm_ints, "Dell Inspiron", { /* Allow interrupts during suspend on Dell Inspiron laptops*/ MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"), @@ -459,13 +495,11 @@ MATCH(DMI_BIOS_VENDOR,"SystemSoft"), MATCH(DMI_BIOS_VERSION,"Version R2.08") } }, -#if defined(CONFIG_SONYPI) || defined(CONFIG_SONYPI_MODULE) { sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */ MATCH(DMI_SYS_VENDOR, "Sony Corporation"), MATCH(DMI_PRODUCT_NAME, "PCG-"), NO_MATCH, NO_MATCH, } }, -#endif { swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-N505X(DE) */ MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), MATCH(DMI_BIOS_VERSION, "R0206H"), @@ -536,11 +570,47 @@ MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0125.P13"), NO_MATCH, NO_MATCH } }, + { broken_pirq, "l44GX Bios", { /* Bad $PIR */ + MATCH(DMI_BIOS_VENDOR, "Intel Corporation"), + MATCH(DMI_BIOS_VERSION,"L440GX0.86B.0066.P07.9906041405"), + NO_MATCH, NO_MATCH + } }, /* Intel in disgiuse - In this case they can't hide and they don't run too well either... */ { broken_pirq, "Dell PowerEdge 8450", { /* Bad $PIR */ MATCH(DMI_PRODUCT_NAME, "Dell PowerEdge 8450"), + NO_MATCH, NO_MATCH, NO_MATCH + } }, + + { broken_acpi_Sx, "ASUS K7V-RM", { /* Bad ACPI Sx table */ + MATCH(DMI_BIOS_VERSION,"ASUS K7V-RM ACPI BIOS Revision 1003A"), + MATCH(DMI_BOARD_NAME, "<K7V-RM>"), + NO_MATCH, NO_MATCH + } }, + + { broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */ + MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), + NO_MATCH, NO_MATCH, NO_MATCH + } }, + { init_ints_after_s1, "Toshiba Satellite 4030cdt", { /* Reinitialization of 8259 is needed after S1 resume */ + MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), + NO_MATCH, NO_MATCH, NO_MATCH + } }, + + { print_if_true, KERN_WARNING "IBM T23 - BIOS 1.03b+ and controller firmware 1.02+ may be needed for Linux APM.", { + MATCH(DMI_SYS_VENDOR, "IBM"), + MATCH(DMI_BIOS_VERSION, "1AET38WW (1.01b)"), + NO_MATCH, NO_MATCH + } }, + + + /* + * Generic per vendor APM settings + */ + + { set_apm_ints, "IBM", { /* Allow interrupts during suspend on IBM laptops */ + MATCH(DMI_SYS_VENDOR, "IBM"), NO_MATCH, NO_MATCH, NO_MATCH } }, diff -u --recursive --new-file v2.4.14/linux/arch/i386/kernel/mpparse.c linux/arch/i386/kernel/mpparse.c --- v2.4.14/linux/arch/i386/kernel/mpparse.c Tue Oct 9 17:06:51 2001 +++ linux/arch/i386/kernel/mpparse.c Fri Nov 9 14:58:18 2001 @@ -36,6 +36,7 @@ */ int apic_version [MAX_APICS]; int mp_bus_id_to_type [MAX_MP_BUSSES]; +int mp_bus_id_to_node [MAX_MP_BUSSES]; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_current_pci_id; @@ -55,6 +56,7 @@ /* Processor that is doing the boot up */ unsigned int boot_cpu_physical_apicid = -1U; +unsigned int boot_cpu_logical_apicid = -1U; /* Internal processor count */ static unsigned int num_processors; @@ -118,18 +120,45 @@ return n; } -static void __init MP_processor_info (struct mpc_config_processor *m) -{ - int ver; +#ifdef CONFIG_X86_IO_APIC +extern int have_acpi_tables; /* set by acpitable.c */ +#else +#define have_acpi_tables (0) +#endif + +/* + * Have to match translation table entries to main table entries by counter + * hence the mpc_record variable .... can't see a less disgusting way of + * doing this .... + */ + +static int mpc_record; +static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata; +void __init MP_processor_info (struct mpc_config_processor *m) +{ + int ver, quad, logical_apicid; + if (!(m->mpc_cpuflag & CPU_ENABLED)) return; - printk("Processor #%d %s APIC version %d\n", - m->mpc_apicid, - mpc_family( (m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , - (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), - m->mpc_apicver); + logical_apicid = m->mpc_apicid; + if (clustered_apic_mode) { + quad = translation_table[mpc_record]->trans_quad; + logical_apicid = (quad << 4) + + (m->mpc_apicid ? m->mpc_apicid << 1 : 1); + printk("Processor #%d %s APIC version %d (quad %d, apic %d)\n", + m->mpc_apicid, + mpc_family((m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , + (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), + m->mpc_apicver, quad, logical_apicid); + } else { + printk("Processor #%d %s APIC version %d\n", + m->mpc_apicid, + mpc_family((m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , + (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), + m->mpc_apicver); + } if (m->mpc_featureflag&(1<<0)) Dprintk(" Floating point unit present.\n"); @@ -172,7 +201,8 @@ Dprintk(" Willamette New Instructions present.\n"); if (m->mpc_featureflag&(1<<27)) Dprintk(" Self Snoop present.\n"); - /* 28 Reserved */ + if (m->mpc_featureflag&(1<<28)) + Dprintk(" HT present.\n"); if (m->mpc_featureflag&(1<<29)) Dprintk(" Thermal Monitor present.\n"); /* 30, 31 Reserved */ @@ -181,6 +211,7 @@ if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { Dprintk(" Bootup CPU\n"); boot_cpu_physical_apicid = m->mpc_apicid; + boot_cpu_logical_apicid = logical_apicid; } num_processors++; @@ -192,12 +223,11 @@ } ver = m->mpc_apicver; - if (clustered_apic_mode) - /* Crude temporary hack. Assumes processors are sequential */ - phys_cpu_present_map |= 1 << (num_processors-1); - else + if (clustered_apic_mode) { + phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad); + } else { phys_cpu_present_map |= 1 << m->mpc_apicid; - + } /* * Validate version */ @@ -214,7 +244,13 @@ memcpy(str, m->mpc_bustype, 6); str[6] = 0; - Dprintk("Bus #%d is %s\n", m->mpc_busid, str); + + if (clustered_apic_mode) { + mp_bus_id_to_node[m->mpc_busid] = translation_table[mpc_record]->trans_quad; + printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, mp_bus_id_to_node[m->mpc_busid]); + } else { + Dprintk("Bus #%d is %s\n", m->mpc_busid, str); + } if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; @@ -286,6 +322,63 @@ BUG(); } +static void __init MP_translation_info (struct mpc_config_translation *m) +{ + printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, + m->trans_quad, m->trans_global, m->trans_local); + + if (mpc_record >= MAX_MPC_ENTRY) + printk("MAX_MPC_ENTRY exceeded!\n"); + else + translation_table[mpc_record] = m; /* stash this for later */ +} + +/* + * Read/parse the MPC oem tables + */ + +static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \ + unsigned short oemsize) +{ + int count = sizeof (*oemtable); /* the header size */ + unsigned char *oemptr = ((unsigned char *)oemtable)+count; + + printk("Found an OEM MPC table at %8p - parsing it ... \n", oemtable); + if (memcmp(oemtable->oem_signature,MPC_OEM_SIGNATURE,4)) + { + printk("SMP mpc oemtable: bad signature [%c%c%c%c]!\n", + oemtable->oem_signature[0], + oemtable->oem_signature[1], + oemtable->oem_signature[2], + oemtable->oem_signature[3]); + return; + } + if (mpf_checksum((unsigned char *)oemtable,oemtable->oem_length)) + { + printk("SMP oem mptable: checksum error!\n"); + return; + } + while (count < oemtable->oem_length) { + switch (*oemptr) { + case MP_TRANSLATION: + { + struct mpc_config_translation *m= + (struct mpc_config_translation *)oemptr; + MP_translation_info(m); + oemptr += sizeof(*m); + count += sizeof(*m); + ++mpc_record; + break; + } + default: + { + printk("Unrecognised OEM table entry type! - %d\n", (int) *oemptr); + return; + } + } + } +} + /* * Read/parse the MPC */ @@ -327,8 +420,18 @@ printk("APIC at: 0x%lX\n",mpc->mpc_lapic); - /* save the local APIC address, it might be non-default */ - mp_lapic_addr = mpc->mpc_lapic; + /* save the local APIC address, it might be non-default, + * but only if we're not using the ACPI tables + */ + if (!have_acpi_tables) + mp_lapic_addr = mpc->mpc_lapic; + + if (clustered_apic_mode && mpc->mpc_oemptr) { + /* We need to process the oem mpc tables to tell us which quad things are in ... */ + mpc_record = 0; + smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, mpc->mpc_oemsize); + mpc_record = 0; + } /* * Now process the configuration blocks. @@ -339,7 +442,10 @@ { struct mpc_config_processor *m= (struct mpc_config_processor *)mpt; - MP_processor_info(m); + + /* ACPI may already have provided this one for us */ + if (!have_acpi_tables) + MP_processor_info(m); mpt += sizeof(*m); count += sizeof(*m); break; @@ -381,7 +487,13 @@ count+=sizeof(*m); break; } + default: + { + count = mpc->mpc_length; + break; + } } + ++mpc_record; } if (clustered_apic_mode && nr_ioapics > 2) { /* don't initialise IO apics on secondary quads */ @@ -550,6 +662,7 @@ } static struct intel_mp_floating *mpf_found; +extern void config_acpi_tables(void); /* * Scan the memory blocks for an SMP configuration block. @@ -557,6 +670,18 @@ void __init get_smp_config (void) { struct intel_mp_floating *mpf = mpf_found; + +#ifdef CONFIG_X86_IO_APIC + /* + * Check if the ACPI tables are provided. Use them only to get + * the processor information, mainly because it provides + * the info on the logical processor(s), rather than the physical + * processor(s) that are provided by the MPS. We attempt to + * check only if the user provided a commandline override + */ + config_acpi_tables(); +#endif + printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); if (mpf->mpf_feature2 & (1<<7)) { printk(" IMCR and PIC compatibility mode.\n"); diff -u --recursive --new-file v2.4.14/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.4.14/linux/arch/i386/kernel/mtrr.c Mon Nov 5 15:55:26 2001 +++ linux/arch/i386/kernel/mtrr.c Fri Nov 9 13:58:02 2001 @@ -2249,9 +2249,11 @@ proc_root_mtrr->proc_fops = &mtrr_fops; } #endif +#ifdef USERSPACE_INTERFACE devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUGO | S_IWUSR, &mtrr_fops, NULL); +#endif init_table (); return 0; } /* End Function mtrr_init */ diff -u --recursive --new-file v2.4.14/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c --- v2.4.14/linux/arch/i386/kernel/pci-pc.c Mon Nov 5 15:55:26 2001 +++ linux/arch/i386/kernel/pci-pc.c Fri Nov 9 13:58:02 2001 @@ -309,7 +309,7 @@ * This should be close to trivial, but it isn't, because there are buggy * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. */ -static int __init pci_sanity_check(struct pci_ops *o) +static int __devinit pci_sanity_check(struct pci_ops *o) { u16 x; struct pci_bus bus; /* Fake bus and device */ @@ -329,7 +329,7 @@ return 0; } -static struct pci_ops * __init pci_check_direct(void) +static struct pci_ops * __devinit pci_check_direct(void) { unsigned int tmp; unsigned long flags; @@ -488,7 +488,7 @@ static int pci_bios_present; -static int __init check_pcibios(void) +static int __devinit check_pcibios(void) { u32 signature, eax, ebx, ecx; u8 status, major_ver, minor_ver, hw_mech; @@ -538,7 +538,7 @@ return 0; } -static int __init pci_bios_find_device (unsigned short vendor, unsigned short device_id, +static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short device_id, unsigned short index, unsigned char *bus, unsigned char *device_fn) { unsigned short bx; @@ -747,7 +747,7 @@ * Try to find PCI BIOS. */ -static struct pci_ops * __init pci_find_bios(void) +static struct pci_ops * __devinit pci_find_bios(void) { union bios32 *check; unsigned char sum; @@ -801,7 +801,7 @@ * which used BIOS ordering, we are bound to do this... */ -static void __init pcibios_sort(void) +static void __devinit pcibios_sort(void) { LIST_HEAD(sorted_devices); struct list_head *ln; @@ -855,7 +855,7 @@ u16 segment; } __attribute__((packed)); -struct irq_routing_table * __init pcibios_get_irq_routing_table(void) +struct irq_routing_table * __devinit pcibios_get_irq_routing_table(void) { struct irq_routing_options opt; struct irq_routing_table *rt = NULL; @@ -929,7 +929,7 @@ * expected to be unique) and remove the ghost devices. */ -static void __init pcibios_fixup_ghosts(struct pci_bus *b) +static void __devinit pcibios_fixup_ghosts(struct pci_bus *b) { struct list_head *ln, *mn; struct pci_dev *d, *e; @@ -979,7 +979,7 @@ * Discover remaining PCI buses in case there are peer host bridges. * We use the number of last PCI bus provided by the PCI BIOS. */ -static void __init pcibios_fixup_peer_bridges(void) +static void __devinit pcibios_fixup_peer_bridges(void) { int n; struct pci_bus bus; @@ -1010,7 +1010,7 @@ * Exceptions for specific devices. Usually work-arounds for fatal design flaws. */ -static void __init pci_fixup_i450nx(struct pci_dev *d) +static void __devinit pci_fixup_i450nx(struct pci_dev *d) { /* * i450NX -- Find and scan all secondary buses on all PXB's. @@ -1032,7 +1032,7 @@ pcibios_last_bus = -1; } -static void __init pci_fixup_i450gx(struct pci_dev *d) +static void __devinit pci_fixup_i450gx(struct pci_dev *d) { /* * i450GX and i450KX -- Find and scan all secondary buses. @@ -1045,49 +1045,7 @@ pcibios_last_bus = -1; } -#if 0 -/* Until we get proper handling pray the BIOS gets it right */ -/* - * ServerWorks host bridges -- Find and scan all secondary buses. - * Register 0x44 contains first, 0x45 last bus number routed there. - */ -static void __init pci_fixup_serverworks(struct pci_dev *d) -{ - u8 busno1, busno2; - - pci_read_config_byte(d, 0x44, &busno1); - pci_read_config_byte(d, 0x45, &busno2); - if (busno2 < busno1) - busno2 = busno1; - if (busno2 > pcibios_last_bus) { - pcibios_last_bus = busno2; - printk("PCI: ServerWorks host bridge: last bus %02x\n", pcibios_last_bus); - } -} -#endif - -#if 0 -/* Our bus code shouldnt need this fixup any more. Delete once verified */ -/* - * Compaq host bridges -- Find and scan all secondary buses. - * This time registers 0xc8 and 0xc9. - */ -static void __init pci_fixup_compaq(struct pci_dev *d) -{ - u8 busno1, busno2; - - pci_read_config_byte(d, 0xc8, &busno1); - pci_read_config_byte(d, 0xc9, &busno2); - if (busno2 < busno1) - busno2 = busno1; - if (busno2 > pcibios_last_bus) { - pcibios_last_bus = busno2; - printk("PCI: Compaq host bridge: last bus %02x\n", busno2); - } -} -#endif - -static void __init pci_fixup_umc_ide(struct pci_dev *d) +static void __devinit pci_fixup_umc_ide(struct pci_dev *d) { /* * UM8886BF IDE controller sets region type bits incorrectly, @@ -1100,7 +1058,7 @@ d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; } -static void __init pci_fixup_ide_bases(struct pci_dev *d) +static void __devinit pci_fixup_ide_bases(struct pci_dev *d) { int i; @@ -1119,7 +1077,7 @@ } } -static void __init pci_fixup_ide_trash(struct pci_dev *d) +static void __devinit pci_fixup_ide_trash(struct pci_dev *d) { int i; @@ -1132,7 +1090,7 @@ d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0; } -static void __init pci_fixup_latency(struct pci_dev *d) +static void __devinit pci_fixup_latency(struct pci_dev *d) { /* * SiS 5597 and 5598 chipsets require latency timer set to @@ -1142,7 +1100,7 @@ pcibios_max_latency = 32; } -static void __init pci_fixup_piix4_acpi(struct pci_dev *d) +static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d) { /* * PIIX4 ACPI device: hardwired IRQ9 @@ -1173,16 +1131,6 @@ struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx }, -#if 0 -/* Until we get proper handling pray the BIOS gets it right */ - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HE, pci_fixup_serverworks }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, pci_fixup_serverworks }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CMIC_HE, pci_fixup_serverworks }, -#endif -#if 0 -/* Our bus code shouldnt need this fixup any more. Delete once verified */ - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_6010, pci_fixup_compaq }, -#endif { PCI_FIXUP_HEADER, PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_fixup_ide_trash }, { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, @@ -1198,14 +1146,14 @@ * are examined. */ -void __init pcibios_fixup_bus(struct pci_bus *b) +void __devinit pcibios_fixup_bus(struct pci_bus *b) { pcibios_fixup_ghosts(b); pci_read_bridge_bases(b); } -void __init pcibios_config_init(void) +void __devinit pcibios_config_init(void) { /* * Try all known PCI access methods. Note that we support using @@ -1262,7 +1210,7 @@ #endif } -char * __init pcibios_setup(char *str) +char * __devinit pcibios_setup(char *str) { if (!strcmp(str, "off")) { pci_probe = 0; diff -u --recursive --new-file v2.4.14/linux/arch/i386/kernel/semaphore.c linux/arch/i386/kernel/semaphore.c --- v2.4.14/linux/arch/i386/kernel/semaphore.c Thu Apr 12 12:22:53 2001 +++ linux/arch/i386/kernel/semaphore.c Fri Nov 9 13:58:02 2001 @@ -243,7 +243,8 @@ .globl __write_lock_failed __write_lock_failed: " LOCK "addl $" RW_LOCK_BIAS_STR ",(%eax) -1: cmpl $" RW_LOCK_BIAS_STR ",(%eax) +1: rep; nop + cmpl $" RW_LOCK_BIAS_STR ",(%eax) jne 1b " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax) @@ -255,7 +256,8 @@ .globl __read_lock_failed __read_lock_failed: lock ; incl (%eax) -1: cmpl $1,(%eax) +1: rep; nop + cmpl $1,(%eax) js 1b lock ; decl (%eax) diff -u --recursive --new-file v2.4.14/linux/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c --- v2.4.14/linux/arch/i386/lib/usercopy.c Sun Sep 23 11:40:55 2001 +++ linux/arch/i386/lib/usercopy.c Fri Nov 9 13:58:02 2001 @@ -165,6 +165,8 @@ unsigned long res, tmp; __asm__ __volatile__( + " testl %0, %0\n" + " jz 3f\n" " andl %0,%%ecx\n" "0: repne; scasb\n" " setne %%al\n" @@ -173,6 +175,8 @@ "1:\n" ".section .fixup,\"ax\"\n" "2: xorl %%eax,%%eax\n" + " jmp 1b\n" + "3: movb $1,%%al\n" " jmp 1b\n" ".previous\n" ".section __ex_table,\"a\"\n" diff -u --recursive --new-file v2.4.14/linux/arch/ia64/Makefile linux/arch/ia64/Makefile --- v2.4.14/linux/arch/ia64/Makefile Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/Makefile Fri Nov 9 14:26:17 2001 @@ -17,13 +17,15 @@ AFLAGS_KERNEL := -mconstant-gp EXTRA = -CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127 -falign-functions=32 +CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \ + -falign-functions=32 +# -ffunction-sections CFLAGS_KERNEL := -mconstant-gp GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') ifneq ($(GCC_VERSION),2) - CFLAGS += -frename-registers + CFLAGS += -frename-registers --param max-inline-insns=400 endif ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y) @@ -32,7 +34,7 @@ ifdef CONFIG_IA64_GENERIC CORE_FILES := arch/$(ARCH)/hp/hp.a \ - arch/$(ARCH)/sn/sn.a \ + arch/$(ARCH)/sn/sn.o \ arch/$(ARCH)/dig/dig.a \ arch/$(ARCH)/sn/io/sgiio.o \ $(CORE_FILES) @@ -52,15 +54,14 @@ $(CORE_FILES) endif -ifdef CONFIG_IA64_SGI_SN1 +ifdef CONFIG_IA64_SGI_SN CFLAGS += -DBRINGUP - SUBDIRS := arch/$(ARCH)/sn/sn1 \ - arch/$(ARCH)/sn \ + SUBDIRS := arch/$(ARCH)/sn/kernel \ arch/$(ARCH)/sn/io \ arch/$(ARCH)/sn/fprom \ $(SUBDIRS) - CORE_FILES := arch/$(ARCH)/sn/sn.a \ - arch/$(ARCH)/sn/io/sgiio.o\ + CORE_FILES := arch/$(ARCH)/sn/kernel/sn.o \ + arch/$(ARCH)/sn/io/sgiio.o \ $(CORE_FILES) endif @@ -105,7 +106,7 @@ compressed: vmlinux $(OBJCOPY) --strip-all vmlinux vmlinux-tmp - gzip -9 vmlinux-tmp + gzip vmlinux-tmp mv vmlinux-tmp.gz vmlinux.gz rawboot: diff -u --recursive --new-file v2.4.14/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.4.14/linux/arch/ia64/config.in Tue Oct 23 22:48:49 2001 +++ linux/arch/ia64/config.in Fri Nov 9 14:26:17 2001 @@ -28,6 +28,7 @@ if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then define_bool CONFIG_ACPI y + define_bool CONFIG_ACPI_EFI y define_bool CONFIG_ACPI_INTERPRETER y define_bool CONFIG_ACPI_KERNEL_CONFIG y fi @@ -40,7 +41,8 @@ "generic CONFIG_IA64_GENERIC \ DIG-compliant CONFIG_IA64_DIG \ HP-simulator CONFIG_IA64_HP_SIM \ - SGI-SN1 CONFIG_IA64_SGI_SN1" generic + SGI-SN1 CONFIG_IA64_SGI_SN1 \ + SGI-SN2 CONFIG_IA64_SGI_SN2" generic choice 'Kernel page size' \ "4KB CONFIG_IA64_PAGE_SIZE_4KB \ @@ -51,25 +53,6 @@ if [ "$CONFIG_ITANIUM" = "y" ]; then define_bool CONFIG_IA64_BRL_EMU y bool ' Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC - if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then - bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC - fi - if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then - bool ' Enable Itanium B1-step specific code' CONFIG_ITANIUM_B1_SPECIFIC - fi - if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then - bool ' Enable Itanium B2-step specific code' CONFIG_ITANIUM_B2_SPECIFIC - fi - bool ' Enable Itanium C-step specific code' CONFIG_ITANIUM_CSTEP_SPECIFIC - if [ "$CONFIG_ITANIUM_CSTEP_SPECIFIC" = "y" ]; then - bool ' Enable Itanium C0-step specific code' CONFIG_ITANIUM_C0_SPECIFIC - fi - if [ "$CONFIG_ITANIUM_B0_SPECIFIC" = "y" \ - -o "$CONFIG_ITANIUM_B1_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B2_SPECIFIC" = "y" ]; then - define_bool CONFIG_ITANIUM_PTCG n - else - define_bool CONFIG_ITANIUM_PTCG y - fi if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then define_int CONFIG_IA64_L1_CACHE_SHIFT 7 # align cache-sensitive data to 128 bytes else @@ -78,7 +61,6 @@ fi if [ "$CONFIG_MCKINLEY" = "y" ]; then - define_bool CONFIG_ITANIUM_PTCG y define_int CONFIG_IA64_L1_CACHE_SHIFT 7 bool ' Enable McKinley A-step specific code' CONFIG_MCKINLEY_ASTEP_SPECIFIC if [ "$CONFIG_MCKINLEY_ASTEP_SPECIFIC" = "y" ]; then @@ -87,28 +69,32 @@ fi if [ "$CONFIG_IA64_DIG" = "y" ]; then - bool ' Force interrupt redirection' CONFIG_IA64_HAVE_IRQREDIR bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA define_bool CONFIG_PM y fi -if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then - bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM - define_bool CONFIG_DEVFS_DEBUG y +if [ "$CONFIG_IA64_SGI_SN1" = "y" ] || [ "$CONFIG_IA64_SGI_SN2" = "y" ]; then + define_bool CONFIG_IA64_SGI_SN y + bool ' Enable extra debugging code' CONFIG_IA64_SGI_SN_DEBUG n + bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN_SIM + bool ' Enable autotest (llsc). Option to run cache test instead of booting' \ + CONFIG_IA64_SGI_AUTOTEST n define_bool CONFIG_DEVFS_FS y - define_bool CONFIG_IA64_BRL_EMU y + if [ "$CONFIG_DEVFS_FS" = "y" ]; then + bool ' Enable DEVFS Debug Code' CONFIG_DEVFS_DEBUG n + fi + bool ' Enable protocol mode for the L1 console' CONFIG_SERIAL_SGI_L1_PROTOCOL y + define_bool CONFIG_DISCONTIGMEM y define_bool CONFIG_IA64_MCA y - define_bool CONFIG_ITANIUM y - define_bool CONFIG_SGI_IOC3_ETH y + define_bool CONFIG_NUMA y define_bool CONFIG_PERCPU_IRQ y - define_int CONFIG_CACHE_LINE_SHIFT 7 - bool ' Enable DISCONTIGMEM support' CONFIG_DISCONTIGMEM - bool ' Enable NUMA support' CONFIG_NUMA + tristate ' PCIBA support' CONFIG_PCIBA fi define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /proc/kcore. bool 'SMP support' CONFIG_SMP +tristate 'Support running of Linux/x86 binaries' CONFIG_IA32_SUPPORT bool 'Performance monitor support' CONFIG_PERFMON tristate '/proc/pal support' CONFIG_IA64_PALINFO tristate '/proc/efi/vars support' CONFIG_EFI_VARS @@ -270,19 +256,23 @@ mainmenu_option next_comment comment 'Kernel hacking' -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Kernel support for IA-32 emulation' CONFIG_IA32_SUPPORT - tristate 'Kernel FP software completion' CONFIG_MATHEMU -else - define_bool CONFIG_MATHEMU y +choice 'Physical memory granularity' \ + "16MB CONFIG_IA64_GRANULE_16MB \ + 64MB CONFIG_IA64_GRANULE_64MB" 64MB + +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL +if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then + bool ' Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS + bool ' Disable VHPT' CONFIG_DISABLE_VHPT + bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ + +# early printk is currently broken for SMP: the secondary processors get stuck... +# bool ' Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK + + bool ' Debug memory allocations' CONFIG_DEBUG_SLAB + bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK + bool ' Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG + bool ' Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ fi - -bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ -bool 'Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK -bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG -bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ -bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS -bool 'Disable VHPT' CONFIG_DISABLE_VHPT endmenu diff -u --recursive --new-file v2.4.14/linux/arch/ia64/defconfig linux/arch/ia64/defconfig --- v2.4.14/linux/arch/ia64/defconfig Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/defconfig Fri Nov 9 14:26:17 2001 @@ -3,47 +3,125 @@ # # +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +# CONFIG_KMOD is not set + +# # General setup # CONFIG_IA64=y # CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set # CONFIG_SBUS is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_ACPI=y +CONFIG_ACPI_EFI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_ITANIUM=y +# CONFIG_MCKINLEY is not set # CONFIG_IA64_GENERIC is not set -CONFIG_IA64_HP_SIM=y -# CONFIG_IA64_SGI_SN1_SIM is not set -# CONFIG_IA64_DIG is not set +CONFIG_IA64_DIG=y +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_SGI_SN1 is not set +# CONFIG_IA64_SGI_SN2 is not set # CONFIG_IA64_PAGE_SIZE_4KB is not set # CONFIG_IA64_PAGE_SIZE_8KB is not set CONFIG_IA64_PAGE_SIZE_16KB=y # CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_IA64_BRL_EMU=y +# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set +CONFIG_IA64_L1_CACHE_SHIFT=6 +CONFIG_IA64_MCA=y +CONFIG_PM=y CONFIG_KCORE_ELF=y -# CONFIG_SMP is not set -# CONFIG_PERFMON is not set -# CONFIG_NET is not set -# CONFIG_SYSVIPC is not set +CONFIG_SMP=y +CONFIG_IA32_SUPPORT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_NET=y +CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set -# CONFIG_BINFMT_ELF is not set +CONFIG_SYSCTL=y +CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_BUSMGR is not set +# CONFIG_ACPI_SYS is not set +# CONFIG_ACPI_CPU is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_EC is not set +# CONFIG_ACPI_CMBATT is not set +# CONFIG_ACPI_THERMAL is not set CONFIG_PCI=y CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set # -# Code maturity level options +# Parallel port support # -CONFIG_EXPERIMENTAL=y +# CONFIG_PARPORT is not set # -# Loadable module support +# Networking options # -# CONFIG_MODULES is not set +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set # -# Parallel port support +# QoS and/or fair queueing # -# CONFIG_PARPORT is not set +# CONFIG_NET_SCHED is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set # # Plug and Play configuration @@ -58,14 +136,12 @@ # CONFIG_BLK_DEV_XD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set - -# -# Additional Block Devices -# -# CONFIG_BLK_DEV_LOOP is not set -# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set # # I2O device support @@ -73,10 +149,23 @@ # CONFIG_I2O is not set # CONFIG_I2O_PCI is not set # CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set # CONFIG_I2O_SCSI is not set # CONFIG_I2O_PROC is not set # +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# # ATA/IDE/MFM/RLL support # CONFIG_IDE=y @@ -92,12 +181,21 @@ # CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +CONFIG_BLK_DEV_IDESCSI=y # # IDE chipset support/bugfixes @@ -109,45 +207,208 @@ CONFIG_BLK_DEV_IDEPCI=y CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_OFFBOARD is not set -CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_PCI_AUTO is not set CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -# CONFIG_BLK_DEV_AEC6210 is not set -# CONFIG_AEC6210_TUNING is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_AEC62XX_TUNING is not set # CONFIG_BLK_DEV_ALI15X3 is not set # CONFIG_WDC_ALI15X3 is not set -# CONFIG_BLK_DEV_AMD7409 is not set -# CONFIG_AMD7409_OVERRIDE is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set # CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set CONFIG_BLK_DEV_PIIX=y -CONFIG_PIIX_TUNING=y +# CONFIG_PIIX_TUNING is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set +# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_IDE_CHIPSETS is not set -CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set # # SCSI support # -# CONFIG_SCSI is not set +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_DEBUG_QUEUES=y +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=y +# CONFIG_SCSI_QLOGIC_QLA2100 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +CONFIG_EEPRO100=y +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set # # Amateur Radio support @@ -165,13 +426,28 @@ # CONFIG_CD_NO_IDESCSI is not set # +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# # Character devices # -# CONFIG_VT is not set -# CONFIG_SERIAL is not set +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_ACPI is not set # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 # # I2C support @@ -182,26 +458,55 @@ # Mice # # CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +CONFIG_INPUT_SERIO=y +CONFIG_INPUT_SERPORT=y # # Joysticks # -# CONFIG_JOYSTICK is not set +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set # CONFIG_QIC02_TAPE is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set CONFIG_EFI_RTC=y - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -210,69 +515,366 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set -# CONFIG_AGP is not set +CONFIG_AGP=y +# CONFIG_AGP_INTEL is not set +CONFIG_AGP_I460=y +# CONFIG_AGP_I810 is not set +# CONFIG_AGP_VIA is not set +# CONFIG_AGP_AMD is not set +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_ALI is not set +# CONFIG_AGP_SWORKS is not set +CONFIG_DRM=y +# CONFIG_DRM_NEW is not set +CONFIG_DRM_OLD=y +CONFIG_DRM40_TDFX=y +# CONFIG_DRM40_GAMMA is not set +# CONFIG_DRM40_R128 is not set +# CONFIG_DRM40_RADEON is not set +# CONFIG_DRM40_I810 is not set +# CONFIG_DRM40_MGA is not set # -# USB support +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux # -# CONFIG_USB is not set +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_MIROPCM20_RDS is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set # # File systems # # CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS_FS=y # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set -# CONFIG_ISO9660_FS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set -# CONFIG_PROC_FS is not set +CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS is not set +CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set -# CONFIG_EXT2_FS is not set +CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types # -# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set CONFIG_MSDOS_PARTITION=y -# CONFIG_NLS is not set -# CONFIG_NLS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_EFI_PARTITION=y +# CONFIG_DEVFS_GUID is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y + +# +# Frame-buffer support +# +# CONFIG_FB is not set # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +CONFIG_SOUND_CS4281=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Controllers +# +CONFIG_USB_UHCI=m +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDDEV=y +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set # # Kernel hacking # -# CONFIG_IA32_SUPPORT is not set -# CONFIG_MATHEMU is not set -# CONFIG_MAGIC_SYSRQ is not set -# CONFIG_IA64_EARLY_PRINTK is not set +# CONFIG_IA64_GRANULE_16MB is not set +CONFIG_IA64_GRANULE_64MB=y +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set # CONFIG_IA64_DEBUG_CMPXCHG is not set # CONFIG_IA64_DEBUG_IRQ is not set -# CONFIG_IA64_PRINT_HAZARDS is not set -# CONFIG_KDB is not set diff -u --recursive --new-file v2.4.14/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c --- v2.4.14/linux/arch/ia64/ia32/binfmt_elf32.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/ia32/binfmt_elf32.c Fri Nov 9 14:26:17 2001 @@ -3,10 +3,11 @@ * * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> * Copyright (C) 2001 Hewlett-Packard Co - * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> * * 06/16/00 A. Mallick initialize csd/ssd/tssd/cflg for ia32_load_state * 04/13/01 D. Mosberger dropped saving tssd in ar.k1---it's not needed + * 09/14/01 D. Mosberger fixed memory management for gdt/tss page */ #include <linux/config.h> @@ -41,65 +42,59 @@ extern void ia64_elf32_init (struct pt_regs *regs); extern void put_dirty_page (struct task_struct * tsk, struct page *page, unsigned long address); +static void elf32_set_personality (void); + #define ELF_PLAT_INIT(_r) ia64_elf32_init(_r) #define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm) -#define elf_map elf_map32 +#define elf_map elf32_map +#define SET_PERSONALITY(ex, ibcs2) elf32_set_personality() /* Ugly but avoids duplication */ #include "../../../fs/binfmt_elf.c" -/* Global descriptor table */ -unsigned long *ia32_gdt_table, *ia32_tss; +extern struct page *ia32_shared_page[]; +extern unsigned long *ia32_gdt; struct page * -put_shared_page (struct task_struct * tsk, struct page *page, unsigned long address) +ia32_install_shared_page (struct vm_area_struct *vma, unsigned long address, int no_share) { - pgd_t * pgd; - pmd_t * pmd; - pte_t * pte; - - if (page_count(page) != 1) - printk("mem_map disagrees with %p at %08lx\n", (void *) page, address); + struct page *pg = ia32_shared_page[(address - vma->vm_start)/PAGE_SIZE]; - pgd = pgd_offset(tsk->mm, address); - - spin_lock(&tsk->mm->page_table_lock); - { - pmd = pmd_alloc(tsk->mm, pgd, address); - if (!pmd) - goto out; - pte = pte_alloc(tsk->mm, pmd, address); - if (!pte) - goto out; - if (!pte_none(*pte)) - goto out; - flush_page_to_ram(page); - set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_SHARED))); - } - spin_unlock(&tsk->mm->page_table_lock); - /* no need for flush_tlb */ - return page; - - out: - spin_unlock(&tsk->mm->page_table_lock); - __free_page(page); - return 0; + get_page(pg); + return pg; } +static struct vm_operations_struct ia32_shared_page_vm_ops = { + nopage: ia32_install_shared_page +}; + void ia64_elf32_init (struct pt_regs *regs) { struct vm_area_struct *vma; - int nr; /* * Map GDT and TSS below 4GB, where the processor can find them. We need to map * it with privilege level 3 because the IVE uses non-privileged accesses to these * tables. IA-32 segmentation is used to protect against IA-32 accesses to them. */ - put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_GDT_OFFSET); - if (PAGE_SHIFT <= IA32_PAGE_SHIFT) - put_shared_page(current, virt_to_page(ia32_tss), IA32_TSS_OFFSET); + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + vma->vm_mm = current->mm; + vma->vm_start = IA32_GDT_OFFSET; + vma->vm_end = vma->vm_start + max(PAGE_SIZE, 2*IA32_PAGE_SIZE); + vma->vm_page_prot = PAGE_SHARED; + vma->vm_flags = VM_READ|VM_MAYREAD; + vma->vm_ops = &ia32_shared_page_vm_ops; + vma->vm_pgoff = 0; + vma->vm_file = NULL; + vma->vm_private_data = NULL; + down_write(¤t->mm->mmap_sem); + { + insert_vm_struct(current->mm, vma); + } + up_write(¤t->mm->mmap_sem); + } /* * Install LDT as anonymous memory. This gives us all-zero segment descriptors @@ -116,34 +111,13 @@ vma->vm_pgoff = 0; vma->vm_file = NULL; vma->vm_private_data = NULL; - insert_vm_struct(current->mm, vma); + down_write(¤t->mm->mmap_sem); + { + insert_vm_struct(current->mm, vma); + } + up_write(¤t->mm->mmap_sem); } - nr = smp_processor_id(); - - current->thread.map_base = IA32_PAGE_OFFSET/3; - current->thread.task_size = IA32_PAGE_OFFSET; /* use what Linux/x86 uses... */ - set_fs(USER_DS); /* set addr limit for new TASK_SIZE */ - - /* Setup the segment selectors */ - regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */ - regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */ - - /* Setup the segment descriptors */ - regs->r24 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]); /* ESD */ - regs->r27 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]); /* DSD */ - regs->r28 = 0; /* FSD (null) */ - regs->r29 = 0; /* GSD (null) */ - regs->r30 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_LDT(nr)]); /* LDTD */ - - /* - * Setup GDTD. Note: GDTD is the descrambled version of the pseudo-descriptor - * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32 - * architecture manual. - */ - regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0, - 0, 0, 0, 0, 0, 0)); - ia64_psr(regs)->ac = 0; /* turn off alignment checking */ regs->loadrs = 0; /* @@ -164,10 +138,19 @@ current->thread.fcr = IA32_FCR_DEFAULT; current->thread.fir = 0; current->thread.fdr = 0; - current->thread.csd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_CS >> 3]); - current->thread.ssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]); - current->thread.tssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_TSS(nr)]); + /* + * Setup GDTD. Note: GDTD is the descrambled version of the pseudo-descriptor + * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32 + * architecture manual. + */ + regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0, + 0, 0, 0, 0, 0, 0)); + /* Setup the segment selectors */ + regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */ + regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */ + + ia32_load_segment_descriptors(current); ia32_load_state(current); } @@ -189,6 +172,7 @@ if (!mpnt) return -ENOMEM; + down_write(¤t->mm->mmap_sem); { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; @@ -204,54 +188,32 @@ } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { - if (bprm->page[i]) { - put_dirty_page(current,bprm->page[i],stack_base); + struct page *page = bprm->page[i]; + if (page) { + bprm->page[i] = NULL; + put_dirty_page(current, page, stack_base); } stack_base += PAGE_SIZE; } + up_write(¤t->mm->mmap_sem); return 0; } -static unsigned long -ia32_mm_addr (unsigned long addr) +static void +elf32_set_personality (void) { - struct vm_area_struct *vma; - - if ((vma = find_vma(current->mm, addr)) == NULL) - return ELF_PAGESTART(addr); - if (vma->vm_start > addr) - return ELF_PAGESTART(addr); - return ELF_PAGEALIGN(addr); + set_personality(PER_LINUX32); + current->thread.map_base = IA32_PAGE_OFFSET/3; + current->thread.task_size = IA32_PAGE_OFFSET; /* use what Linux/x86 uses... */ + set_fs(USER_DS); /* set addr limit for new TASK_SIZE */ } -/* - * Normally we would do an `mmap' to map in the process's text section. - * This doesn't work with IA32 processes as the ELF file might specify - * a non page size aligned address. Instead we will just allocate - * memory and read the data in from the file. Slightly less efficient - * but it works. - */ -extern long ia32_do_mmap (struct file *filep, unsigned int len, unsigned int prot, - unsigned int flags, unsigned int fd, unsigned int offset); - static unsigned long -elf_map32 (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) +elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type) { - unsigned long retval; + unsigned long pgoff = (eppnt->p_vaddr) & ~IA32_PAGE_MASK; - if (eppnt->p_memsz >= (1UL<<32) || addr > (1UL<<32) - eppnt->p_memsz) - return -EINVAL; - - /* - * Make sure the elf interpreter doesn't get loaded at location 0 - * so that NULL pointers correctly cause segfaults. - */ - if (addr == 0) - addr += PAGE_SIZE; - set_brk(ia32_mm_addr(addr), addr + eppnt->p_memsz); - memset((char *) addr + eppnt->p_filesz, 0, eppnt->p_memsz - eppnt->p_filesz); - kernel_read(filep, eppnt->p_offset, (char *) addr, eppnt->p_filesz); - retval = (unsigned long) addr; - return retval; + return ia32_do_mmap(filep, (addr & IA32_PAGE_MASK), eppnt->p_filesz + pgoff, prot, type, + eppnt->p_offset - pgoff); } diff -u --recursive --new-file v2.4.14/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S --- v2.4.14/linux/arch/ia64/ia32/ia32_entry.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/ia32/ia32_entry.S Fri Nov 9 14:26:17 2001 @@ -2,7 +2,7 @@ #include <asm/offsets.h> #include <asm/signal.h> -#include "../kernel/entry.h" +#include "../kernel/minstate.h" /* * execve() is special because in case of success, we need to @@ -14,13 +14,13 @@ alloc loc1=ar.pfs,3,2,4,0 mov loc0=rp .body - mov out0=in0 // filename + zxt4 out0=in0 // filename ;; // stop bit between alloc and call - mov out1=in1 // argv - mov out2=in2 // envp + zxt4 out1=in1 // argv + zxt4 out2=in2 // envp add out3=16,sp // regs br.call.sptk.few rp=sys32_execve -1: cmp4.ge p6,p0=r8,r0 +1: cmp.ge p6,p0=r8,r0 mov ar.pfs=loc1 // restore ar.pfs ;; (p6) mov ar.pfs=r0 // clear ar.pfs in case of success @@ -29,31 +29,80 @@ br.ret.sptk.few rp END(ia32_execve) - // - // Get possibly unaligned sigmask argument into an aligned - // kernel buffer -GLOBAL_ENTRY(ia32_rt_sigsuspend) - // We'll cheat and not do an alloc here since we are ultimately - // going to do a simple branch to the IA64 sys_rt_sigsuspend. - // r32 is still the first argument which is the signal mask. - // We copy this 4-byte aligned value to an 8-byte aligned buffer - // in the task structure and then jump to the IA64 code. +ENTRY(ia32_clone) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2) + alloc r16=ar.pfs,2,2,4,0 + DO_SAVE_SWITCH_STACK + mov loc0=rp + mov loc1=r16 // save ar.pfs across do_fork + .body + zxt4 out1=in1 // newsp + mov out3=0 // stacksize + adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s + zxt4 out0=in0 // out0 = clone_flags + br.call.sptk.many rp=do_fork +.ret0: .restore sp + adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack + mov ar.pfs=loc1 + mov rp=loc0 + br.ret.sptk.many rp +END(ia32_clone) - EX(.Lfail, ld4 r2=[r32],4) // load low part of sigmask - ;; - EX(.Lfail, ld4 r3=[r32]) // load high part of sigmask - adds r32=IA64_TASK_THREAD_SIGMASK_OFFSET,r13 - ;; - st8 [r32]=r2 - adds r10=IA64_TASK_THREAD_SIGMASK_OFFSET+4,r13 +ENTRY(sys32_rt_sigsuspend) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs + mov loc0=rp + mov out0=in0 // mask + mov out1=in1 // sigsetsize + mov out2=sp // out2 = &sigscratch + .fframe 16 + adds sp=-16,sp // allocate dummy "sigscratch" ;; + .body + br.call.sptk.many rp=ia32_rt_sigsuspend +1: .restore sp + adds sp=16,sp + mov rp=loc0 + mov ar.pfs=loc1 + br.ret.sptk.many rp +END(sys32_rt_sigsuspend) - st4 [r10]=r3 - br.cond.sptk.many sys_rt_sigsuspend - -.Lfail: br.ret.sptk.many rp // failed to read sigmask -END(ia32_rt_sigsuspend) +ENTRY(sys32_sigsuspend) + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs + mov loc0=rp + mov out0=in2 // mask (first two args are ignored) + ;; + mov out1=sp // out1 = &sigscratch + .fframe 16 + adds sp=-16,sp // allocate dummy "sigscratch" + .body + br.call.sptk.many rp=ia32_sigsuspend +1: .restore sp + adds sp=16,sp + mov rp=loc0 + mov ar.pfs=loc1 + br.ret.sptk.many rp +END(sys32_sigsuspend) +GLOBAL_ENTRY(ia32_ret_from_clone) + PT_REGS_UNWIND_INFO(0) + /* + * We need to call schedule_tail() to complete the scheduling process. + * Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the + * address of the previously executing task. + */ + br.call.sptk.many rp=ia64_invoke_schedule_tail +.ret1: adds r2=IA64_TASK_PTRACE_OFFSET,r13 + ;; + ld8 r2=[r2] + ;; + mov r8=0 + tbit.nz p6,p0=r2,PT_TRACESYS_BIT +(p6) br.cond.spnt .ia32_strace_check_retval + ;; // prevent RAW on r8 +END(ia32_ret_from_clone) + // fall thrugh GLOBAL_ENTRY(ia32_ret_from_syscall) PT_REGS_UNWIND_INFO(0) @@ -72,20 +121,25 @@ // manipulate ar.pfs. // // Input: - // r15 = syscall number - // b6 = syscall entry point + // r8 = syscall number + // b6 = syscall entry point // GLOBAL_ENTRY(ia32_trace_syscall) PT_REGS_UNWIND_INFO(0) + mov r3=-38 + adds r2=IA64_PT_REGS_R8_OFFSET+16,sp + ;; + st8 [r2]=r3 // initialize return code to -ENOSYS br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args -.ret0: br.call.sptk.few rp=b6 // do the syscall -.ret1: cmp.lt p6,p0=r8,r0 // syscall failed? +.ret2: br.call.sptk.few rp=b6 // do the syscall +.ia32_strace_check_retval: + cmp.lt p6,p0=r8,r0 // syscall failed? adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 ;; st8.spill [r2]=r8 // store return value in slot for r8 br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value -.ret2: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame - br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel! +.ret4: alloc r2=ar.pfs,0,0,0,0 // drop the syscall argument frame + br.cond.sptk.many ia64_leave_kernel END(ia32_trace_syscall) GLOBAL_ENTRY(sys32_vfork) @@ -110,7 +164,7 @@ mov out3=0 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s br.call.sptk.few rp=do_fork -.ret3: mov ar.pfs=loc1 +.ret5: mov ar.pfs=loc1 .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov rp=loc0 @@ -137,21 +191,21 @@ data8 sys32_time data8 sys_mknod data8 sys_chmod /* 15 */ - data8 sys_lchown + data8 sys_lchown /* 16-bit version */ data8 sys32_ni_syscall /* old break syscall holder */ data8 sys32_ni_syscall data8 sys32_lseek data8 sys_getpid /* 20 */ data8 sys_mount data8 sys_oldumount - data8 sys_setuid - data8 sys_getuid + data8 sys_setuid /* 16-bit version */ + data8 sys_getuid /* 16-bit version */ data8 sys32_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ data8 sys32_ptrace data8 sys32_alarm data8 sys32_ni_syscall - data8 sys_pause - data8 ia32_utime /* 30 */ + data8 sys32_pause + data8 sys32_utime /* 30 */ data8 sys32_ni_syscall /* old stty syscall holder */ data8 sys32_ni_syscall /* old gtty syscall holder */ data8 sys_access @@ -167,15 +221,15 @@ data8 sys32_times data8 sys32_ni_syscall /* old prof syscall holder */ data8 sys_brk /* 45 */ - data8 sys_setgid - data8 sys_getgid + data8 sys_setgid /* 16-bit version */ + data8 sys_getgid /* 16-bit version */ data8 sys32_signal - data8 sys_geteuid - data8 sys_getegid /* 50 */ + data8 sys_geteuid /* 16-bit version */ + data8 sys_getegid /* 16-bit version */ /* 50 */ data8 sys_acct data8 sys_umount /* recycled never used phys( */ data8 sys32_ni_syscall /* old lock syscall holder */ - data8 ia32_ioctl + data8 sys32_ioctl data8 sys32_fcntl /* 55 */ data8 sys32_ni_syscall /* old mpx syscall holder */ data8 sys_setpgid @@ -191,19 +245,19 @@ data8 sys32_sigaction data8 sys32_ni_syscall data8 sys32_ni_syscall - data8 sys_setreuid /* 70 */ - data8 sys_setregid - data8 sys32_ni_syscall - data8 sys_sigpending + data8 sys_setreuid /* 16-bit version */ /* 70 */ + data8 sys_setregid /* 16-bit version */ + data8 sys32_sigsuspend + data8 sys32_sigpending data8 sys_sethostname data8 sys32_setrlimit /* 75 */ - data8 sys32_getrlimit + data8 sys32_old_getrlimit data8 sys32_getrusage data8 sys32_gettimeofday data8 sys32_settimeofday - data8 sys_getgroups /* 80 */ - data8 sys_setgroups - data8 old_select + data8 sys32_getgroups16 /* 80 */ + data8 sys32_setgroups16 + data8 sys32_old_select data8 sys_symlink data8 sys32_ni_syscall data8 sys_readlink /* 85 */ @@ -212,17 +266,17 @@ data8 sys_reboot data8 sys32_readdir data8 sys32_mmap /* 90 */ - data8 sys_munmap + data8 sys32_munmap data8 sys_truncate data8 sys_ftruncate data8 sys_fchmod - data8 sys_fchown /* 95 */ + data8 sys_fchown /* 16-bit version */ /* 95 */ data8 sys_getpriority data8 sys_setpriority data8 sys32_ni_syscall /* old profil syscall holder */ data8 sys32_statfs data8 sys32_fstatfs /* 100 */ - data8 sys_ioperm + data8 sys32_ioperm data8 sys32_socketcall data8 sys_syslog data8 sys32_setitimer @@ -231,36 +285,36 @@ data8 sys32_newlstat data8 sys32_newfstat data8 sys32_ni_syscall - data8 sys_iopl /* 110 */ + data8 sys32_iopl /* 110 */ data8 sys_vhangup data8 sys32_ni_syscall /* used to be sys_idle */ data8 sys32_ni_syscall data8 sys32_wait4 data8 sys_swapoff /* 115 */ - data8 sys_sysinfo + data8 sys32_sysinfo data8 sys32_ipc data8 sys_fsync data8 sys32_sigreturn - data8 sys_clone /* 120 */ + data8 ia32_clone /* 120 */ data8 sys_setdomainname data8 sys32_newuname data8 sys32_modify_ldt - data8 sys_adjtimex + data8 sys32_ni_syscall /* adjtimex */ data8 sys32_mprotect /* 125 */ - data8 sys_sigprocmask - data8 sys_create_module - data8 sys_init_module - data8 sys_delete_module - data8 sys_get_kernel_syms /* 130 */ - data8 sys_quotactl + data8 sys32_sigprocmask + data8 sys32_ni_syscall /* create_module */ + data8 sys32_ni_syscall /* init_module */ + data8 sys32_ni_syscall /* delete_module */ + data8 sys32_ni_syscall /* get_kernel_syms */ /* 130 */ + data8 sys32_quotactl data8 sys_getpgid data8 sys_fchdir - data8 sys_bdflush - data8 sys_sysfs /* 135 */ - data8 sys_personality + data8 sys32_ni_syscall /* sys_bdflush */ + data8 sys_sysfs /* 135 */ + data8 sys32_personality data8 sys32_ni_syscall /* for afs_syscall */ - data8 sys_setfsuid - data8 sys_setfsgid + data8 sys_setfsuid /* 16-bit version */ + data8 sys_setfsgid /* 16-bit version */ data8 sys_llseek /* 140 */ data8 sys32_getdents data8 sys32_select @@ -282,66 +336,73 @@ data8 sys_sched_yield data8 sys_sched_get_priority_max data8 sys_sched_get_priority_min /* 160 */ - data8 sys_sched_rr_get_interval + data8 sys32_sched_rr_get_interval data8 sys32_nanosleep data8 sys_mremap - data8 sys_setresuid - data8 sys32_getresuid /* 165 */ - data8 sys_vm86 - data8 sys_query_module + data8 sys_setresuid /* 16-bit version */ + data8 sys32_getresuid16 /* 16-bit version */ /* 165 */ + data8 sys32_ni_syscall /* vm86 */ + data8 sys32_ni_syscall /* sys_query_module */ data8 sys_poll - data8 sys_nfsservctl + data8 sys32_ni_syscall /* nfsservctl */ data8 sys_setresgid /* 170 */ - data8 sys32_getresgid + data8 sys32_getresgid16 data8 sys_prctl data8 sys32_rt_sigreturn data8 sys32_rt_sigaction data8 sys32_rt_sigprocmask /* 175 */ data8 sys_rt_sigpending - data8 sys_rt_sigtimedwait - data8 sys_rt_sigqueueinfo - data8 ia32_rt_sigsuspend - data8 sys_pread /* 180 */ - data8 sys_pwrite - data8 sys_chown + data8 sys32_rt_sigtimedwait + data8 sys32_rt_sigqueueinfo + data8 sys32_rt_sigsuspend + data8 sys32_pread /* 180 */ + data8 sys32_pwrite + data8 sys_chown /* 16-bit version */ data8 sys_getcwd data8 sys_capget data8 sys_capset /* 185 */ data8 sys32_sigaltstack - data8 sys_sendfile + data8 sys32_sendfile data8 sys32_ni_syscall /* streams1 */ data8 sys32_ni_syscall /* streams2 */ data8 sys32_vfork /* 190 */ + data8 sys32_getrlimit + data8 sys32_mmap2 + data8 sys32_truncate64 + data8 sys32_ftruncate64 + data8 sys32_stat64 /* 195 */ + data8 sys32_lstat64 + data8 sys32_fstat64 + data8 sys_lchown + data8 sys_getuid + data8 sys_getgid /* 200 */ + data8 sys_geteuid + data8 sys_getegid + data8 sys_setreuid + data8 sys_setregid + data8 sys_getgroups /* 205 */ + data8 sys_setgroups + data8 sys_fchown + data8 sys_setresuid + data8 sys_getresuid + data8 sys_setresgid /* 210 */ + data8 sys_getresgid + data8 sys_chown + data8 sys_setuid + data8 sys_setgid + data8 sys_setfsuid /* 215 */ + data8 sys_setfsgid + data8 sys_pivot_root + data8 sys_mincore + data8 sys_madvise + data8 sys_getdents64 /* 220 */ + data8 sys32_fcntl64 + data8 sys_ni_syscall /* reserved for TUX */ + data8 sys_ni_syscall /* reserved for Security */ + data8 sys_gettid + data8 sys_readahead /* 225 */ data8 sys_ni_syscall data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 195 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 200 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 205 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 210 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 215 */ - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall - data8 sys_ni_syscall /* 220 */ data8 sys_ni_syscall data8 sys_ni_syscall /* diff -u --recursive --new-file v2.4.14/linux/arch/ia64/ia32/ia32_ioctl.c linux/arch/ia64/ia32/ia32_ioctl.c --- v2.4.14/linux/arch/ia64/ia32/ia32_ioctl.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/ia32/ia32_ioctl.c Fri Nov 9 14:26:17 2001 @@ -3,6 +3,8 @@ * * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> + * Copyright (C) 2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/types.h> @@ -22,8 +24,12 @@ #include <linux/if_ppp.h> #include <linux/ixjuser.h> #include <linux/i2o-dev.h> + +#include <asm/ia32.h> + #include <../drivers/char/drm/drm.h> + #define IOCTL_NR(a) ((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) #define DO_IOCTL(fd, cmd, arg) ({ \ @@ -36,179 +42,200 @@ _ret; \ }) -#define P(i) ((void *)(long)(i)) - +#define P(i) ((void *)(unsigned long)(i)) asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); -asmlinkage long ia32_ioctl(unsigned int fd, unsigned int cmd, unsigned int arg) +static long +put_dirent32 (struct dirent *d, struct linux32_dirent *d32) +{ + size_t namelen = strlen(d->d_name); + + return (put_user(d->d_ino, &d32->d_ino) + || put_user(d->d_off, &d32->d_off) + || put_user(d->d_reclen, &d32->d_reclen) + || copy_to_user(d32->d_name, d->d_name, namelen + 1)); +} + +asmlinkage long +sys32_ioctl (unsigned int fd, unsigned int cmd, unsigned int arg) { long ret; switch (IOCTL_NR(cmd)) { - - case IOCTL_NR(DRM_IOCTL_VERSION): - { - drm_version_t ver; - struct { - int version_major; - int version_minor; - int version_patchlevel; - unsigned int name_len; - unsigned int name; /* pointer */ - unsigned int date_len; - unsigned int date; /* pointer */ - unsigned int desc_len; - unsigned int desc; /* pointer */ - } ver32; - - if (copy_from_user(&ver32, P(arg), sizeof(ver32))) - return -EFAULT; - ver.name_len = ver32.name_len; - ver.name = P(ver32.name); - ver.date_len = ver32.date_len; - ver.date = P(ver32.date); - ver.desc_len = ver32.desc_len; - ver.desc = P(ver32.desc); - ret = DO_IOCTL(fd, cmd, &ver); - if (ret >= 0) { - ver32.version_major = ver.version_major; - ver32.version_minor = ver.version_minor; - ver32.version_patchlevel = ver.version_patchlevel; - ver32.name_len = ver.name_len; - ver32.date_len = ver.date_len; - ver32.desc_len = ver.desc_len; - if (copy_to_user(P(arg), &ver32, sizeof(ver32))) - return -EFAULT; - } - return(ret); - } - - case IOCTL_NR(DRM_IOCTL_GET_UNIQUE): - { - drm_unique_t un; - struct { - unsigned int unique_len; - unsigned int unique; - } un32; - - if (copy_from_user(&un32, P(arg), sizeof(un32))) - return -EFAULT; - un.unique_len = un32.unique_len; - un.unique = P(un32.unique); - ret = DO_IOCTL(fd, cmd, &un); - if (ret >= 0) { - un32.unique_len = un.unique_len; - if (copy_to_user(P(arg), &un32, sizeof(un32))) - return -EFAULT; - } - return(ret); - } - case IOCTL_NR(DRM_IOCTL_SET_UNIQUE): - case IOCTL_NR(DRM_IOCTL_ADD_MAP): - case IOCTL_NR(DRM_IOCTL_ADD_BUFS): - case IOCTL_NR(DRM_IOCTL_MARK_BUFS): - case IOCTL_NR(DRM_IOCTL_INFO_BUFS): - case IOCTL_NR(DRM_IOCTL_MAP_BUFS): - case IOCTL_NR(DRM_IOCTL_FREE_BUFS): - case IOCTL_NR(DRM_IOCTL_ADD_CTX): - case IOCTL_NR(DRM_IOCTL_RM_CTX): - case IOCTL_NR(DRM_IOCTL_MOD_CTX): - case IOCTL_NR(DRM_IOCTL_GET_CTX): - case IOCTL_NR(DRM_IOCTL_SWITCH_CTX): - case IOCTL_NR(DRM_IOCTL_NEW_CTX): - case IOCTL_NR(DRM_IOCTL_RES_CTX): - - case IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE): - case IOCTL_NR(DRM_IOCTL_AGP_RELEASE): - case IOCTL_NR(DRM_IOCTL_AGP_ENABLE): - case IOCTL_NR(DRM_IOCTL_AGP_INFO): - case IOCTL_NR(DRM_IOCTL_AGP_ALLOC): - case IOCTL_NR(DRM_IOCTL_AGP_FREE): - case IOCTL_NR(DRM_IOCTL_AGP_BIND): - case IOCTL_NR(DRM_IOCTL_AGP_UNBIND): - - /* Mga specific ioctls */ - - case IOCTL_NR(DRM_IOCTL_MGA_INIT): - - /* I810 specific ioctls */ - - case IOCTL_NR(DRM_IOCTL_I810_GETBUF): - case IOCTL_NR(DRM_IOCTL_I810_COPY): - - /* Rage 128 specific ioctls */ - - case IOCTL_NR(DRM_IOCTL_R128_PACKET): - - case IOCTL_NR(VFAT_IOCTL_READDIR_BOTH): - case IOCTL_NR(VFAT_IOCTL_READDIR_SHORT): - case IOCTL_NR(MTIOCGET): - case IOCTL_NR(MTIOCPOS): - case IOCTL_NR(MTIOCGETCONFIG): - case IOCTL_NR(MTIOCSETCONFIG): - case IOCTL_NR(PPPIOCSCOMPRESS): - case IOCTL_NR(PPPIOCGIDLE): - case IOCTL_NR(NCP_IOC_GET_FS_INFO_V2): - case IOCTL_NR(NCP_IOC_GETOBJECTNAME): - case IOCTL_NR(NCP_IOC_SETOBJECTNAME): - case IOCTL_NR(NCP_IOC_GETPRIVATEDATA): - case IOCTL_NR(NCP_IOC_SETPRIVATEDATA): - case IOCTL_NR(NCP_IOC_GETMOUNTUID2): - case IOCTL_NR(CAPI_MANUFACTURER_CMD): - case IOCTL_NR(VIDIOCGTUNER): - case IOCTL_NR(VIDIOCSTUNER): - case IOCTL_NR(VIDIOCGWIN): - case IOCTL_NR(VIDIOCSWIN): - case IOCTL_NR(VIDIOCGFBUF): - case IOCTL_NR(VIDIOCSFBUF): - case IOCTL_NR(MGSL_IOCSPARAMS): - case IOCTL_NR(MGSL_IOCGPARAMS): - case IOCTL_NR(ATM_GETNAMES): - case IOCTL_NR(ATM_GETLINKRATE): - case IOCTL_NR(ATM_GETTYPE): - case IOCTL_NR(ATM_GETESI): - case IOCTL_NR(ATM_GETADDR): - case IOCTL_NR(ATM_RSTADDR): - case IOCTL_NR(ATM_ADDADDR): - case IOCTL_NR(ATM_DELADDR): - case IOCTL_NR(ATM_GETCIRANGE): - case IOCTL_NR(ATM_SETCIRANGE): - case IOCTL_NR(ATM_SETESI): - case IOCTL_NR(ATM_SETESIF): - case IOCTL_NR(ATM_GETSTAT): - case IOCTL_NR(ATM_GETSTATZ): - case IOCTL_NR(ATM_GETLOOP): - case IOCTL_NR(ATM_SETLOOP): - case IOCTL_NR(ATM_QUERYLOOP): - case IOCTL_NR(ENI_SETMULT): - case IOCTL_NR(NS_GETPSTAT): - /* case IOCTL_NR(NS_SETBUFLEV): This is a duplicate case with ZATM_GETPOOLZ */ - case IOCTL_NR(ZATM_GETPOOLZ): - case IOCTL_NR(ZATM_GETPOOL): - case IOCTL_NR(ZATM_SETPOOL): - case IOCTL_NR(ZATM_GETTHIST): - case IOCTL_NR(IDT77105_GETSTAT): - case IOCTL_NR(IDT77105_GETSTATZ): - case IOCTL_NR(IXJCTL_TONE_CADENCE): - case IOCTL_NR(IXJCTL_FRAMES_READ): - case IOCTL_NR(IXJCTL_FRAMES_WRITTEN): - case IOCTL_NR(IXJCTL_READ_WAIT): - case IOCTL_NR(IXJCTL_WRITE_WAIT): - case IOCTL_NR(IXJCTL_DRYBUFFER_READ): - case IOCTL_NR(I2OHRTGET): - case IOCTL_NR(I2OLCTGET): - case IOCTL_NR(I2OPARMSET): - case IOCTL_NR(I2OPARMGET): - case IOCTL_NR(I2OSWDL): - case IOCTL_NR(I2OSWUL): - case IOCTL_NR(I2OSWDEL): - case IOCTL_NR(I2OHTML): + case IOCTL_NR(VFAT_IOCTL_READDIR_SHORT): + case IOCTL_NR(VFAT_IOCTL_READDIR_BOTH): { + struct linux32_dirent *d32 = P(arg); + struct dirent d[2]; + + ret = DO_IOCTL(fd, _IOR('r', _IOC_NR(cmd), + struct dirent [2]), + (unsigned long) d); + if (ret < 0) + return ret; + + if (put_dirent32(d, d32) || put_dirent32(d + 1, d32 + 1)) + return -EFAULT; + + return ret; + } + + case IOCTL_NR(DRM_IOCTL_VERSION): + { + drm_version_t ver; + struct { + int version_major; + int version_minor; + int version_patchlevel; + unsigned int name_len; + unsigned int name; /* pointer */ + unsigned int date_len; + unsigned int date; /* pointer */ + unsigned int desc_len; + unsigned int desc; /* pointer */ + } ver32; + + if (copy_from_user(&ver32, P(arg), sizeof(ver32))) + return -EFAULT; + ver.name_len = ver32.name_len; + ver.name = P(ver32.name); + ver.date_len = ver32.date_len; + ver.date = P(ver32.date); + ver.desc_len = ver32.desc_len; + ver.desc = P(ver32.desc); + ret = DO_IOCTL(fd, DRM_IOCTL_VERSION, &ver); + if (ret >= 0) { + ver32.version_major = ver.version_major; + ver32.version_minor = ver.version_minor; + ver32.version_patchlevel = ver.version_patchlevel; + ver32.name_len = ver.name_len; + ver32.date_len = ver.date_len; + ver32.desc_len = ver.desc_len; + if (copy_to_user(P(arg), &ver32, sizeof(ver32))) + return -EFAULT; + } + return ret; + } + + case IOCTL_NR(DRM_IOCTL_GET_UNIQUE): + { + drm_unique_t un; + struct { + unsigned int unique_len; + unsigned int unique; + } un32; + + if (copy_from_user(&un32, P(arg), sizeof(un32))) + return -EFAULT; + un.unique_len = un32.unique_len; + un.unique = P(un32.unique); + ret = DO_IOCTL(fd, DRM_IOCTL_GET_UNIQUE, &un); + if (ret >= 0) { + un32.unique_len = un.unique_len; + if (copy_to_user(P(arg), &un32, sizeof(un32))) + return -EFAULT; + } + return ret; + } + case IOCTL_NR(DRM_IOCTL_SET_UNIQUE): + case IOCTL_NR(DRM_IOCTL_ADD_MAP): + case IOCTL_NR(DRM_IOCTL_ADD_BUFS): + case IOCTL_NR(DRM_IOCTL_MARK_BUFS): + case IOCTL_NR(DRM_IOCTL_INFO_BUFS): + case IOCTL_NR(DRM_IOCTL_MAP_BUFS): + case IOCTL_NR(DRM_IOCTL_FREE_BUFS): + case IOCTL_NR(DRM_IOCTL_ADD_CTX): + case IOCTL_NR(DRM_IOCTL_RM_CTX): + case IOCTL_NR(DRM_IOCTL_MOD_CTX): + case IOCTL_NR(DRM_IOCTL_GET_CTX): + case IOCTL_NR(DRM_IOCTL_SWITCH_CTX): + case IOCTL_NR(DRM_IOCTL_NEW_CTX): + case IOCTL_NR(DRM_IOCTL_RES_CTX): + + case IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE): + case IOCTL_NR(DRM_IOCTL_AGP_RELEASE): + case IOCTL_NR(DRM_IOCTL_AGP_ENABLE): + case IOCTL_NR(DRM_IOCTL_AGP_INFO): + case IOCTL_NR(DRM_IOCTL_AGP_ALLOC): + case IOCTL_NR(DRM_IOCTL_AGP_FREE): + case IOCTL_NR(DRM_IOCTL_AGP_BIND): + case IOCTL_NR(DRM_IOCTL_AGP_UNBIND): + + /* Mga specific ioctls */ + + case IOCTL_NR(DRM_IOCTL_MGA_INIT): + + /* I810 specific ioctls */ + + case IOCTL_NR(DRM_IOCTL_I810_GETBUF): + case IOCTL_NR(DRM_IOCTL_I810_COPY): + + case IOCTL_NR(MTIOCGET): + case IOCTL_NR(MTIOCPOS): + case IOCTL_NR(MTIOCGETCONFIG): + case IOCTL_NR(MTIOCSETCONFIG): + case IOCTL_NR(PPPIOCSCOMPRESS): + case IOCTL_NR(PPPIOCGIDLE): + case IOCTL_NR(NCP_IOC_GET_FS_INFO_V2): + case IOCTL_NR(NCP_IOC_GETOBJECTNAME): + case IOCTL_NR(NCP_IOC_SETOBJECTNAME): + case IOCTL_NR(NCP_IOC_GETPRIVATEDATA): + case IOCTL_NR(NCP_IOC_SETPRIVATEDATA): + case IOCTL_NR(NCP_IOC_GETMOUNTUID2): + case IOCTL_NR(CAPI_MANUFACTURER_CMD): + case IOCTL_NR(VIDIOCGTUNER): + case IOCTL_NR(VIDIOCSTUNER): + case IOCTL_NR(VIDIOCGWIN): + case IOCTL_NR(VIDIOCSWIN): + case IOCTL_NR(VIDIOCGFBUF): + case IOCTL_NR(VIDIOCSFBUF): + case IOCTL_NR(MGSL_IOCSPARAMS): + case IOCTL_NR(MGSL_IOCGPARAMS): + case IOCTL_NR(ATM_GETNAMES): + case IOCTL_NR(ATM_GETLINKRATE): + case IOCTL_NR(ATM_GETTYPE): + case IOCTL_NR(ATM_GETESI): + case IOCTL_NR(ATM_GETADDR): + case IOCTL_NR(ATM_RSTADDR): + case IOCTL_NR(ATM_ADDADDR): + case IOCTL_NR(ATM_DELADDR): + case IOCTL_NR(ATM_GETCIRANGE): + case IOCTL_NR(ATM_SETCIRANGE): + case IOCTL_NR(ATM_SETESI): + case IOCTL_NR(ATM_SETESIF): + case IOCTL_NR(ATM_GETSTAT): + case IOCTL_NR(ATM_GETSTATZ): + case IOCTL_NR(ATM_GETLOOP): + case IOCTL_NR(ATM_SETLOOP): + case IOCTL_NR(ATM_QUERYLOOP): + case IOCTL_NR(ENI_SETMULT): + case IOCTL_NR(NS_GETPSTAT): + /* case IOCTL_NR(NS_SETBUFLEV): This is a duplicate case with ZATM_GETPOOLZ */ + case IOCTL_NR(ZATM_GETPOOLZ): + case IOCTL_NR(ZATM_GETPOOL): + case IOCTL_NR(ZATM_SETPOOL): + case IOCTL_NR(ZATM_GETTHIST): + case IOCTL_NR(IDT77105_GETSTAT): + case IOCTL_NR(IDT77105_GETSTATZ): + case IOCTL_NR(IXJCTL_TONE_CADENCE): + case IOCTL_NR(IXJCTL_FRAMES_READ): + case IOCTL_NR(IXJCTL_FRAMES_WRITTEN): + case IOCTL_NR(IXJCTL_READ_WAIT): + case IOCTL_NR(IXJCTL_WRITE_WAIT): + case IOCTL_NR(IXJCTL_DRYBUFFER_READ): + case IOCTL_NR(I2OHRTGET): + case IOCTL_NR(I2OLCTGET): + case IOCTL_NR(I2OPARMSET): + case IOCTL_NR(I2OPARMGET): + case IOCTL_NR(I2OSWDL): + case IOCTL_NR(I2OSWUL): + case IOCTL_NR(I2OSWDEL): + case IOCTL_NR(I2OHTML): break; - default: - return(sys_ioctl(fd, cmd, (unsigned long)arg)); + default: + return sys_ioctl(fd, cmd, (unsigned long)arg); } printk("%x:unimplemented IA32 ioctl system call\n", cmd); - return(-EINVAL); + return -EINVAL; } diff -u --recursive --new-file v2.4.14/linux/arch/ia64/ia32/ia32_ldt.c linux/arch/ia64/ia32/ia32_ldt.c --- v2.4.14/linux/arch/ia64/ia32/ia32_ldt.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/ia32/ia32_ldt.c Fri Nov 9 14:26:17 2001 @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Hewlett-Packard Co - * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> * * Adapted from arch/i386/kernel/ldt.c */ @@ -16,6 +16,8 @@ #include <asm/uaccess.h> #include <asm/ia32.h> +#define P(p) ((void *) (unsigned long) (p)) + /* * read_ldt() is not really atomic - this is not a problem since synchronization of reads * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic, @@ -58,10 +60,30 @@ } static int +read_default_ldt (void * ptr, unsigned long bytecount) +{ + unsigned long size; + int err; + + /* XXX fix me: should return equivalent of default_ldt[0] */ + err = 0; + size = 8; + if (size > bytecount) + size = bytecount; + + err = size; + if (clear_user(ptr, size)) + err = -EFAULT; + + return err; +} + +static int write_ldt (void * ptr, unsigned long bytecount, int oldmode) { struct ia32_modify_ldt_ldt_s ldt_info; __u64 entry; + int ret; if (bytecount != sizeof(ldt_info)) return -EINVAL; @@ -97,23 +119,28 @@ * memory, but we still need to guard against out-of-memory, hence we must use * put_user(). */ - return __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number); + ret = __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number); + ia32_load_segment_descriptors(current); + return ret; } asmlinkage int -sys32_modify_ldt (int func, void *ptr, unsigned int bytecount) +sys32_modify_ldt (int func, unsigned int ptr, unsigned int bytecount) { int ret = -ENOSYS; switch (func) { case 0: - ret = read_ldt(ptr, bytecount); + ret = read_ldt(P(ptr), bytecount); break; case 1: - ret = write_ldt(ptr, bytecount, 1); + ret = write_ldt(P(ptr), bytecount, 1); + break; + case 2: + ret = read_default_ldt(P(ptr), bytecount); break; case 0x11: - ret = write_ldt(ptr, bytecount, 0); + ret = write_ldt(P(ptr), bytecount, 0); break; } return ret; diff -u --recursive --new-file v2.4.14/linux/arch/ia64/ia32/ia32_signal.c linux/arch/ia64/ia32/ia32_signal.c --- v2.4.14/linux/arch/ia64/ia32/ia32_signal.c Mon Oct 9 17:54:53 2000 +++ linux/arch/ia64/ia32/ia32_signal.c Fri Nov 9 14:26:17 2001 @@ -1,8 +1,8 @@ /* * IA32 Architecture-specific signal handling support. * - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1999, 2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> @@ -13,6 +13,7 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/mm.h> +#include <linux/personality.h> #include <linux/ptrace.h> #include <linux/sched.h> #include <linux/signal.h> @@ -28,9 +29,15 @@ #include <asm/segment.h> #include <asm/ia32.h> +#include "../kernel/sigframe.h" + +#define A(__x) ((unsigned long)(__x)) + #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +#define __IA32_NR_sigreturn 119 +#define __IA32_NR_rt_sigreturn 173 struct sigframe_ia32 { @@ -54,12 +61,51 @@ char retcode[8]; }; -static int +int +copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from) +{ + unsigned long tmp; + int err; + + if (!access_ok(VERIFY_READ, from, sizeof(siginfo_t32))) + return -EFAULT; + + err = __get_user(to->si_signo, &from->si_signo); + err |= __get_user(to->si_errno, &from->si_errno); + err |= __get_user(to->si_code, &from->si_code); + + if (from->si_code < 0) + err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); + else { + switch (from->si_code >> 16) { + case __SI_CHLD >> 16: + err |= __get_user(to->si_utime, &from->si_utime); + err |= __get_user(to->si_stime, &from->si_stime); + err |= __get_user(to->si_status, &from->si_status); + default: + err |= __get_user(to->si_pid, &from->si_pid); + err |= __get_user(to->si_uid, &from->si_uid); + break; + case __SI_FAULT >> 16: + err |= __get_user(tmp, &from->si_addr); + to->si_addr = (void *) tmp; + break; + case __SI_POLL >> 16: + err |= __get_user(to->si_band, &from->si_band); + err |= __get_user(to->si_fd, &from->si_fd); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + } + return err; +} + +int copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from) { int err; - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32))) + if (!access_ok(VERIFY_WRITE, to, sizeof(siginfo_t32))) return -EFAULT; /* If you change siginfo_t structure, please be sure @@ -97,110 +143,329 @@ return err; } +static inline void +sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer) +{ + if (handler + 1 <= 2) + /* SIG_DFL, SIG_IGN, or SIG_ERR: must sign-extend to 64-bits */ + sa->sa.sa_handler = (__sighandler_t) A((int) handler); + else + sa->sa.sa_handler = (__sighandler_t) (((unsigned long) restorer << 32) | handler); +} +asmlinkage long +ia32_rt_sigsuspend (sigset32_t *uset, unsigned int sigsetsize, struct sigscratch *scr) +{ + extern long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall); + sigset_t oldset, set; -static int -setup_sigcontext_ia32(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, - struct pt_regs *regs, unsigned long mask) + scr->scratch_unat = 0; /* avoid leaking kernel bits to user level */ + memset(&set, 0, sizeof(&set)); + + if (sigsetsize > sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&set.sig, &uset->sig, sigsetsize)) + return -EFAULT; + + sigdelsetmask(&set, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + { + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); + } + spin_unlock_irq(¤t->sigmask_lock); + + /* + * The return below usually returns to the signal handler. We need to pre-set the + * correct error code here to ensure that the right values get saved in sigcontext + * by ia64_do_signal. + */ + scr->pt.r8 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (ia64_do_signal(&oldset, scr, 1)) + return -EINTR; + } +} + +asmlinkage long +ia32_sigsuspend (unsigned int mask, struct sigscratch *scr) +{ + return ia32_rt_sigsuspend((sigset32_t *)&mask, sizeof(mask), scr); +} + +asmlinkage long +sys32_signal (int sig, unsigned int handler) +{ + struct k_sigaction new_sa, old_sa; + int ret; + + sigact_set_handler(&new_sa, handler, 0); + new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; + + ret = do_sigaction(sig, &new_sa, &old_sa); + + return ret ? ret : IA32_SA_HANDLER(&old_sa); +} + +asmlinkage long +sys32_rt_sigaction (int sig, struct sigaction32 *act, + struct sigaction32 *oact, unsigned int sigsetsize) +{ + struct k_sigaction new_ka, old_ka; + unsigned int handler, restorer; + int ret; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset32_t)) + return -EINVAL; + + if (act) { + ret = get_user(handler, &act->sa_handler); + ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); + ret |= get_user(restorer, &act->sa_restorer); + ret |= copy_from_user(&new_ka.sa.sa_mask, &act->sa_mask, sizeof(sigset32_t)); + if (ret) + return -EFAULT; + + sigact_set_handler(&new_ka, handler, restorer); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler); + ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); + ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer); + ret |= copy_to_user(&oact->sa_mask, &old_ka.sa.sa_mask, sizeof(sigset32_t)); + } + return ret; +} + + +extern asmlinkage long sys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, + size_t sigsetsize); + +asmlinkage long +sys32_rt_sigprocmask (int how, sigset32_t *set, sigset32_t *oset, unsigned int sigsetsize) +{ + mm_segment_t old_fs = get_fs(); + sigset_t s; + long ret; + + if (sigsetsize > sizeof(s)) + return -EINVAL; + + if (set) { + memset(&s, 0, sizeof(s)); + if (copy_from_user(&s.sig, set, sigsetsize)) + return -EFAULT; + } + set_fs(KERNEL_DS); + ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sizeof(s)); + set_fs(old_fs); + if (ret) + return ret; + if (oset) { + if (copy_to_user(oset, &s.sig, sigsetsize)) + return -EFAULT; + } + return 0; +} + +asmlinkage long +sys32_sigprocmask (int how, unsigned int *set, unsigned int *oset) { - int err = 0; - unsigned long flag; + return sys32_rt_sigprocmask(how, (sigset32_t *) set, (sigset32_t *) oset, sizeof(*set)); +} - err |= __put_user((regs->r16 >> 32) & 0xffff , (unsigned int *)&sc->fs); - err |= __put_user((regs->r16 >> 48) & 0xffff , (unsigned int *)&sc->gs); +asmlinkage long +sys32_rt_sigtimedwait (sigset32_t *uthese, siginfo_t32 *uinfo, struct timespec32 *uts, + unsigned int sigsetsize) +{ + extern asmlinkage long sys_rt_sigtimedwait (const sigset_t *, siginfo_t *, + const struct timespec *, size_t); + extern int copy_siginfo_to_user32 (siginfo_t32 *, siginfo_t *); + mm_segment_t old_fs = get_fs(); + struct timespec t; + siginfo_t info; + sigset_t s; + int ret; - err |= __put_user((regs->r16 >> 56) & 0xffff, (unsigned int *)&sc->es); - err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds); - err |= __put_user(regs->r15, &sc->edi); - err |= __put_user(regs->r14, &sc->esi); - err |= __put_user(regs->r13, &sc->ebp); - err |= __put_user(regs->r12, &sc->esp); - err |= __put_user(regs->r11, &sc->ebx); - err |= __put_user(regs->r10, &sc->edx); - err |= __put_user(regs->r9, &sc->ecx); - err |= __put_user(regs->r8, &sc->eax); + if (copy_from_user(&s.sig, uthese, sizeof(sigset32_t))) + return -EFAULT; + if (uts) { + ret = get_user(t.tv_sec, &uts->tv_sec); + ret |= get_user(t.tv_nsec, &uts->tv_nsec); + if (ret) + return -EFAULT; + } + set_fs(KERNEL_DS); + ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); + set_fs(old_fs); + if (ret >= 0 && uinfo) { + if (copy_siginfo_to_user32(uinfo, &info)) + return -EFAULT; + } + return ret; +} + +asmlinkage long +sys32_rt_sigqueueinfo (int pid, int sig, siginfo_t32 *uinfo) +{ + extern asmlinkage long sys_rt_sigqueueinfo (int, int, siginfo_t *); + extern int copy_siginfo_from_user32 (siginfo_t *to, siginfo_t32 *from); + mm_segment_t old_fs = get_fs(); + siginfo_t info; + int ret; + + if (copy_siginfo_from_user32(&info, uinfo)) + return -EFAULT; + set_fs(KERNEL_DS); + ret = sys_rt_sigqueueinfo(pid, sig, &info); + set_fs(old_fs); + return ret; +} + +asmlinkage long +sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) +{ + struct k_sigaction new_ka, old_ka; + unsigned int handler, restorer; + int ret; + + if (act) { + old_sigset32_t mask; + + ret = get_user(handler, &act->sa_handler); + ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); + ret |= get_user(restorer, &act->sa_restorer); + ret |= get_user(mask, &act->sa_mask); + if (ret) + return ret; + + sigact_set_handler(&new_ka, handler, restorer); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + ret = put_user(IA32_SA_HANDLER(&old_ka), &oact->sa_handler); + ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); + ret |= put_user(IA32_SA_RESTORER(&old_ka), &oact->sa_restorer); + ret |= put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +static int +setup_sigcontext_ia32 (struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, + struct pt_regs *regs, unsigned long mask) +{ + int err = 0; + unsigned long flag; + + err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs); + err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs); + err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es); + err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds); + err |= __put_user(regs->r15, &sc->edi); + err |= __put_user(regs->r14, &sc->esi); + err |= __put_user(regs->r13, &sc->ebp); + err |= __put_user(regs->r12, &sc->esp); + err |= __put_user(regs->r11, &sc->ebx); + err |= __put_user(regs->r10, &sc->edx); + err |= __put_user(regs->r9, &sc->ecx); + err |= __put_user(regs->r8, &sc->eax); #if 0 - err |= __put_user(current->tss.trap_no, &sc->trapno); - err |= __put_user(current->tss.error_code, &sc->err); + err |= __put_user(current->tss.trap_no, &sc->trapno); + err |= __put_user(current->tss.error_code, &sc->err); #endif - err |= __put_user(regs->cr_iip, &sc->eip); - err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs); - /* - * `eflags' is in an ar register for this context - */ - asm volatile ("mov %0=ar.eflag ;;" : "=r"(flag)); - err |= __put_user((unsigned int)flag, &sc->eflags); - - err |= __put_user(regs->r12, &sc->esp_at_signal); - err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss); + err |= __put_user(regs->cr_iip, &sc->eip); + err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs); + /* + * `eflags' is in an ar register for this context + */ + asm volatile ("mov %0=ar.eflag ;;" : "=r"(flag)); + err |= __put_user((unsigned int)flag, &sc->eflags); + err |= __put_user(regs->r12, &sc->esp_at_signal); + err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss); #if 0 - tmp = save_i387(fpstate); - if (tmp < 0) - err = 1; - else - err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); + tmp = save_i387(fpstate); + if (tmp < 0) + err = 1; + else + err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); - /* non-iBCS2 extensions.. */ + /* non-iBCS2 extensions.. */ #endif - err |= __put_user(mask, &sc->oldmask); + err |= __put_user(mask, &sc->oldmask); #if 0 - err |= __put_user(current->tss.cr2, &sc->cr2); + err |= __put_user(current->tss.cr2, &sc->cr2); #endif - - return err; + return err; } static int -restore_sigcontext_ia32(struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax) +restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax) { - unsigned int err = 0; + unsigned int err = 0; + +#define COPY(ia64x, ia32x) err |= __get_user(regs->ia64x, &sc->ia32x) -#define COPY(ia64x, ia32x) err |= __get_user(regs->ia64x, &sc->ia32x) +#define copyseg_gs(tmp) (regs->r16 |= (unsigned long) tmp << 48) +#define copyseg_fs(tmp) (regs->r16 |= (unsigned long) tmp << 32) +#define copyseg_cs(tmp) (regs->r17 |= tmp) +#define copyseg_ss(tmp) (regs->r17 |= (unsigned long) tmp << 16) +#define copyseg_es(tmp) (regs->r16 |= (unsigned long) tmp << 16) +#define copyseg_ds(tmp) (regs->r16 |= tmp) + +#define COPY_SEG(seg) \ + { \ + unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ + copyseg_##seg(tmp); \ + } +#define COPY_SEG_STRICT(seg) \ + { \ + unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ + copyseg_##seg(tmp|3); \ + } -#define copyseg_gs(tmp) (regs->r16 |= (unsigned long) tmp << 48) -#define copyseg_fs(tmp) (regs->r16 |= (unsigned long) tmp << 32) -#define copyseg_cs(tmp) (regs->r17 |= tmp) -#define copyseg_ss(tmp) (regs->r17 |= (unsigned long) tmp << 16) -#define copyseg_es(tmp) (regs->r16 |= (unsigned long) tmp << 16) -#define copyseg_ds(tmp) (regs->r16 |= tmp) - -#define COPY_SEG(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ - copyseg_##seg(tmp); } - -#define COPY_SEG_STRICT(seg) \ - { unsigned short tmp; \ - err |= __get_user(tmp, &sc->seg); \ - copyseg_##seg(tmp|3); } - - /* To make COPY_SEGs easier, we zero r16, r17 */ - regs->r16 = 0; - regs->r17 = 0; - - COPY_SEG(gs); - COPY_SEG(fs); - COPY_SEG(es); - COPY_SEG(ds); - COPY(r15, edi); - COPY(r14, esi); - COPY(r13, ebp); - COPY(r12, esp); - COPY(r11, ebx); - COPY(r10, edx); - COPY(r9, ecx); - COPY(cr_iip, eip); - COPY_SEG_STRICT(cs); - COPY_SEG_STRICT(ss); - { + /* To make COPY_SEGs easier, we zero r16, r17 */ + regs->r16 = 0; + regs->r17 = 0; + + COPY_SEG(gs); + COPY_SEG(fs); + COPY_SEG(es); + COPY_SEG(ds); + COPY(r15, edi); + COPY(r14, esi); + COPY(r13, ebp); + COPY(r12, esp); + COPY(r11, ebx); + COPY(r10, edx); + COPY(r9, ecx); + COPY(cr_iip, eip); + COPY_SEG_STRICT(cs); + COPY_SEG_STRICT(ss); + ia32_load_segment_descriptors(current); + { unsigned int tmpflags; unsigned long flag; /* - * IA32 `eflags' is not part of `pt_regs', it's - * in an ar register which is part of the thread - * context. Fortunately, we are executing in the + * IA32 `eflags' is not part of `pt_regs', it's in an ar register which + * is part of the thread context. Fortunately, we are executing in the * IA32 process's context. */ err |= __get_user(tmpflags, &sc->eflags); @@ -210,186 +475,191 @@ asm volatile ("mov ar.eflag=%0 ;;" :: "r"(flag)); regs->r1 = -1; /* disable syscall checks, r1 is orig_eax */ - } + } #if 0 - { - struct _fpstate * buf; - err |= __get_user(buf, &sc->fpstate); - if (buf) { - if (verify_area(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_i387(buf); - } - } + { + struct _fpstate * buf; + err |= __get_user(buf, &sc->fpstate); + if (buf) { + if (verify_area(VERIFY_READ, buf, sizeof(*buf))) + goto badframe; + err |= restore_i387(buf); + } + } #endif - err |= __get_user(*peax, &sc->eax); - return err; + err |= __get_user(*peax, &sc->eax); + return err; -#if 0 -badframe: - return 1; +#if 0 + badframe: + return 1; #endif - } /* * Determine which stack to use.. */ static inline void * -get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) +get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { - unsigned long esp; - unsigned int xss; + unsigned long esp; - /* Default to using normal stack */ - esp = regs->r12; - xss = regs->r16 >> 16; - - /* This is the X/Open sanctioned signal stack switching. */ - if (ka->sa.sa_flags & SA_ONSTACK) { - if (! on_sig_stack(esp)) - esp = current->sas_ss_sp + current->sas_ss_size; - } - /* Legacy stack switching not supported */ - - return (void *)((esp - frame_size) & -8ul); + /* Default to using normal stack (truncate off sign-extension of bit 31: */ + esp = (unsigned int) regs->r12; + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (!on_sig_stack(esp)) + esp = current->sas_ss_sp + current->sas_ss_size; + } + /* Legacy stack switching not supported */ + + return (void *)((esp - frame_size) & -8ul); } static int -setup_frame_ia32(int sig, struct k_sigaction *ka, sigset_t *set, - struct pt_regs * regs) -{ - struct sigframe_ia32 *frame; - int err = 0; - - frame = get_sigframe(ka, regs, sizeof(*frame)); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; - - err |= __put_user((current->exec_domain - && current->exec_domain->signal_invmap - && sig < 32 - ? (int)(current->exec_domain->signal_invmap[sig]) - : sig), - &frame->sig); - - err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]); - - if (_IA32_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); - } - - /* Set up to return from userspace. If provided, use a stub - already in userspace. */ - err |= __put_user((long)frame->retcode, &frame->pretcode); - /* This is popl %eax ; movl $,%eax ; int $0x80 */ - err |= __put_user(0xb858, (short *)(frame->retcode+0)); -#define __IA32_NR_sigreturn 119 - err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2)); - err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4)); - err |= __put_user(0x80cd, (short *)(frame->retcode+6)); - - if (err) - goto give_sigsegv; - - /* Set up registers for signal handler */ - regs->r12 = (unsigned long) frame; - regs->cr_iip = (unsigned long) ka->sa.sa_handler; - - set_fs(USER_DS); - regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ - regs->r17 = (__USER_DS << 16) | __USER_CS; +setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) +{ + struct sigframe_ia32 *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + err |= __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? (int)(current->exec_domain->signal_invmap[sig]) + : sig), + &frame->sig); + + err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]); + + if (_IA32_NSIG_WORDS > 1) + err |= __copy_to_user(frame->extramask, (char *) &set->sig + 4, + sizeof(frame->extramask)); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + unsigned int restorer = IA32_SA_RESTORER(ka); + err |= __put_user(restorer, &frame->pretcode); + } else { + err |= __put_user((long)frame->retcode, &frame->pretcode); + /* This is popl %eax ; movl $,%eax ; int $0x80 */ + err |= __put_user(0xb858, (short *)(frame->retcode+0)); + err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2)); + err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4)); + err |= __put_user(0x80cd, (short *)(frame->retcode+6)); + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + regs->r12 = (unsigned long) frame; + regs->cr_iip = IA32_SA_HANDLER(ka); + + set_fs(USER_DS); + regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ + regs->r17 = (__USER_DS << 16) | __USER_CS; #if 0 - regs->eflags &= ~TF_MASK; + regs->eflags &= ~TF_MASK; #endif #if 0 - printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n", + printk("SIG deliver (%s:%d): sig=%d sp=%p pc=%lx ra=%x\n", current->comm, current->pid, sig, (void *) frame, regs->cr_iip, frame->pretcode); #endif - return 1; + return 1; -give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); - return 0; + give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); + return 0; } static int -setup_rt_frame_ia32(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs * regs) +setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs * regs) { - struct rt_sigframe_ia32 *frame; - int err = 0; + struct rt_sigframe_ia32 *frame; + int err = 0; - frame = get_sigframe(ka, regs, sizeof(*frame)); + frame = get_sigframe(ka, regs, sizeof(*frame)); - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; - - err |= __put_user((current->exec_domain - && current->exec_domain->signal_invmap - && sig < 32 - ? current->exec_domain->signal_invmap[sig] - : sig), - &frame->sig); - err |= __put_user((long)&frame->info, &frame->pinfo); - err |= __put_user((long)&frame->uc, &frame->puc); - err |= copy_siginfo_to_user32(&frame->info, info); - - /* Create the ucontext. */ - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(regs->r12), - &frame->uc.uc_stack.ss_flags); - err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate, - regs, set->sig[0]); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - - err |= __put_user((long)frame->retcode, &frame->pretcode); - /* This is movl $,%eax ; int $0x80 */ - err |= __put_user(0xb8, (char *)(frame->retcode+0)); -#define __IA32_NR_rt_sigreturn 173 - err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1)); - err |= __put_user(0x80cd, (short *)(frame->retcode+5)); + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + err |= __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + err |= __put_user((long)&frame->info, &frame->pinfo); + err |= __put_user((long)&frame->uc, &frame->puc); + err |= copy_siginfo_to_user32(&frame->info, info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->r12), &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate, regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + if (err) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + unsigned int restorer = IA32_SA_RESTORER(ka); + err |= __put_user(restorer, &frame->pretcode); + } else { + err |= __put_user((long)frame->retcode, &frame->pretcode); + /* This is movl $,%eax ; int $0x80 */ + err |= __put_user(0xb8, (char *)(frame->retcode+0)); + err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1)); + err |= __put_user(0x80cd, (short *)(frame->retcode+5)); + } - if (err) - goto give_sigsegv; + if (err) + goto give_sigsegv; - /* Set up registers for signal handler */ - regs->r12 = (unsigned long) frame; - regs->cr_iip = (unsigned long) ka->sa.sa_handler; + /* Set up registers for signal handler */ + regs->r12 = (unsigned long) frame; + regs->cr_iip = IA32_SA_HANDLER(ka); - set_fs(USER_DS); + set_fs(USER_DS); - regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ - regs->r17 = (__USER_DS << 16) | __USER_CS; + regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ + regs->r17 = (__USER_DS << 16) | __USER_CS; #if 0 - regs->eflags &= ~TF_MASK; + regs->eflags &= ~TF_MASK; #endif #if 0 - printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n", + printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n", current->comm, current->pid, (void *) frame, regs->cr_iip, frame->pretcode); #endif - return 1; + return 1; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); - return 0; + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); + return 0; } int @@ -398,95 +668,78 @@ { /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) - return(setup_rt_frame_ia32(sig, ka, info, set, regs)); + return setup_rt_frame_ia32(sig, ka, info, set, regs); else - return(setup_frame_ia32(sig, ka, set, regs)); + return setup_frame_ia32(sig, ka, set, regs); } -asmlinkage int -sys32_sigreturn( -int arg0, -int arg1, -int arg2, -int arg3, -int arg4, -int arg5, -int arg6, -int arg7, -unsigned long stack) -{ - struct pt_regs *regs = (struct pt_regs *) &stack; - struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(regs->r12- 8); - sigset_t set; - int eax; - - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - - if (__get_user(set.sig[0], &frame->sc.oldmask) - || (_IA32_NSIG_WORDS > 1 - && __copy_from_user((((char *) &set.sig) + 4), - &frame->extramask, - sizeof(frame->extramask)))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); - current->blocked = (sigset_t) set; - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - - if (restore_sigcontext_ia32(regs, &frame->sc, &eax)) - goto badframe; - return eax; - -badframe: - force_sig(SIGSEGV, current); - return 0; -} - -asmlinkage int -sys32_rt_sigreturn( -int arg0, -int arg1, -int arg2, -int arg3, -int arg4, -int arg5, -int arg6, -int arg7, -unsigned long stack) -{ - struct pt_regs *regs = (struct pt_regs *) &stack; - struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(regs->r12 - 4); - sigset_t set; - stack_t st; - int eax; - - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); - current->blocked = set; - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - - if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax)) - goto badframe; - - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) - goto badframe; - /* It is more difficult to avoid calling this function than to - call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs->r12); - - return eax; - -badframe: - force_sig(SIGSEGV, current); - return 0; -} +asmlinkage long +sys32_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, + unsigned long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + unsigned long esp = (unsigned int) regs->r12; + struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(esp - 8); + sigset_t set; + int eax; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_IA32_NSIG_WORDS > 1 && __copy_from_user((char *) &set.sig + 4, &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = (sigset_t) set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext_ia32(regs, &frame->sc, &eax)) + goto badframe; + return eax; + + badframe: + force_sig(SIGSEGV, current); + return 0; +} +asmlinkage long +sys32_rt_sigreturn (int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, + unsigned long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + unsigned long esp = (unsigned int) regs->r12; + struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(esp - 4); + sigset_t set; + stack_t st; + int eax; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax)) + goto badframe; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, esp); + + return eax; + + badframe: + force_sig(SIGSEGV, current); + return 0; +} diff -u --recursive --new-file v2.4.14/linux/arch/ia64/ia32/ia32_support.c linux/arch/ia64/ia32/ia32_support.c --- v2.4.14/linux/arch/ia64/ia32/ia32_support.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/ia32/ia32_support.c Fri Nov 9 14:26:17 2001 @@ -4,15 +4,18 @@ * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com> * Copyright (C) 2001 Hewlett-Packard Co - * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> * * 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context * 02/19/01 D. Mosberger dropped tssd; it's not needed + * 09/14/01 D. Mosberger fixed memory management for gdt/tss page + * 09/29/01 D. Mosberger added ia32_load_segment_descriptors() */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/mm.h> +#include <linux/personality.h> #include <linux/sched.h> #include <asm/page.h> @@ -21,10 +24,46 @@ #include <asm/processor.h> #include <asm/ia32.h> -extern unsigned long *ia32_gdt_table, *ia32_tss; - extern void die_if_kernel (char *str, struct pt_regs *regs, long err); +struct exec_domain ia32_exec_domain; +struct page *ia32_shared_page[(2*IA32_PAGE_SIZE + PAGE_SIZE - 1)/PAGE_SIZE]; +unsigned long *ia32_gdt; + +static unsigned long +load_desc (u16 selector) +{ + unsigned long *table, limit, index; + + if (!selector) + return 0; + if (selector & IA32_SEGSEL_TI) { + table = (unsigned long *) IA32_LDT_OFFSET; + limit = IA32_LDT_ENTRIES; + } else { + table = ia32_gdt; + limit = IA32_PAGE_SIZE / sizeof(ia32_gdt[0]); + } + index = selector >> IA32_SEGSEL_INDEX_SHIFT; + if (index >= limit) + return 0; + return IA32_SEG_UNSCRAMBLE(table[index]); +} + +void +ia32_load_segment_descriptors (struct task_struct *task) +{ + struct pt_regs *regs = ia64_task_regs(task); + + /* Setup the segment descriptors */ + regs->r24 = load_desc(regs->r16 >> 16); /* ESD */ + regs->r27 = load_desc(regs->r16 >> 0); /* DSD */ + regs->r28 = load_desc(regs->r16 >> 32); /* FSD */ + regs->r29 = load_desc(regs->r16 >> 48); /* GSD */ + task->thread.csd = load_desc(regs->r17 >> 0); /* CSD */ + task->thread.ssd = load_desc(regs->r17 >> 16); /* SSD */ +} + void ia32_save_state (struct task_struct *t) { @@ -46,14 +85,17 @@ t->thread.csd = csd; t->thread.ssd = ssd; ia64_set_kr(IA64_KR_IO_BASE, t->thread.old_iob); + ia64_set_kr(IA64_KR_TSSD, t->thread.old_k1); } void ia32_load_state (struct task_struct *t) { - unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd; + unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd; struct pt_regs *regs = ia64_task_regs(t); - int nr; + int nr = smp_processor_id(); /* LDT and TSS depend on CPU number: */ + + nr = smp_processor_id(); eflag = t->thread.eflag; fsr = t->thread.fsr; @@ -62,6 +104,7 @@ fdr = t->thread.fdr; csd = t->thread.csd; ssd = t->thread.ssd; + tssd = load_desc(_TSS(nr)); /* TSSD */ asm volatile ("mov ar.eflag=%0;" "mov ar.fsr=%1;" @@ -72,11 +115,12 @@ "mov ar.ssd=%6;" :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd)); current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE); + current->thread.old_k1 = ia64_get_kr(IA64_KR_TSSD); ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE); + ia64_set_kr(IA64_KR_TSSD, tssd); - /* load TSS and LDT while preserving SS and CS: */ - nr = smp_processor_id(); regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32) | (__u32) regs->r17; + regs->r30 = load_desc(_LDT(nr)); /* LDTD */ } /* @@ -85,36 +129,34 @@ void ia32_gdt_init (void) { - unsigned long gdt_and_tss_page, ldt_size; + unsigned long *tss; + unsigned long ldt_size; int nr; - /* allocate two IA-32 pages of memory: */ - gdt_and_tss_page = __get_free_pages(GFP_KERNEL, - (IA32_PAGE_SHIFT < PAGE_SHIFT) - ? 0 : (IA32_PAGE_SHIFT + 1) - PAGE_SHIFT); - ia32_gdt_table = (unsigned long *) gdt_and_tss_page; - ia32_tss = (unsigned long *) (gdt_and_tss_page + IA32_PAGE_SIZE); - - /* Zero the gdt and tss */ - memset((void *) gdt_and_tss_page, 0, 2*IA32_PAGE_SIZE); + ia32_shared_page[0] = alloc_page(GFP_KERNEL); + ia32_gdt = page_address(ia32_shared_page[0]); + tss = ia32_gdt + IA32_PAGE_SIZE/sizeof(ia32_gdt[0]); + + if (IA32_PAGE_SIZE == PAGE_SIZE) { + ia32_shared_page[1] = alloc_page(GFP_KERNEL); + tss = page_address(ia32_shared_page[1]); + } /* CS descriptor in IA-32 (scrambled) format */ - ia32_gdt_table[__USER_CS >> 3] = - IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT, - 0xb, 1, 3, 1, 1, 1, 1); + ia32_gdt[__USER_CS >> 3] = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT, + 0xb, 1, 3, 1, 1, 1, 1); /* DS descriptor in IA-32 (scrambled) format */ - ia32_gdt_table[__USER_DS >> 3] = - IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT, - 0x3, 1, 3, 1, 1, 1, 1); + ia32_gdt[__USER_DS >> 3] = IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET-1) >> IA32_PAGE_SHIFT, + 0x3, 1, 3, 1, 1, 1, 1); /* We never change the TSS and LDT descriptors, so we can share them across all CPUs. */ ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); for (nr = 0; nr < NR_CPUS; ++nr) { - ia32_gdt_table[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235, - 0xb, 0, 3, 1, 1, 1, 0); - ia32_gdt_table[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1, - 0x2, 0, 3, 1, 1, 1, 0); + ia32_gdt[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235, + 0xb, 0, 3, 1, 1, 1, 0); + ia32_gdt[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1, + 0x2, 0, 3, 1, 1, 1, 0); } } @@ -133,3 +175,18 @@ siginfo.si_code = TRAP_BRKPT; force_sig_info(SIGTRAP, &siginfo, current); } + +static int __init +ia32_init (void) +{ + ia32_exec_domain.name = "Linux/x86"; + ia32_exec_domain.handler = NULL; + ia32_exec_domain.pers_low = PER_LINUX32; + ia32_exec_domain.pers_high = PER_LINUX32; + ia32_exec_domain.signal_map = default_exec_domain.signal_map; + ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap; + register_exec_domain(&ia32_exec_domain); + return 0; +} + +__initcall(ia32_init); diff -u --recursive --new-file v2.4.14/linux/arch/ia64/ia32/ia32_traps.c linux/arch/ia64/ia32/ia32_traps.c --- v2.4.14/linux/arch/ia64/ia32/ia32_traps.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/ia32/ia32_traps.c Fri Nov 9 14:26:17 2001 @@ -1,7 +1,12 @@ /* - * IA32 exceptions handler + * IA-32 exception handlers + * + * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com> + * Copyright (C) 2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> * * 06/16/00 A. Mallick added siginfo for most cases (close to IA32) + * 09/29/00 D. Mosberger added ia32_intercept() */ #include <linux/kernel.h> @@ -9,6 +14,26 @@ #include <asm/ia32.h> #include <asm/ptrace.h> + +int +ia32_intercept (struct pt_regs *regs, unsigned long isr) +{ + switch ((isr >> 16) & 0xff) { + case 0: /* Instruction intercept fault */ + case 3: /* Locked Data reference fault */ + case 1: /* Gate intercept trap */ + return -1; + + case 2: /* System flag trap */ + if (((isr >> 14) & 0x3) >= 2) { + /* MOV SS, POP SS instructions */ + ia64_psr(regs)->id = 1; + return 0; + } else + return -1; + } + return -1; +} int ia32_exception (struct pt_regs *regs, unsigned long isr) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.4.14/linux/arch/ia64/ia32/sys_ia32.c Mon Aug 27 12:41:39 2001 +++ linux/arch/ia64/ia32/sys_ia32.c Fri Nov 9 14:26:17 2001 @@ -1,14 +1,13 @@ /* - * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on - * sys_sparc32 + * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Derived from sys_sparc32.c. * * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 2000 Hewlett-Packard Co. - * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 2000-2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> * * These routines maintain argument size conversion between 32bit and 64bit * environment. @@ -53,31 +52,56 @@ #include <asm/types.h> #include <asm/uaccess.h> #include <asm/semaphore.h> -#include <asm/ipc.h> #include <net/scm.h> #include <net/sock.h> #include <asm/ia32.h> +#define DEBUG 0 + +#if DEBUG +# define DBG(fmt...) printk(KERN_DEBUG fmt) +#else +# define DBG(fmt...) +#endif + #define A(__x) ((unsigned long)(__x)) #define AA(__x) ((unsigned long)(__x)) #define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1))) #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define OFFSET4K(a) ((a) & 0xfff) +#define PAGE_START(addr) ((addr) & PAGE_MASK) +#define PAGE_OFF(addr) ((addr) & ~PAGE_MASK) + extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *); extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long); +extern asmlinkage long sys_munmap (unsigned long, size_t); +extern unsigned long arch_get_unmapped_area (struct file *, unsigned long, unsigned long, + unsigned long, unsigned long); + +/* forward declaration: */ +asmlinkage long sys32_mprotect (unsigned int, unsigned int, int); + +/* + * Anything that modifies or inspects ia32 user virtual memory must hold this semaphore + * while doing so. + */ +/* XXX make per-mm: */ +static DECLARE_MUTEX(ia32_mmap_sem); static int nargs (unsigned int arg, char **ap) { - int n, err, addr; + unsigned int addr; + int n, err; if (!arg) return 0; n = 0; do { - err = get_user(addr, (int *)A(arg)); + err = get_user(addr, (unsigned int *)A(arg)); if (err) return err; if (ap) @@ -94,7 +118,7 @@ int stack) { struct pt_regs *regs = (struct pt_regs *)&stack; - unsigned long old_map_base, old_task_size; + unsigned long old_map_base, old_task_size, tssd; char **av, **ae; int na, ne, len; long r; @@ -123,15 +147,20 @@ old_map_base = current->thread.map_base; old_task_size = current->thread.task_size; + tssd = ia64_get_kr(IA64_KR_TSSD); - /* we may be exec'ing a 64-bit process: reset map base & task-size: */ + /* we may be exec'ing a 64-bit process: reset map base, task-size, and io-base: */ current->thread.map_base = DEFAULT_MAP_BASE; current->thread.task_size = DEFAULT_TASK_SIZE; + ia64_set_kr(IA64_KR_IO_BASE, current->thread.old_iob); + ia64_set_kr(IA64_KR_TSSD, current->thread.old_k1); set_fs(KERNEL_DS); r = sys_execve(filename, av, ae, regs); if (r < 0) { - /* oops, execve failed, switch back to old map base & task-size: */ + /* oops, execve failed, switch back to old values... */ + ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE); + ia64_set_kr(IA64_KR_TSSD, tssd); current->thread.map_base = old_map_base; current->thread.task_size = old_task_size; set_fs(USER_DS); /* establish new task-size as the address-limit */ @@ -142,30 +171,33 @@ } static inline int -putstat(struct stat32 *ubuf, struct stat *kbuf) +putstat (struct stat32 *ubuf, struct stat *kbuf) { int err; - err = put_user (kbuf->st_dev, &ubuf->st_dev); - err |= __put_user (kbuf->st_ino, &ubuf->st_ino); - err |= __put_user (kbuf->st_mode, &ubuf->st_mode); - err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink); - err |= __put_user (kbuf->st_uid, &ubuf->st_uid); - err |= __put_user (kbuf->st_gid, &ubuf->st_gid); - err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev); - err |= __put_user (kbuf->st_size, &ubuf->st_size); - err |= __put_user (kbuf->st_atime, &ubuf->st_atime); - err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime); - err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime); - err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize); - err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks); + if (clear_user(ubuf, sizeof(*ubuf))) + return 1; + + err = __put_user(kbuf->st_dev, &ubuf->st_dev); + err |= __put_user(kbuf->st_ino, &ubuf->st_ino); + err |= __put_user(kbuf->st_mode, &ubuf->st_mode); + err |= __put_user(kbuf->st_nlink, &ubuf->st_nlink); + err |= __put_user(kbuf->st_uid, &ubuf->st_uid); + err |= __put_user(kbuf->st_gid, &ubuf->st_gid); + err |= __put_user(kbuf->st_rdev, &ubuf->st_rdev); + err |= __put_user(kbuf->st_size, &ubuf->st_size); + err |= __put_user(kbuf->st_atime, &ubuf->st_atime); + err |= __put_user(kbuf->st_mtime, &ubuf->st_mtime); + err |= __put_user(kbuf->st_ctime, &ubuf->st_ctime); + err |= __put_user(kbuf->st_blksize, &ubuf->st_blksize); + err |= __put_user(kbuf->st_blocks, &ubuf->st_blocks); return err; } -extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf); +extern asmlinkage long sys_newstat (char * filename, struct stat * statbuf); asmlinkage long -sys32_newstat(char * filename, struct stat32 *statbuf) +sys32_newstat (char *filename, struct stat32 *statbuf) { int ret; struct stat s; @@ -173,8 +205,8 @@ set_fs(KERNEL_DS); ret = sys_newstat(filename, &s); - set_fs (old_fs); - if (putstat (statbuf, &s)) + set_fs(old_fs); + if (putstat(statbuf, &s)) return -EFAULT; return ret; } @@ -182,16 +214,16 @@ extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf); asmlinkage long -sys32_newlstat(char * filename, struct stat32 *statbuf) +sys32_newlstat (char *filename, struct stat32 *statbuf) { - int ret; - struct stat s; mm_segment_t old_fs = get_fs(); + struct stat s; + int ret; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_newlstat(filename, &s); - set_fs (old_fs); - if (putstat (statbuf, &s)) + set_fs(old_fs); + if (putstat(statbuf, &s)) return -EFAULT; return ret; } @@ -199,112 +231,249 @@ extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf); asmlinkage long -sys32_newfstat(unsigned int fd, struct stat32 *statbuf) +sys32_newfstat (unsigned int fd, struct stat32 *statbuf) { - int ret; - struct stat s; mm_segment_t old_fs = get_fs(); + struct stat s; + int ret; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_newfstat(fd, &s); - set_fs (old_fs); - if (putstat (statbuf, &s)) + set_fs(old_fs); + if (putstat(statbuf, &s)) return -EFAULT; return ret; } -#define OFFSET4K(a) ((a) & 0xfff) +#if PAGE_SHIFT > IA32_PAGE_SHIFT -unsigned long -do_mmap_fake(struct file *file, unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, loff_t off) + +static int +get_page_prot (unsigned long addr) +{ + struct vm_area_struct *vma = find_vma(current->mm, addr); + int prot = 0; + + if (!vma || vma->vm_start > addr) + return 0; + + if (vma->vm_flags & VM_READ) + prot |= PROT_READ; + if (vma->vm_flags & VM_WRITE) + prot |= PROT_WRITE; + if (vma->vm_flags & VM_EXEC) + prot |= PROT_EXEC; + return prot; +} + +/* + * Map a subpage by creating an anonymous page that contains the union of the old page and + * the subpage. + */ +static unsigned long +mmap_subpage (struct file *file, unsigned long start, unsigned long end, int prot, int flags, + loff_t off) { + void *page = (void *) get_zeroed_page(GFP_KERNEL); struct inode *inode; - void *front, *back; - unsigned long baddr; - int r; - char c; + unsigned long ret; + int old_prot = get_page_prot(start); - if (OFFSET4K(addr) || OFFSET4K(off)) - return -EINVAL; - prot |= PROT_WRITE; - front = NULL; - back = NULL; - if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) { - front = kmalloc(addr - baddr, GFP_KERNEL); - if (!front) - return -ENOMEM; - __copy_user(front, (void *)baddr, addr - baddr); + DBG("mmap_subpage(file=%p,start=0x%lx,end=0x%lx,prot=%x,flags=%x,off=0x%llx)\n", + file, start, end, prot, flags, off); + + if (!page) + return -ENOMEM; + + if (old_prot) + copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE); + + down_write(¤t->mm->mmap_sem); + { + ret = do_mmap(0, PAGE_START(start), PAGE_SIZE, prot | PROT_WRITE, + flags | MAP_FIXED | MAP_ANONYMOUS, 0); } - if (addr && ((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) { - back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL); - if (!back) { - if (front) - kfree(front); - return -ENOMEM; + up_write(¤t->mm->mmap_sem); + + if (IS_ERR((void *) ret)) + goto out; + + if (old_prot) { + /* copy back the old page contents. */ + if (PAGE_OFF(start)) + copy_to_user((void *) PAGE_START(start), page, PAGE_OFF(start)); + if (PAGE_OFF(end)) + copy_to_user((void *) end, page + PAGE_OFF(end), + PAGE_SIZE - PAGE_OFF(end)); + } + if (!(flags & MAP_ANONYMOUS)) { + /* read the file contents */ + inode = file->f_dentry->d_inode; + if (!inode->i_fop || !file->f_op->read + || ((*file->f_op->read)(file, (char *) start, end - start, &off) < 0)) + { + ret = -EINVAL; + goto out; + } + } + if (!(prot & PROT_WRITE)) + ret = sys_mprotect(PAGE_START(start), PAGE_SIZE, prot | old_prot); + out: + free_page((unsigned long) page); + return ret; +} + +static unsigned long +emulate_mmap (struct file *file, unsigned long start, unsigned long len, int prot, int flags, + loff_t off) +{ + unsigned long tmp, end, pend, pstart, ret, is_congruent, fudge = 0; + struct inode *inode; + loff_t poff; + + end = start + len; + pstart = PAGE_START(start); + pend = PAGE_ALIGN(end); + + if (flags & MAP_FIXED) { + if (start > pstart) { + if (flags & MAP_SHARED) + printk(KERN_INFO + "%s(%d): emulate_mmap() can't share head (addr=0x%lx)\n", + current->comm, current->pid, start); + ret = mmap_subpage(file, start, min(PAGE_ALIGN(start), end), prot, flags, + off); + if (IS_ERR((void *) ret)) + return ret; + pstart += PAGE_SIZE; + if (pstart >= pend) + return start; /* done */ + } + if (end < pend) { + if (flags & MAP_SHARED) + printk(KERN_INFO + "%s(%d): emulate_mmap() can't share tail (end=0x%lx)\n", + current->comm, current->pid, end); + ret = mmap_subpage(file, max(start, PAGE_START(end)), end, prot, flags, + (off + len) - PAGE_OFF(end)); + if (IS_ERR((void *) ret)) + return ret; + pend -= PAGE_SIZE; + if (pstart >= pend) + return start; /* done */ + } + } else { + /* + * If a start address was specified, use it if the entire rounded out area + * is available. + */ + if (start && !pstart) + fudge = 1; /* handle case of mapping to range (0,PAGE_SIZE) */ + tmp = arch_get_unmapped_area(file, pstart - fudge, pend - pstart, 0, flags); + if (tmp != pstart) { + pstart = tmp; + start = pstart + PAGE_OFF(off); /* make start congruent with off */ + end = start + len; + pend = PAGE_ALIGN(end); } - __copy_user(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); } + + poff = off + (pstart - start); /* note: (pstart - start) may be negative */ + is_congruent = (flags & MAP_ANONYMOUS) || (PAGE_OFF(poff) == 0); + + if ((flags & MAP_SHARED) && !is_congruent) + printk(KERN_INFO "%s(%d): emulate_mmap() can't share contents of incongruent mmap " + "(addr=0x%lx,off=0x%llx)\n", current->comm, current->pid, start, off); + + DBG("mmap_body: mapping [0x%lx-0x%lx) %s with poff 0x%llx\n", pstart, pend, + is_congruent ? "congruent" : "not congruent", poff); + down_write(¤t->mm->mmap_sem); - r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0); + { + if (!(flags & MAP_ANONYMOUS) && is_congruent) + ret = do_mmap(file, pstart, pend - pstart, prot, flags | MAP_FIXED, poff); + else + ret = do_mmap(0, pstart, pend - pstart, + prot | ((flags & MAP_ANONYMOUS) ? 0 : PROT_WRITE), + flags | MAP_FIXED | MAP_ANONYMOUS, 0); + } up_write(¤t->mm->mmap_sem); - if (r < 0) - return(r); - if (addr == 0) - addr = r; - if (back) { - __copy_user((char *)addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); - kfree(back); - } - if (front) { - __copy_user((void *)baddr, front, addr - baddr); - kfree(front); - } - if (flags & MAP_ANONYMOUS) { - clear_user((char *)addr, len); - return(addr); + + if (IS_ERR((void *) ret)) + return ret; + + if (!is_congruent) { + /* read the file contents */ + inode = file->f_dentry->d_inode; + if (!inode->i_fop || !file->f_op->read + || ((*file->f_op->read)(file, (char *) pstart, pend - pstart, &poff) < 0)) + { + sys_munmap(pstart, pend - pstart); + return -EINVAL; + } + if (!(prot & PROT_WRITE) && sys_mprotect(pstart, pend - pstart, prot) < 0) + return EINVAL; } - if (!file) - return -EINVAL; - inode = file->f_dentry->d_inode; - if (!inode->i_fop) - return -EINVAL; - if (!file->f_op->read) - return -EINVAL; - r = file->f_op->read(file, (char *)addr, len, &off); - return (r < 0) ? -EINVAL : addr; + return start; } -long -ia32_do_mmap (struct file *file, unsigned int addr, unsigned int len, unsigned int prot, - unsigned int flags, unsigned int fd, unsigned int offset) +#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */ + +static inline unsigned int +get_prot32 (unsigned int prot) { - long error = -EFAULT; - unsigned int poff; + if (prot & PROT_WRITE) + /* on x86, PROT_WRITE implies PROT_READ which implies PROT_EEC */ + prot |= PROT_READ | PROT_WRITE | PROT_EXEC; + else if (prot & (PROT_READ | PROT_EXEC)) + /* on x86, there is no distinction between PROT_READ and PROT_EXEC */ + prot |= (PROT_READ | PROT_EXEC); - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - prot |= PROT_EXEC; + return prot; +} - if ((flags & MAP_FIXED) && ((addr & ~PAGE_MASK) || (offset & ~PAGE_MASK))) - error = do_mmap_fake(file, addr, len, prot, flags, (loff_t)offset); - else { - poff = offset & PAGE_MASK; - len += offset - poff; +unsigned long +ia32_do_mmap (struct file *file, unsigned long addr, unsigned long len, int prot, int flags, + loff_t offset) +{ + DBG("ia32_do_mmap(file=%p,addr=0x%lx,len=0x%lx,prot=%x,flags=%x,offset=0x%llx)\n", + file, addr, len, prot, flags, offset); + + if (file && (!file->f_op || !file->f_op->mmap)) + return -ENODEV; + + len = IA32_PAGE_ALIGN(len); + if (len == 0) + return addr; + + if (len > IA32_PAGE_OFFSET || addr > IA32_PAGE_OFFSET - len) + return -EINVAL; + + if (OFFSET4K(offset)) + return -EINVAL; - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT); - up_write(¤t->mm->mmap_sem); + prot = get_prot32(prot); - if (!IS_ERR((void *) error)) - error += offset - poff; +#if PAGE_SHIFT > IA32_PAGE_SHIFT + down(&ia32_mmap_sem); + { + addr = emulate_mmap(file, addr, len, prot, flags, offset); } - return error; + up(&ia32_mmap_sem); +#else + down_write(¤t->mm->mmap_sem); + { + addr = do_mmap(file, addr, len, prot, flags, offset); + } + up_write(¤t->mm->mmap_sem); +#endif + DBG("ia32_do_mmap: returning 0x%lx\n", addr); + return addr; } /* - * Linux/i386 didn't use to be able to handle more than - * 4 system call parameters, so these system calls used a memory - * block for parameter passing.. + * Linux/i386 didn't use to be able to handle more than 4 system call parameters, so these + * system calls used a memory block for parameter passing.. */ struct mmap_arg_struct { @@ -317,180 +486,166 @@ }; asmlinkage long -sys32_mmap(struct mmap_arg_struct *arg) +sys32_mmap (struct mmap_arg_struct *arg) { struct mmap_arg_struct a; struct file *file = NULL; - long retval; + unsigned long addr; + int flags; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; - if (PAGE_ALIGN(a.len) == 0) - return a.addr; + if (OFFSET4K(a.offset)) + return -EINVAL; + + flags = a.flags; - if (!(a.flags & MAP_ANONYMOUS)) { + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { file = fget(a.fd); if (!file) return -EBADF; } -#ifdef CONFIG_IA64_PAGE_SIZE_4KB - if ((a.offset & ~PAGE_MASK) != 0) - return -EINVAL; - down_write(¤t->mm->mmap_sem); - retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT); - up_write(¤t->mm->mmap_sem); -#else - retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset); -#endif + addr = ia32_do_mmap(file, a.addr, a.len, a.prot, flags, a.offset); + if (file) fput(file); - return retval; + return addr; } asmlinkage long -sys32_mprotect(unsigned long start, size_t len, unsigned long prot) +sys32_mmap2 (unsigned int addr, unsigned int len, unsigned int prot, unsigned int flags, + unsigned int fd, unsigned int pgoff) { + struct file *file = NULL; + unsigned long retval; -#ifdef CONFIG_IA64_PAGE_SIZE_4KB - return(sys_mprotect(start, len, prot)); -#else // CONFIG_IA64_PAGE_SIZE_4KB - if (prot == 0) - return(0); - len += start & ~PAGE_MASK; - if ((start & ~PAGE_MASK) && (prot & PROT_WRITE)) - prot |= PROT_EXEC; - return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot)); -#endif // CONFIG_IA64_PAGE_SIZE_4KB -} + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + return -EBADF; + } -asmlinkage long -sys32_pipe(int *fd) -{ - int retval; - int fds[2]; + retval = ia32_do_mmap(file, addr, len, prot, flags, + (unsigned long) pgoff << IA32_PAGE_SHIFT); - retval = do_pipe(fds); - if (retval) - goto out; - if (copy_to_user(fd, fds, sizeof(fds))) - retval = -EFAULT; - out: + if (file) + fput(file); return retval; } asmlinkage long -sys32_signal (int sig, unsigned int handler) +sys32_munmap (unsigned int start, unsigned int len) { - struct k_sigaction new_sa, old_sa; - int ret; + unsigned int end = start + len; + long ret; + +#if PAGE_SHIFT <= IA32_PAGE_SHIFT + ret = sys_munmap(start, end - start); +#else + if (start > end) + return -EINVAL; + + start = PAGE_ALIGN(start); + end = PAGE_START(end); + + if (start >= end) + return 0; + + down(&ia32_mmap_sem); + { + ret = sys_munmap(start, end - start); + } + up(&ia32_mmap_sem); +#endif + return ret; +} - new_sa.sa.sa_handler = (__sighandler_t) A(handler); - new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; +#if PAGE_SHIFT > IA32_PAGE_SHIFT + +/* + * When mprotect()ing a partial page, we set the permission to the union of the old + * settings and the new settings. In other words, it's only possible to make access to a + * partial page less restrictive. + */ +static long +mprotect_subpage (unsigned long address, int new_prot) +{ + int old_prot; - ret = do_sigaction(sig, &new_sa, &old_sa); + if (new_prot == PROT_NONE) + return 0; /* optimize case where nothing changes... */ - return ret ? ret : (unsigned long)old_sa.sa.sa_handler; + old_prot = get_page_prot(address); + return sys_mprotect(address, PAGE_SIZE, new_prot | old_prot); } +#endif /* PAGE_SHIFT > IA32_PAGE_SHIFT */ + asmlinkage long -sys32_rt_sigaction(int sig, struct sigaction32 *act, - struct sigaction32 *oact, unsigned int sigsetsize) +sys32_mprotect (unsigned int start, unsigned int len, int prot) { - struct k_sigaction new_ka, old_ka; - int ret; - sigset32_t set32; + unsigned long end = start + len; +#if PAGE_SHIFT > IA32_PAGE_SHIFT + long retval = 0; +#endif + + prot = get_prot32(prot); - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset32_t)) +#if PAGE_SHIFT <= IA32_PAGE_SHIFT + return sys_mprotect(start, end - start, prot); +#else + if (OFFSET4K(start)) return -EINVAL; - if (act) { - ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); - ret |= __copy_from_user(&set32, &act->sa_mask, - sizeof(sigset32_t)); - switch (_NSIG_WORDS) { - case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] - | (((long)set32.sig[7]) << 32); - case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] - | (((long)set32.sig[5]) << 32); - case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] - | (((long)set32.sig[3]) << 32); - case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] - | (((long)set32.sig[1]) << 32); - } - ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + end = IA32_PAGE_ALIGN(end); + if (end < start) + return -EINVAL; - if (ret) - return -EFAULT; - } + down(&ia32_mmap_sem); + { + if (PAGE_OFF(start)) { + /* start address is 4KB aligned but not page aligned. */ + retval = mprotect_subpage(PAGE_START(start), prot); + if (retval < 0) + goto out; - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + start = PAGE_ALIGN(start); + if (start >= end) + goto out; /* retval is already zero... */ + } - if (!ret && oact) { - switch (_NSIG_WORDS) { - case 4: - set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); - set32.sig[6] = old_ka.sa.sa_mask.sig[3]; - case 3: - set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); - set32.sig[4] = old_ka.sa.sa_mask.sig[2]; - case 2: - set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); - set32.sig[2] = old_ka.sa.sa_mask.sig[1]; - case 1: - set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); - set32.sig[0] = old_ka.sa.sa_mask.sig[0]; + if (PAGE_OFF(end)) { + /* end address is 4KB aligned but not page aligned. */ + retval = mprotect_subpage(PAGE_START(end), prot); + if (retval < 0) + return retval; + end = PAGE_START(end); } - ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); - ret |= __copy_to_user(&oact->sa_mask, &set32, - sizeof(sigset32_t)); - ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + retval = sys_mprotect(start, end - start, prot); } - - return ret; + out: + up(&ia32_mmap_sem); + return retval; +#endif } - -extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, - size_t sigsetsize); - asmlinkage long -sys32_rt_sigprocmask(int how, sigset32_t *set, sigset32_t *oset, - unsigned int sigsetsize) +sys32_pipe (int *fd) { - sigset_t s; - sigset32_t s32; - int ret; - mm_segment_t old_fs = get_fs(); + int retval; + int fds[2]; - if (set) { - if (copy_from_user (&s32, set, sizeof(sigset32_t))) - return -EFAULT; - switch (_NSIG_WORDS) { - case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); - case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); - case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); - case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); - } - } - set_fs (KERNEL_DS); - ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, - sigsetsize); - set_fs (old_fs); - if (ret) return ret; - if (oset) { - switch (_NSIG_WORDS) { - case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; - case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; - case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; - case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; - } - if (copy_to_user (oset, &s32, sizeof(sigset32_t))) - return -EFAULT; - } - return 0; + retval = do_pipe(fds); + if (retval) + goto out; + if (copy_to_user(fd, fds, sizeof(fds))) + retval = -EFAULT; + out: + return retval; } static inline int @@ -498,31 +653,34 @@ { int err; - err = put_user (kbuf->f_type, &ubuf->f_type); - err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize); - err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks); - err |= __put_user (kbuf->f_bfree, &ubuf->f_bfree); - err |= __put_user (kbuf->f_bavail, &ubuf->f_bavail); - err |= __put_user (kbuf->f_files, &ubuf->f_files); - err |= __put_user (kbuf->f_ffree, &ubuf->f_ffree); - err |= __put_user (kbuf->f_namelen, &ubuf->f_namelen); - err |= __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]); - err |= __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]); + if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) + return -EFAULT; + + err = __put_user(kbuf->f_type, &ubuf->f_type); + err |= __put_user(kbuf->f_bsize, &ubuf->f_bsize); + err |= __put_user(kbuf->f_blocks, &ubuf->f_blocks); + err |= __put_user(kbuf->f_bfree, &ubuf->f_bfree); + err |= __put_user(kbuf->f_bavail, &ubuf->f_bavail); + err |= __put_user(kbuf->f_files, &ubuf->f_files); + err |= __put_user(kbuf->f_ffree, &ubuf->f_ffree); + err |= __put_user(kbuf->f_namelen, &ubuf->f_namelen); + err |= __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]); + err |= __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]); return err; } extern asmlinkage long sys_statfs(const char * path, struct statfs * buf); asmlinkage long -sys32_statfs(const char * path, struct statfs32 *buf) +sys32_statfs (const char *path, struct statfs32 *buf) { int ret; struct statfs s; mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_statfs((const char *)path, &s); - set_fs (old_fs); + set_fs(KERNEL_DS); + ret = sys_statfs(path, &s); + set_fs(old_fs); if (put_statfs(buf, &s)) return -EFAULT; return ret; @@ -531,15 +689,15 @@ extern asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf); asmlinkage long -sys32_fstatfs(unsigned int fd, struct statfs32 *buf) +sys32_fstatfs (unsigned int fd, struct statfs32 *buf) { int ret; struct statfs s; mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_fstatfs(fd, &s); - set_fs (old_fs); + set_fs(old_fs); if (put_statfs(buf, &s)) return -EFAULT; return ret; @@ -557,23 +715,21 @@ }; static inline long -get_tv32(struct timeval *o, struct timeval32 *i) +get_tv32 (struct timeval *o, struct timeval32 *i) { return (!access_ok(VERIFY_READ, i, sizeof(*i)) || - (__get_user(o->tv_sec, &i->tv_sec) | - __get_user(o->tv_usec, &i->tv_usec))); + (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec))); } static inline long -put_tv32(struct timeval32 *o, struct timeval *i) +put_tv32 (struct timeval32 *o, struct timeval *i) { return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || - (__put_user(i->tv_sec, &o->tv_sec) | - __put_user(i->tv_usec, &o->tv_usec))); + (__put_user(i->tv_sec, &o->tv_sec) | __put_user(i->tv_usec, &o->tv_usec))); } static inline long -get_it32(struct itimerval *o, struct itimerval32 *i) +get_it32 (struct itimerval *o, struct itimerval32 *i) { return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | @@ -583,7 +739,7 @@ } static inline long -put_it32(struct itimerval32 *o, struct itimerval *i) +put_it32 (struct itimerval32 *o, struct itimerval *i) { return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | @@ -592,10 +748,10 @@ __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); } -extern int do_getitimer(int which, struct itimerval *value); +extern int do_getitimer (int which, struct itimerval *value); asmlinkage long -sys32_getitimer(int which, struct itimerval32 *it) +sys32_getitimer (int which, struct itimerval32 *it) { struct itimerval kit; int error; @@ -607,10 +763,10 @@ return error; } -extern int do_setitimer(int which, struct itimerval *, struct itimerval *); +extern int do_setitimer (int which, struct itimerval *, struct itimerval *); asmlinkage long -sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out) +sys32_setitimer (int which, struct itimerval32 *in, struct itimerval32 *out) { struct itimerval kin, kout; int error; @@ -630,8 +786,9 @@ return 0; } + asmlinkage unsigned long -sys32_alarm(unsigned int seconds) +sys32_alarm (unsigned int seconds) { struct itimerval it_new, it_old; unsigned int oldalarm; @@ -660,7 +817,7 @@ extern asmlinkage long sys_gettimeofday (struct timeval *tv, struct timezone *tz); asmlinkage long -ia32_utime(char * filename, struct utimbuf_32 *times32) +sys32_utime (char *filename, struct utimbuf_32 *times32) { mm_segment_t old_fs = get_fs(); struct timeval tv[2], *tvp; @@ -673,20 +830,20 @@ if (get_user(tv[1].tv_sec, ×32->mtime)) return -EFAULT; tv[1].tv_usec = 0; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); tvp = tv; } else tvp = NULL; ret = sys_utimes(filename, tvp); - set_fs (old_fs); + set_fs(old_fs); return ret; } extern struct timezone sys_tz; -extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz); +extern int do_sys_settimeofday (struct timeval *tv, struct timezone *tz); asmlinkage long -sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz) +sys32_gettimeofday (struct timeval32 *tv, struct timezone *tz) { if (tv) { struct timeval ktv; @@ -702,7 +859,7 @@ } asmlinkage long -sys32_settimeofday(struct timeval32 *tv, struct timezone *tz) +sys32_settimeofday (struct timeval32 *tv, struct timezone *tz) { struct timeval ktv; struct timezone ktz; @@ -719,20 +876,6 @@ return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL); } -struct linux32_dirent { - u32 d_ino; - u32 d_off; - u16 d_reclen; - char d_name[1]; -}; - -struct old_linux32_dirent { - u32 d_ino; - u32 d_offset; - u16 d_namlen; - char d_name[1]; -}; - struct getdents32_callback { struct linux32_dirent * current_dir; struct linux32_dirent * previous; @@ -775,7 +918,7 @@ } asmlinkage long -sys32_getdents (unsigned int fd, void * dirent, unsigned int count) +sys32_getdents (unsigned int fd, struct linux32_dirent *dirent, unsigned int count) { struct file * file; struct linux32_dirent * lastdirent; @@ -787,7 +930,7 @@ if (!file) goto out; - buf.current_dir = (struct linux32_dirent *) dirent; + buf.current_dir = dirent; buf.previous = NULL; buf.count = count; buf.error = 0; @@ -831,7 +974,7 @@ } asmlinkage long -sys32_readdir (unsigned int fd, void * dirent, unsigned int count) +sys32_readdir (unsigned int fd, void *dirent, unsigned int count) { int error; struct file * file; @@ -866,7 +1009,7 @@ #define ROUND_UP_TIME(x,y) (((x)+(y)-1)/(y)) asmlinkage long -sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32) +sys32_select (int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32) { fd_set_bits fds; char *bits; @@ -878,8 +1021,7 @@ time_t sec, usec; ret = -EFAULT; - if (get_user(sec, &tvp32->tv_sec) - || get_user(usec, &tvp32->tv_usec)) + if (get_user(sec, &tvp32->tv_sec) || get_user(usec, &tvp32->tv_usec)) goto out_nofds; ret = -EINVAL; @@ -933,9 +1075,7 @@ usec = timeout % HZ; usec *= (1000000/HZ); } - if (put_user(sec, (int *)&tvp32->tv_sec) - || put_user(usec, (int *)&tvp32->tv_usec)) - { + if (put_user(sec, &tvp32->tv_sec) || put_user(usec, &tvp32->tv_usec)) { ret = -EFAULT; goto out; } @@ -969,50 +1109,43 @@ }; asmlinkage long -old_select(struct sel_arg_struct *arg) +sys32_old_select (struct sel_arg_struct *arg) { struct sel_arg_struct a; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; - return sys32_select(a.n, (fd_set *)A(a.inp), (fd_set *)A(a.outp), (fd_set *)A(a.exp), - (struct timeval32 *)A(a.tvp)); + return sys32_select(a.n, (fd_set *) A(a.inp), (fd_set *) A(a.outp), (fd_set *) A(a.exp), + (struct timeval32 *) A(a.tvp)); } -struct timespec32 { - int tv_sec; - int tv_nsec; -}; - -extern asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); +extern asmlinkage long sys_nanosleep (struct timespec *rqtp, struct timespec *rmtp); asmlinkage long -sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp) +sys32_nanosleep (struct timespec32 *rqtp, struct timespec32 *rmtp) { struct timespec t; int ret; - mm_segment_t old_fs = get_fs (); + mm_segment_t old_fs = get_fs(); - if (get_user (t.tv_sec, &rqtp->tv_sec) || - __get_user (t.tv_nsec, &rqtp->tv_nsec)) + if (get_user (t.tv_sec, &rqtp->tv_sec) || get_user (t.tv_nsec, &rqtp->tv_nsec)) return -EFAULT; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_nanosleep(&t, rmtp ? &t : NULL); - set_fs (old_fs); + set_fs(old_fs); if (rmtp && ret == -EINTR) { - if (__put_user (t.tv_sec, &rmtp->tv_sec) || - __put_user (t.tv_nsec, &rmtp->tv_nsec)) + if (put_user(t.tv_sec, &rmtp->tv_sec) || put_user(t.tv_nsec, &rmtp->tv_nsec)) return -EFAULT; } return ret; } struct iovec32 { unsigned int iov_base; int iov_len; }; -asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long); -asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long); +asmlinkage ssize_t sys_readv (unsigned long,const struct iovec *,unsigned long); +asmlinkage ssize_t sys_writev (unsigned long,const struct iovec *,unsigned long); static struct iovec * -get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type) +get_iovec32 (struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type) { int i; u32 buf, len; @@ -1022,24 +1155,23 @@ if (!count) return 0; - if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count)) - return(struct iovec *)0; + if (verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count)) + return NULL; if (count > UIO_MAXIOV) - return(struct iovec *)0; + return NULL; if (count > UIO_FASTIOV) { iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); if (!iov) - return((struct iovec *)0); + return NULL; } else iov = iov_buf; ivp = iov; for (i = 0; i < count; i++) { - if (__get_user(len, &iov32->iov_len) || - __get_user(buf, &iov32->iov_base)) { + if (__get_user(len, &iov32->iov_len) || __get_user(buf, &iov32->iov_base)) { if (iov != iov_buf) kfree(iov); - return((struct iovec *)0); + return NULL; } if (verify_area(type, (void *)A(buf), len)) { if (iov != iov_buf) @@ -1047,22 +1179,23 @@ return((struct iovec *)0); } ivp->iov_base = (void *)A(buf); - ivp->iov_len = (__kernel_size_t)len; + ivp->iov_len = (__kernel_size_t) len; iov32++; ivp++; } - return(iov); + return iov; } asmlinkage long -sys32_readv(int fd, struct iovec32 *vector, u32 count) +sys32_readv (int fd, struct iovec32 *vector, u32 count) { struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov; - int ret; + long ret; mm_segment_t old_fs = get_fs(); - if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) == (struct iovec *)0) + iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE); + if (!iov) return -EFAULT; set_fs(KERNEL_DS); ret = sys_readv(fd, iov, count); @@ -1073,14 +1206,15 @@ } asmlinkage long -sys32_writev(int fd, struct iovec32 *vector, u32 count) +sys32_writev (int fd, struct iovec32 *vector, u32 count) { struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov; - int ret; + long ret; mm_segment_t old_fs = get_fs(); - if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) == (struct iovec *)0) + iov = get_iovec32(vector, iovstack, count, VERIFY_READ); + if (!iov) return -EFAULT; set_fs(KERNEL_DS); ret = sys_writev(fd, iov, count); @@ -1098,45 +1232,66 @@ int rlim_max; }; -extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim); +extern asmlinkage long sys_getrlimit (unsigned int resource, struct rlimit *rlim); asmlinkage long -sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim) +sys32_old_getrlimit (unsigned int resource, struct rlimit32 *rlim) { + mm_segment_t old_fs = get_fs(); + struct rlimit r; + int ret; + + set_fs(KERNEL_DS); + ret = sys_getrlimit(resource, &r); + set_fs(old_fs); + if (!ret) { + ret = put_user(RESOURCE32(r.rlim_cur), &rlim->rlim_cur); + ret |= put_user(RESOURCE32(r.rlim_max), &rlim->rlim_max); + } + return ret; +} + +asmlinkage long +sys32_getrlimit (unsigned int resource, struct rlimit32 *rlim) +{ + mm_segment_t old_fs = get_fs(); struct rlimit r; int ret; - mm_segment_t old_fs = get_fs (); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_getrlimit(resource, &r); - set_fs (old_fs); + set_fs(old_fs); if (!ret) { - ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur); - ret |= __put_user (RESOURCE32(r.rlim_max), &rlim->rlim_max); + if (r.rlim_cur >= 0xffffffff) + r.rlim_cur = 0xffffffff; + if (r.rlim_max >= 0xffffffff) + r.rlim_max = 0xffffffff; + ret = put_user(r.rlim_cur, &rlim->rlim_cur); + ret |= put_user(r.rlim_max, &rlim->rlim_max); } return ret; } -extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim); +extern asmlinkage long sys_setrlimit (unsigned int resource, struct rlimit *rlim); asmlinkage long -sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim) +sys32_setrlimit (unsigned int resource, struct rlimit32 *rlim) { struct rlimit r; int ret; - mm_segment_t old_fs = get_fs (); + mm_segment_t old_fs = get_fs(); - if (resource >= RLIM_NLIMITS) return -EINVAL; - if (get_user (r.rlim_cur, &rlim->rlim_cur) || - __get_user (r.rlim_max, &rlim->rlim_max)) + if (resource >= RLIM_NLIMITS) + return -EINVAL; + if (get_user(r.rlim_cur, &rlim->rlim_cur) || get_user(r.rlim_max, &rlim->rlim_max)) return -EFAULT; if (r.rlim_cur == RLIM_INFINITY32) r.rlim_cur = RLIM_INFINITY; if (r.rlim_max == RLIM_INFINITY32) r.rlim_max = RLIM_INFINITY; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_setrlimit(resource, &r); - set_fs (old_fs); + set_fs(old_fs); return ret; } @@ -1154,25 +1309,141 @@ unsigned msg_flags; }; -static inline int -shape_msg(struct msghdr *mp, struct msghdr32 *mp32) -{ - int ret; - unsigned int i; +struct cmsghdr32 { + __kernel_size_t32 cmsg_len; + int cmsg_level; + int cmsg_type; +}; - if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32))) - return(-EFAULT); - ret = __get_user(i, &mp32->msg_name); - mp->msg_name = (void *)A(i); - ret |= __get_user(mp->msg_namelen, &mp32->msg_namelen); - ret |= __get_user(i, &mp32->msg_iov); +/* Bleech... */ +#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) +#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) +#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) ) +#define CMSG32_DATA(cmsg) \ + ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32)))) +#define CMSG32_SPACE(len) \ + (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len)) +#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len)) +#define __CMSG32_FIRSTHDR(ctl,len) \ + ((len) >= sizeof(struct cmsghdr32) ? (struct cmsghdr32 *)(ctl) : (struct cmsghdr32 *)NULL) +#define CMSG32_FIRSTHDR(msg) __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) + +static inline struct cmsghdr32 * +__cmsg32_nxthdr (void *ctl, __kernel_size_t size, struct cmsghdr32 *cmsg, int cmsg_len) +{ + struct cmsghdr32 * ptr; + + ptr = (struct cmsghdr32 *)(((unsigned char *) cmsg) + CMSG32_ALIGN(cmsg_len)); + if ((unsigned long)((char*)(ptr+1) - (char *) ctl) > size) + return NULL; + return ptr; +} + +static inline struct cmsghdr32 * +cmsg32_nxthdr (struct msghdr *msg, struct cmsghdr32 *cmsg, int cmsg_len) +{ + return __cmsg32_nxthdr(msg->msg_control, msg->msg_controllen, cmsg, cmsg_len); +} + +static inline int +get_msghdr32 (struct msghdr *mp, struct msghdr32 *mp32) +{ + int ret; + unsigned int i; + + if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32))) + return -EFAULT; + ret = __get_user(i, &mp32->msg_name); + mp->msg_name = (void *)A(i); + ret |= __get_user(mp->msg_namelen, &mp32->msg_namelen); + ret |= __get_user(i, &mp32->msg_iov); mp->msg_iov = (struct iovec *)A(i); ret |= __get_user(mp->msg_iovlen, &mp32->msg_iovlen); ret |= __get_user(i, &mp32->msg_control); mp->msg_control = (void *)A(i); ret |= __get_user(mp->msg_controllen, &mp32->msg_controllen); ret |= __get_user(mp->msg_flags, &mp32->msg_flags); - return(ret ? -EFAULT : 0); + return ret ? -EFAULT : 0; +} + +/* + * There is a lot of hair here because the alignment rules (and thus placement) of cmsg + * headers and length are different for 32-bit apps. -DaveM + */ +static int +get_cmsghdr32 (struct msghdr *kmsg, unsigned char *stackbuf, struct sock *sk, size_t *bufsize) +{ + struct cmsghdr *kcmsg, *kcmsg_base; + __kernel_size_t kcmlen, tmp; + __kernel_size_t32 ucmlen; + struct cmsghdr32 *ucmsg; + long err; + + kcmlen = 0; + kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; + ucmsg = CMSG32_FIRSTHDR(kmsg); + while (ucmsg != NULL) { + if (get_user(ucmlen, &ucmsg->cmsg_len)) + return -EFAULT; + + /* Catch bogons. */ + if (CMSG32_ALIGN(ucmlen) < CMSG32_ALIGN(sizeof(struct cmsghdr32))) + return -EINVAL; + if ((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control) + ucmlen) + > kmsg->msg_controllen) + return -EINVAL; + + tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + + CMSG_ALIGN(sizeof(struct cmsghdr))); + kcmlen += tmp; + ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); + } + if (kcmlen == 0) + return -EINVAL; + + /* + * The kcmlen holds the 64-bit version of the control length. It may not be + * modified as we do not stick it into the kmsg until we have successfully copied + * over all of the data from the user. + */ + if (kcmlen > *bufsize) { + *bufsize = kcmlen; + kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL); + } + if (kcmsg == NULL) + return -ENOBUFS; + + /* Now copy them over neatly. */ + memset(kcmsg, 0, kcmlen); + ucmsg = CMSG32_FIRSTHDR(kmsg); + while (ucmsg != NULL) { + err = get_user(ucmlen, &ucmsg->cmsg_len); + tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + + CMSG_ALIGN(sizeof(struct cmsghdr))); + kcmsg->cmsg_len = tmp; + err |= get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); + err |= get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); + + /* Copy over the data. */ + err |= copy_from_user(CMSG_DATA(kcmsg), CMSG32_DATA(ucmsg), + (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))); + if (err) + goto out_free_efault; + + /* Advance. */ + kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); + ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); + } + + /* Ok, looks like we made it. Hook it up and return success. */ + kmsg->msg_control = kcmsg_base; + kmsg->msg_controllen = kcmlen; + return 0; + +out_free_efault: + if (kcmsg_base != (struct cmsghdr *)stackbuf) + sock_kfree_s(sk, kcmsg_base, kcmlen); + return -EFAULT; } /* @@ -1187,20 +1458,17 @@ */ static inline int -verify_iovec32(struct msghdr *m, struct iovec *iov, char *address, int mode) +verify_iovec32 (struct msghdr *m, struct iovec *iov, char *address, int mode) { int size, err, ct; struct iovec32 *iov32; - if(m->msg_namelen) - { - if(mode==VERIFY_READ) - { - err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address); - if(err<0) + if (m->msg_namelen) { + if (mode == VERIFY_READ) { + err = move_addr_to_kernel(m->msg_name, m->msg_namelen, address); + if (err < 0) goto out; } - m->msg_name = address; } else m->msg_name = NULL; @@ -1209,7 +1477,7 @@ size = m->msg_iovlen * sizeof(struct iovec32); if (copy_from_user(iov, m->msg_iov, size)) goto out; - m->msg_iov=iov; + m->msg_iov = iov; err = 0; iov32 = (struct iovec32 *)iov; @@ -1222,8 +1490,188 @@ return err; } -extern __inline__ void -sockfd_put(struct socket *sock) +static void +put_cmsg32(struct msghdr *kmsg, int level, int type, int len, void *data) +{ + struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; + struct cmsghdr32 cmhdr; + int cmlen = CMSG32_LEN(len); + + if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { + kmsg->msg_flags |= MSG_CTRUNC; + return; + } + + if(kmsg->msg_controllen < cmlen) { + kmsg->msg_flags |= MSG_CTRUNC; + cmlen = kmsg->msg_controllen; + } + cmhdr.cmsg_level = level; + cmhdr.cmsg_type = type; + cmhdr.cmsg_len = cmlen; + + if(copy_to_user(cm, &cmhdr, sizeof cmhdr)) + return; + if(copy_to_user(CMSG32_DATA(cm), data, + cmlen - sizeof(struct cmsghdr32))) + return; + cmlen = CMSG32_SPACE(len); + kmsg->msg_control += cmlen; + kmsg->msg_controllen -= cmlen; +} + +static void +scm_detach_fds32 (struct msghdr *kmsg, struct scm_cookie *scm) +{ + struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; + int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) + / sizeof(int); + int fdnum = scm->fp->count; + struct file **fp = scm->fp->fp; + int *cmfptr; + int err = 0, i; + + if (fdnum < fdmax) + fdmax = fdnum; + + for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); + i < fdmax; + i++, cmfptr++) { + int new_fd; + err = get_unused_fd(); + if (err < 0) + break; + new_fd = err; + err = put_user(new_fd, cmfptr); + if (err) { + put_unused_fd(new_fd); + break; + } + /* Bump the usage count and install the file. */ + get_file(fp[i]); + current->files->fd[new_fd] = fp[i]; + } + + if (i > 0) { + int cmlen = CMSG32_LEN(i * sizeof(int)); + if (!err) + err = put_user(SOL_SOCKET, &cm->cmsg_level); + if (!err) + err = put_user(SCM_RIGHTS, &cm->cmsg_type); + if (!err) + err = put_user(cmlen, &cm->cmsg_len); + if (!err) { + cmlen = CMSG32_SPACE(i * sizeof(int)); + kmsg->msg_control += cmlen; + kmsg->msg_controllen -= cmlen; + } + } + if (i < fdnum) + kmsg->msg_flags |= MSG_CTRUNC; + + /* + * All of the files that fit in the message have had their + * usage counts incremented, so we just free the list. + */ + __scm_destroy(scm); +} + +/* + * In these cases we (currently) can just copy to data over verbatim because all CMSGs + * created by the kernel have well defined types which have the same layout in both the + * 32-bit and 64-bit API. One must add some special cased conversions here if we start + * sending control messages with incompatible types. + * + * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after + * we do our work. The remaining cases are: + * + * SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean + * IP_TTL int 32-bit clean + * IP_TOS __u8 32-bit clean + * IP_RECVOPTS variable length 32-bit clean + * IP_RETOPTS variable length 32-bit clean + * (these last two are clean because the types are defined + * by the IPv4 protocol) + * IP_RECVERR struct sock_extended_err + + * struct sockaddr_in 32-bit clean + * SOL_IPV6 IPV6_RECVERR struct sock_extended_err + + * struct sockaddr_in6 32-bit clean + * IPV6_PKTINFO struct in6_pktinfo 32-bit clean + * IPV6_HOPLIMIT int 32-bit clean + * IPV6_FLOWINFO u32 32-bit clean + * IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean + * IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean + * IPV6_RTHDR ipv6 routing exthdr 32-bit clean + * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean + */ +static void +cmsg32_recvmsg_fixup (struct msghdr *kmsg, unsigned long orig_cmsg_uptr) +{ + unsigned char *workbuf, *wp; + unsigned long bufsz, space_avail; + struct cmsghdr *ucmsg; + long err; + + bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr; + space_avail = kmsg->msg_controllen + bufsz; + wp = workbuf = kmalloc(bufsz, GFP_KERNEL); + if (workbuf == NULL) + goto fail; + + /* To make this more sane we assume the kernel sends back properly + * formatted control messages. Because of how the kernel will truncate + * the cmsg_len for MSG_TRUNC cases, we need not check that case either. + */ + ucmsg = (struct cmsghdr *) orig_cmsg_uptr; + while (((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) { + struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; + int clen64, clen32; + + /* + * UCMSG is the 64-bit format CMSG entry in user-space. KCMSG32 is within + * the kernel space temporary buffer we use to convert into a 32-bit style + * CMSG. + */ + err = get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len); + err |= get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level); + err |= get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type); + if (err) + goto fail2; + + clen64 = kcmsg32->cmsg_len; + copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg), + clen64 - CMSG_ALIGN(sizeof(*ucmsg))); + clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) + + CMSG32_ALIGN(sizeof(struct cmsghdr32))); + kcmsg32->cmsg_len = clen32; + + ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64)); + wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); + } + + /* Copy back fixed up data, and adjust pointers. */ + bufsz = (wp - workbuf); + if (copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz)) + goto fail2; + + kmsg->msg_control = (struct cmsghdr *) (((char *)orig_cmsg_uptr) + bufsz); + kmsg->msg_controllen = space_avail - bufsz; + kfree(workbuf); + return; + + fail2: + kfree(workbuf); + fail: + /* + * If we leave the 64-bit format CMSG chunks in there, the application could get + * confused and crash. So to ensure greater recovery, we report no CMSGs. + */ + kmsg->msg_controllen += bufsz; + kmsg->msg_control = (void *) orig_cmsg_uptr; +} + +static inline void +sockfd_put (struct socket *sock) { fput(sock->file); } @@ -1234,13 +1682,14 @@ 24 for IPv6, about 80 for AX.25 */ -extern struct socket *sockfd_lookup(int fd, int *err); +extern struct socket *sockfd_lookup (int fd, int *err); /* * BSD sendmsg interface */ -int sys32_sendmsg(int fd, struct msghdr32 *msg, unsigned flags) +int +sys32_sendmsg (int fd, struct msghdr32 *msg, unsigned flags) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -1248,10 +1697,11 @@ unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */ unsigned char *ctl_buf = ctl; struct msghdr msg_sys; - int err, ctl_len, iov_size, total_len; + int err, iov_size, total_len; + size_t ctl_len; err = -EFAULT; - if (shape_msg(&msg_sys, msg)) + if (get_msghdr32(&msg_sys, msg)) goto out; sock = sockfd_lookup(fd, &err); @@ -1282,20 +1732,12 @@ if (msg_sys.msg_controllen > INT_MAX) goto out_freeiov; - ctl_len = msg_sys.msg_controllen; - if (ctl_len) - { - if (ctl_len > sizeof(ctl)) - { - err = -ENOBUFS; - ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); - if (ctl_buf == NULL) - goto out_freeiov; - } - err = -EFAULT; - if (copy_from_user(ctl_buf, msg_sys.msg_control, ctl_len)) - goto out_freectl; - msg_sys.msg_control = ctl_buf; + if (msg_sys.msg_controllen) { + ctl_len = sizeof(ctl); + err = get_cmsghdr32(&msg_sys, ctl_buf, sock->sk, &ctl_len); + if (err) + goto out_freeiov; + ctl_buf = msg_sys.msg_control; } msg_sys.msg_flags = flags; @@ -1303,7 +1745,6 @@ msg_sys.msg_flags |= MSG_DONTWAIT; err = sock_sendmsg(sock, &msg_sys, total_len); -out_freectl: if (ctl_buf != ctl) sock_kfree_s(sock->sk, ctl_buf, ctl_len); out_freeiov: @@ -1328,6 +1769,7 @@ struct msghdr msg_sys; unsigned long cmsg_ptr; int err, iov_size, total_len, len; + struct scm_cookie scm; /* kernel mode address */ char addr[MAX_SOCK_ADDR]; @@ -1336,8 +1778,8 @@ struct sockaddr *uaddr; int *uaddr_len; - err=-EFAULT; - if (shape_msg(&msg_sys, msg)) + err = -EFAULT; + if (get_msghdr32(&msg_sys, msg)) goto out; sock = sockfd_lookup(fd, &err); @@ -1374,13 +1816,42 @@ if (sock->file->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; - err = sock_recvmsg(sock, &msg_sys, total_len, flags); - if (err < 0) - goto out_freeiov; - len = err; - if (uaddr != NULL) { - err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); + memset(&scm, 0, sizeof(scm)); + + lock_kernel(); + { + err = sock->ops->recvmsg(sock, &msg_sys, total_len, flags, &scm); + if (err < 0) + goto out_unlock_freeiov; + + len = err; + if (!msg_sys.msg_control) { + if (sock->passcred || scm.fp) + msg_sys.msg_flags |= MSG_CTRUNC; + if (scm.fp) + __scm_destroy(&scm); + } else { + /* + * If recvmsg processing itself placed some control messages into + * user space, it's is using 64-bit CMSG processing, so we need to + * fix it up before we tack on more stuff. + */ + if ((unsigned long) msg_sys.msg_control != cmsg_ptr) + cmsg32_recvmsg_fixup(&msg_sys, cmsg_ptr); + + /* Wheee... */ + if (sock->passcred) + put_cmsg32(&msg_sys, SOL_SOCKET, SCM_CREDENTIALS, + sizeof(scm.creds), &scm.creds); + if (scm.fp != NULL) + scm_detach_fds32(&msg_sys, &scm); + } + } + unlock_kernel(); + + if (uaddr != NULL) { + err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); if (err < 0) goto out_freeiov; } @@ -1393,20 +1864,23 @@ goto out_freeiov; err = len; -out_freeiov: + out_freeiov: if (iov != iovstack) sock_kfree_s(sock->sk, iov, iov_size); -out_put: + out_put: sockfd_put(sock); -out: + out: return err; + + out_unlock_freeiov: + goto out_freeiov; } /* Argument list sizes for sys_socketcall */ #define AL(x) ((x) * sizeof(u32)) -static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), - AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), - AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; +static const unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), + AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), + AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; #undef AL extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); @@ -1435,7 +1909,8 @@ extern asmlinkage long sys_shutdown(int fd, int how); extern asmlinkage long sys_listen(int fd, int backlog); -asmlinkage long sys32_socketcall(int call, u32 *args) +asmlinkage long +sys32_socketcall (int call, u32 *args) { int ret; u32 a[6]; @@ -1463,16 +1938,13 @@ ret = sys_listen(a0, a1); break; case SYS_ACCEPT: - ret = sys_accept(a0, (struct sockaddr *)A(a1), - (int *)A(a[2])); + ret = sys_accept(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); break; case SYS_GETSOCKNAME: - ret = sys_getsockname(a0, (struct sockaddr *)A(a1), - (int *)A(a[2])); + ret = sys_getsockname(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); break; case SYS_GETPEERNAME: - ret = sys_getpeername(a0, (struct sockaddr *)A(a1), - (int *)A(a[2])); + ret = sys_getpeername(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); break; case SYS_SOCKETPAIR: ret = sys_socketpair(a0, a1, a[2], (int *)A(a[3])); @@ -1500,12 +1972,10 @@ ret = sys_getsockopt(a0, a1, a[2], a[3], a[4]); break; case SYS_SENDMSG: - ret = sys32_sendmsg(a0, (struct msghdr32 *)A(a1), - a[2]); + ret = sys32_sendmsg(a0, (struct msghdr32 *) A(a1), a[2]); break; case SYS_RECVMSG: - ret = sys32_recvmsg(a0, (struct msghdr32 *)A(a1), - a[2]); + ret = sys32_recvmsg(a0, (struct msghdr32 *) A(a1), a[2]); break; default: ret = EINVAL; @@ -1522,15 +1992,28 @@ struct msgbuf32 { s32 mtype; char mtext[1]; }; -struct ipc_perm32 -{ - key_t key; - __kernel_uid_t32 uid; - __kernel_gid_t32 gid; - __kernel_uid_t32 cuid; - __kernel_gid_t32 cgid; +struct ipc_perm32 { + key_t key; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_uid_t32 cuid; + __kernel_gid_t32 cgid; + __kernel_mode_t32 mode; + unsigned short seq; +}; + +struct ipc64_perm32 { + key_t key; + __kernel_uid32_t32 uid; + __kernel_gid32_t32 gid; + __kernel_uid32_t32 cuid; + __kernel_gid32_t32 cgid; __kernel_mode_t32 mode; - unsigned short seq; + unsigned short __pad1; + unsigned short seq; + unsigned short __pad2; + unsigned int unused1; + unsigned int unused2; }; struct semid_ds32 { @@ -1544,8 +2027,18 @@ unsigned short sem_nsems; /* no. of semaphores in array */ }; -struct msqid_ds32 -{ +struct semid64_ds32 { + struct ipc64_perm32 sem_perm; + __kernel_time_t32 sem_otime; + unsigned int __unused1; + __kernel_time_t32 sem_ctime; + unsigned int __unused2; + unsigned int sem_nsems; + unsigned int __unused3; + unsigned int __unused4; +}; + +struct msqid_ds32 { struct ipc_perm32 msg_perm; u32 msg_first; u32 msg_last; @@ -1561,110 +2054,206 @@ __kernel_ipc_pid_t32 msg_lrpid; }; +struct msqid64_ds32 { + struct ipc64_perm32 msg_perm; + __kernel_time_t32 msg_stime; + unsigned int __unused1; + __kernel_time_t32 msg_rtime; + unsigned int __unused2; + __kernel_time_t32 msg_ctime; + unsigned int __unused3; + unsigned int msg_cbytes; + unsigned int msg_qnum; + unsigned int msg_qbytes; + __kernel_pid_t32 msg_lspid; + __kernel_pid_t32 msg_lrpid; + unsigned int __unused4; + unsigned int __unused5; +}; + struct shmid_ds32 { - struct ipc_perm32 shm_perm; - int shm_segsz; - __kernel_time_t32 shm_atime; - __kernel_time_t32 shm_dtime; - __kernel_time_t32 shm_ctime; - __kernel_ipc_pid_t32 shm_cpid; - __kernel_ipc_pid_t32 shm_lpid; - unsigned short shm_nattch; + struct ipc_perm32 shm_perm; + int shm_segsz; + __kernel_time_t32 shm_atime; + __kernel_time_t32 shm_dtime; + __kernel_time_t32 shm_ctime; + __kernel_ipc_pid_t32 shm_cpid; + __kernel_ipc_pid_t32 shm_lpid; + unsigned short shm_nattch; +}; + +struct shmid64_ds32 { + struct ipc64_perm shm_perm; + __kernel_size_t32 shm_segsz; + __kernel_time_t32 shm_atime; + unsigned int __unused1; + __kernel_time_t32 shm_dtime; + unsigned int __unused2; + __kernel_time_t32 shm_ctime; + unsigned int __unused3; + __kernel_pid_t32 shm_cpid; + __kernel_pid_t32 shm_lpid; + unsigned int shm_nattch; + unsigned int __unused4; + unsigned int __unused5; +}; + +struct shminfo64_32 { + unsigned int shmmax; + unsigned int shmmin; + unsigned int shmmni; + unsigned int shmseg; + unsigned int shmall; + unsigned int __unused1; + unsigned int __unused2; + unsigned int __unused3; + unsigned int __unused4; }; +struct shm_info32 { + int used_ids; + u32 shm_tot, shm_rss, shm_swp; + u32 swap_attempts, swap_successes; +}; + +struct ipc_kludge { + struct msgbuf *msgp; + long msgtyp; +}; + +#define SEMOP 1 +#define SEMGET 2 +#define SEMCTL 3 +#define MSGSND 11 +#define MSGRCV 12 +#define MSGGET 13 +#define MSGCTL 14 +#define SHMAT 21 +#define SHMDT 22 +#define SHMGET 23 +#define SHMCTL 24 + #define IPCOP_MASK(__x) (1UL << (__x)) static int -do_sys32_semctl(int first, int second, int third, void *uptr) +ipc_parse_version32 (int *cmd) +{ + if (*cmd & IPC_64) { + *cmd ^= IPC_64; + return IPC_64; + } else { + return IPC_OLD; + } +} + +static int +semctl32 (int first, int second, int third, void *uptr) { union semun fourth; u32 pad; int err = 0, err2; struct semid64_ds s; - struct semid_ds32 *usp; mm_segment_t old_fs; + int version = ipc_parse_version32(&third); if (!uptr) return -EINVAL; if (get_user(pad, (u32 *)uptr)) return -EFAULT; - if(third == SETVAL) + if (third == SETVAL) fourth.val = (int)pad; else fourth.__pad = (void *)A(pad); switch (third) { - - case IPC_INFO: - case IPC_RMID: - case IPC_SET: - case SEM_INFO: - case GETVAL: - case GETPID: - case GETNCNT: - case GETZCNT: - case GETALL: - case SETVAL: - case SETALL: - err = sys_semctl (first, second, third, fourth); + case IPC_INFO: + case IPC_RMID: + case IPC_SET: + case SEM_INFO: + case GETVAL: + case GETPID: + case GETNCNT: + case GETZCNT: + case GETALL: + case SETVAL: + case SETALL: + err = sys_semctl(first, second, third, fourth); break; - case IPC_STAT: - case SEM_STAT: - usp = (struct semid_ds32 *)A(pad); + case IPC_STAT: + case SEM_STAT: fourth.__pad = &s; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_semctl (first, second, third, fourth); - set_fs (old_fs); - err2 = put_user(s.sem_perm.key, &usp->sem_perm.key); - err2 |= __put_user(s.sem_perm.uid, &usp->sem_perm.uid); - err2 |= __put_user(s.sem_perm.gid, &usp->sem_perm.gid); - err2 |= __put_user(s.sem_perm.cuid, - &usp->sem_perm.cuid); - err2 |= __put_user (s.sem_perm.cgid, - &usp->sem_perm.cgid); - err2 |= __put_user (s.sem_perm.mode, - &usp->sem_perm.mode); - err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq); - err2 |= __put_user (s.sem_otime, &usp->sem_otime); - err2 |= __put_user (s.sem_ctime, &usp->sem_ctime); - err2 |= __put_user (s.sem_nsems, &usp->sem_nsems); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_semctl(first, second, third, fourth); + set_fs(old_fs); + + if (version == IPC_64) { + struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad); + + if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) { + err = -EFAULT; + break; + } + err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key); + err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid); + err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid); + err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid); + err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid); + err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode); + err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq); + err2 |= __put_user(s.sem_otime, &usp64->sem_otime); + err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime); + err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems); + } else { + struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad); + + if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) { + err = -EFAULT; + break; + } + err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key); + err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid); + err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid); + err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid); + err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid); + err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode); + err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq); + err2 |= __put_user(s.sem_otime, &usp32->sem_otime); + err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime); + err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems); + } if (err2) - err = -EFAULT; + err = -EFAULT; break; - } - return err; } static int do_sys32_msgsnd (int first, int second, int third, void *uptr) { - struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) - + 4, GFP_USER); + struct msgbuf *p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); struct msgbuf32 *up = (struct msgbuf32 *)uptr; mm_segment_t old_fs; int err; if (!p) return -ENOMEM; - err = get_user (p->mtype, &up->mtype); - err |= __copy_from_user (p->mtext, &up->mtext, second); + err = get_user(p->mtype, &up->mtype); + err |= copy_from_user(p->mtext, &up->mtext, second); if (err) goto out; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgsnd (first, p, second, third); - set_fs (old_fs); -out: - kfree (p); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgsnd(first, p, second, third); + set_fs(old_fs); + out: + kfree(p); return err; } static int -do_sys32_msgrcv (int first, int second, int msgtyp, int third, - int version, void *uptr) +do_sys32_msgrcv (int first, int second, int msgtyp, int third, int version, void *uptr) { struct msgbuf32 *up; struct msgbuf *p; @@ -1679,185 +2268,281 @@ if (!uptr) goto out; err = -EFAULT; - if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge))) + if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge))) goto out; uptr = (void *)A(ipck.msgp); msgtyp = ipck.msgtyp; } err = -ENOMEM; - p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER); + p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); if (!p) goto out; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgrcv (first, p, second + 4, msgtyp, third); - set_fs (old_fs); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgrcv(first, p, second + 4, msgtyp, third); + set_fs(old_fs); if (err < 0) goto free_then_out; up = (struct msgbuf32 *)uptr; - if (put_user (p->mtype, &up->mtype) || - __copy_to_user (&up->mtext, p->mtext, err)) + if (put_user(p->mtype, &up->mtype) || copy_to_user(&up->mtext, p->mtext, err)) err = -EFAULT; free_then_out: - kfree (p); + kfree(p); out: return err; } static int -do_sys32_msgctl (int first, int second, void *uptr) +msgctl32 (int first, int second, void *uptr) { int err = -EINVAL, err2; struct msqid_ds m; struct msqid64_ds m64; - struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; + struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr; + struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr; mm_segment_t old_fs; + int version = ipc_parse_version32(&second); switch (second) { - - case IPC_INFO: - case IPC_RMID: - case MSG_INFO: - err = sys_msgctl (first, second, (struct msqid_ds *)uptr); - break; - - case IPC_SET: - err = get_user (m.msg_perm.uid, &up->msg_perm.uid); - err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid); - err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode); - err |= __get_user (m.msg_qbytes, &up->msg_qbytes); + case IPC_INFO: + case IPC_RMID: + case MSG_INFO: + err = sys_msgctl(first, second, (struct msqid_ds *)uptr); + break; + + case IPC_SET: + if (version == IPC_64) { + err = get_user(m.msg_perm.uid, &up64->msg_perm.uid); + err |= get_user(m.msg_perm.gid, &up64->msg_perm.gid); + err |= get_user(m.msg_perm.mode, &up64->msg_perm.mode); + err |= get_user(m.msg_qbytes, &up64->msg_qbytes); + } else { + err = get_user(m.msg_perm.uid, &up32->msg_perm.uid); + err |= get_user(m.msg_perm.gid, &up32->msg_perm.gid); + err |= get_user(m.msg_perm.mode, &up32->msg_perm.mode); + err |= get_user(m.msg_qbytes, &up32->msg_qbytes); + } if (err) break; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgctl (first, second, &m); - set_fs (old_fs); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgctl(first, second, &m); + set_fs(old_fs); break; - case IPC_STAT: - case MSG_STAT: - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_msgctl (first, second, (void *) &m64); - set_fs (old_fs); - err2 = put_user (m64.msg_perm.key, &up->msg_perm.key); - err2 |= __put_user(m64.msg_perm.uid, &up->msg_perm.uid); - err2 |= __put_user(m64.msg_perm.gid, &up->msg_perm.gid); - err2 |= __put_user(m64.msg_perm.cuid, &up->msg_perm.cuid); - err2 |= __put_user(m64.msg_perm.cgid, &up->msg_perm.cgid); - err2 |= __put_user(m64.msg_perm.mode, &up->msg_perm.mode); - err2 |= __put_user(m64.msg_perm.seq, &up->msg_perm.seq); - err2 |= __put_user(m64.msg_stime, &up->msg_stime); - err2 |= __put_user(m64.msg_rtime, &up->msg_rtime); - err2 |= __put_user(m64.msg_ctime, &up->msg_ctime); - err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes); - err2 |= __put_user(m64.msg_qnum, &up->msg_qnum); - err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes); - err2 |= __put_user(m64.msg_lspid, &up->msg_lspid); - err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid); - if (err2) - err = -EFAULT; - break; + case IPC_STAT: + case MSG_STAT: + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_msgctl(first, second, (void *) &m64); + set_fs(old_fs); + if (version == IPC_64) { + if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) { + err = -EFAULT; + break; + } + err2 = __put_user(m64.msg_perm.key, &up64->msg_perm.key); + err2 |= __put_user(m64.msg_perm.uid, &up64->msg_perm.uid); + err2 |= __put_user(m64.msg_perm.gid, &up64->msg_perm.gid); + err2 |= __put_user(m64.msg_perm.cuid, &up64->msg_perm.cuid); + err2 |= __put_user(m64.msg_perm.cgid, &up64->msg_perm.cgid); + err2 |= __put_user(m64.msg_perm.mode, &up64->msg_perm.mode); + err2 |= __put_user(m64.msg_perm.seq, &up64->msg_perm.seq); + err2 |= __put_user(m64.msg_stime, &up64->msg_stime); + err2 |= __put_user(m64.msg_rtime, &up64->msg_rtime); + err2 |= __put_user(m64.msg_ctime, &up64->msg_ctime); + err2 |= __put_user(m64.msg_cbytes, &up64->msg_cbytes); + err2 |= __put_user(m64.msg_qnum, &up64->msg_qnum); + err2 |= __put_user(m64.msg_qbytes, &up64->msg_qbytes); + err2 |= __put_user(m64.msg_lspid, &up64->msg_lspid); + err2 |= __put_user(m64.msg_lrpid, &up64->msg_lrpid); + if (err2) + err = -EFAULT; + } else { + if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) { + err = -EFAULT; + break; + } + err2 = __put_user(m64.msg_perm.key, &up32->msg_perm.key); + err2 |= __put_user(m64.msg_perm.uid, &up32->msg_perm.uid); + err2 |= __put_user(m64.msg_perm.gid, &up32->msg_perm.gid); + err2 |= __put_user(m64.msg_perm.cuid, &up32->msg_perm.cuid); + err2 |= __put_user(m64.msg_perm.cgid, &up32->msg_perm.cgid); + err2 |= __put_user(m64.msg_perm.mode, &up32->msg_perm.mode); + err2 |= __put_user(m64.msg_perm.seq, &up32->msg_perm.seq); + err2 |= __put_user(m64.msg_stime, &up32->msg_stime); + err2 |= __put_user(m64.msg_rtime, &up32->msg_rtime); + err2 |= __put_user(m64.msg_ctime, &up32->msg_ctime); + err2 |= __put_user(m64.msg_cbytes, &up32->msg_cbytes); + err2 |= __put_user(m64.msg_qnum, &up32->msg_qnum); + err2 |= __put_user(m64.msg_qbytes, &up32->msg_qbytes); + err2 |= __put_user(m64.msg_lspid, &up32->msg_lspid); + err2 |= __put_user(m64.msg_lrpid, &up32->msg_lrpid); + if (err2) + err = -EFAULT; + } + break; } - return err; } static int -do_sys32_shmat (int first, int second, int third, int version, void *uptr) +shmat32 (int first, int second, int third, int version, void *uptr) { unsigned long raddr; u32 *uaddr = (u32 *)A((u32)third); int err; if (version == 1) - return -EINVAL; - err = sys_shmat (first, uptr, second, &raddr); + return -EINVAL; /* iBCS2 emulator entry point: unsupported */ + err = sys_shmat(first, uptr, second, &raddr); if (err) return err; return put_user(raddr, uaddr); } static int -do_sys32_shmctl (int first, int second, void *uptr) +shmctl32 (int first, int second, void *uptr) { int err = -EFAULT, err2; struct shmid_ds s; struct shmid64_ds s64; - struct shmid_ds32 *up = (struct shmid_ds32 *)uptr; + struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr; + struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr; mm_segment_t old_fs; - struct shm_info32 { - int used_ids; - u32 shm_tot, shm_rss, shm_swp; - u32 swap_attempts, swap_successes; - } *uip = (struct shm_info32 *)uptr; + struct shm_info32 *uip = (struct shm_info32 *)uptr; struct shm_info si; + int version = ipc_parse_version32(&second); + struct shminfo64 smi; + struct shminfo *usi32 = (struct shminfo *) uptr; + struct shminfo64_32 *usi64 = (struct shminfo64_32 *) uptr; switch (second) { + case IPC_INFO: + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, (struct shmid_ds *)&smi); + set_fs(old_fs); + + if (version == IPC_64) { + if (!access_ok(VERIFY_WRITE, usi64, sizeof(*usi64))) { + err = -EFAULT; + break; + } + err2 = __put_user(smi.shmmax, &usi64->shmmax); + err2 |= __put_user(smi.shmmin, &usi64->shmmin); + err2 |= __put_user(smi.shmmni, &usi64->shmmni); + err2 |= __put_user(smi.shmseg, &usi64->shmseg); + err2 |= __put_user(smi.shmall, &usi64->shmall); + } else { + if (!access_ok(VERIFY_WRITE, usi32, sizeof(*usi32))) { + err = -EFAULT; + break; + } + err2 = __put_user(smi.shmmax, &usi32->shmmax); + err2 |= __put_user(smi.shmmin, &usi32->shmmin); + err2 |= __put_user(smi.shmmni, &usi32->shmmni); + err2 |= __put_user(smi.shmseg, &usi32->shmseg); + err2 |= __put_user(smi.shmall, &usi32->shmall); + } + if (err2) + err = -EFAULT; + break; - case IPC_INFO: - case IPC_RMID: - case SHM_LOCK: - case SHM_UNLOCK: - err = sys_shmctl (first, second, (struct shmid_ds *)uptr); + case IPC_RMID: + case SHM_LOCK: + case SHM_UNLOCK: + err = sys_shmctl(first, second, (struct shmid_ds *)uptr); break; - case IPC_SET: - err = get_user (s.shm_perm.uid, &up->shm_perm.uid); - err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid); - err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode); + + case IPC_SET: + if (version == IPC_64) { + err = get_user(s.shm_perm.uid, &up64->shm_perm.uid); + err |= get_user(s.shm_perm.gid, &up64->shm_perm.gid); + err |= get_user(s.shm_perm.mode, &up64->shm_perm.mode); + } else { + err = get_user(s.shm_perm.uid, &up32->shm_perm.uid); + err |= get_user(s.shm_perm.gid, &up32->shm_perm.gid); + err |= get_user(s.shm_perm.mode, &up32->shm_perm.mode); + } if (err) break; - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_shmctl (first, second, &s); - set_fs (old_fs); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, &s); + set_fs(old_fs); break; - case IPC_STAT: - case SHM_STAT: - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_shmctl (first, second, (void *) &s64); - set_fs (old_fs); + case IPC_STAT: + case SHM_STAT: + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, (void *) &s64); + set_fs(old_fs); if (err < 0) break; - err2 = put_user (s64.shm_perm.key, &up->shm_perm.key); - err2 |= __put_user (s64.shm_perm.uid, &up->shm_perm.uid); - err2 |= __put_user (s64.shm_perm.gid, &up->shm_perm.gid); - err2 |= __put_user (s64.shm_perm.cuid, - &up->shm_perm.cuid); - err2 |= __put_user (s64.shm_perm.cgid, - &up->shm_perm.cgid); - err2 |= __put_user (s64.shm_perm.mode, - &up->shm_perm.mode); - err2 |= __put_user (s64.shm_perm.seq, &up->shm_perm.seq); - err2 |= __put_user (s64.shm_atime, &up->shm_atime); - err2 |= __put_user (s64.shm_dtime, &up->shm_dtime); - err2 |= __put_user (s64.shm_ctime, &up->shm_ctime); - err2 |= __put_user (s64.shm_segsz, &up->shm_segsz); - err2 |= __put_user (s64.shm_nattch, &up->shm_nattch); - err2 |= __put_user (s64.shm_cpid, &up->shm_cpid); - err2 |= __put_user (s64.shm_lpid, &up->shm_lpid); + if (version == IPC_64) { + if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) { + err = -EFAULT; + break; + } + err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key); + err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid); + err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid); + err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid); + err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid); + err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode); + err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq); + err2 |= __put_user(s64.shm_atime, &up64->shm_atime); + err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime); + err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime); + err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz); + err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch); + err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid); + err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid); + } else { + if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) { + err = -EFAULT; + break; + } + err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key); + err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid); + err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid); + err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid); + err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid); + err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode); + err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq); + err2 |= __put_user(s64.shm_atime, &up32->shm_atime); + err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime); + err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime); + err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz); + err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch); + err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid); + err2 |= __put_user(s64.shm_lpid, &up32->shm_lpid); + } if (err2) err = -EFAULT; break; - case SHM_INFO: - old_fs = get_fs (); - set_fs (KERNEL_DS); - err = sys_shmctl (first, second, (void *)&si); - set_fs (old_fs); + case SHM_INFO: + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_shmctl(first, second, (void *)&si); + set_fs(old_fs); if (err < 0) break; - err2 = put_user (si.used_ids, &uip->used_ids); - err2 |= __put_user (si.shm_tot, &uip->shm_tot); - err2 |= __put_user (si.shm_rss, &uip->shm_rss); - err2 |= __put_user (si.shm_swp, &uip->shm_swp); - err2 |= __put_user (si.swap_attempts, - &uip->swap_attempts); - err2 |= __put_user (si.swap_successes, - &uip->swap_successes); + + if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip))) { + err = -EFAULT; + break; + } + err2 = __put_user(si.used_ids, &uip->used_ids); + err2 |= __put_user(si.shm_tot, &uip->shm_tot); + err2 |= __put_user(si.shm_rss, &uip->shm_rss); + err2 |= __put_user(si.shm_swp, &uip->shm_swp); + err2 |= __put_user(si.swap_attempts, &uip->swap_attempts); + err2 |= __put_user(si.swap_successes, &uip->swap_successes); if (err2) err = -EFAULT; break; @@ -1869,59 +2554,42 @@ asmlinkage long sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) { - int version, err; + int version; version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; switch (call) { - - case SEMOP: + case SEMOP: /* struct sembuf is the same on 32 and 64bit :)) */ - err = sys_semop (first, (struct sembuf *)AA(ptr), - second); - break; - case SEMGET: - err = sys_semget (first, second, third); - break; - case SEMCTL: - err = do_sys32_semctl (first, second, third, - (void *)AA(ptr)); - break; - - case MSGSND: - err = do_sys32_msgsnd (first, second, third, - (void *)AA(ptr)); - break; - case MSGRCV: - err = do_sys32_msgrcv (first, second, fifth, third, - version, (void *)AA(ptr)); - break; - case MSGGET: - err = sys_msgget ((key_t) first, second); - break; - case MSGCTL: - err = do_sys32_msgctl (first, second, (void *)AA(ptr)); - break; + return sys_semop(first, (struct sembuf *)AA(ptr), second); + case SEMGET: + return sys_semget(first, second, third); + case SEMCTL: + return semctl32(first, second, third, (void *)AA(ptr)); + + case MSGSND: + return do_sys32_msgsnd(first, second, third, (void *)AA(ptr)); + case MSGRCV: + return do_sys32_msgrcv(first, second, fifth, third, version, (void *)AA(ptr)); + case MSGGET: + return sys_msgget((key_t) first, second); + case MSGCTL: + return msgctl32(first, second, (void *)AA(ptr)); + + case SHMAT: + return shmat32(first, second, third, version, (void *)AA(ptr)); + break; + case SHMDT: + return sys_shmdt((char *)AA(ptr)); + case SHMGET: + return sys_shmget(first, second, third); + case SHMCTL: + return shmctl32(first, second, (void *)AA(ptr)); - case SHMAT: - err = do_sys32_shmat (first, second, third, version, (void *)AA(ptr)); - break; - case SHMDT: - err = sys_shmdt ((char *)AA(ptr)); - break; - case SHMGET: - err = sys_shmget (first, second, third); - break; - case SHMCTL: - err = do_sys32_shmctl (first, second, (void *)AA(ptr)); - break; - default: - err = -EINVAL; - break; + default: + return -EINVAL; } - - return err; } /* @@ -1929,7 +2597,8 @@ * sys_gettimeofday(). IA64 did this but i386 Linux did not * so we have to implement this system call here. */ -asmlinkage long sys32_time(int * tloc) +asmlinkage long +sys32_time (int *tloc) { int i; @@ -1937,7 +2606,7 @@ stuff it to user space. No side effects */ i = CURRENT_TIME; if (tloc) { - if (put_user(i,tloc)) + if (put_user(i, tloc)) i = -EFAULT; } return i; @@ -1967,7 +2636,10 @@ { int err; - err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); + if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru))) + return -EFAULT; + + err = __put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec); @@ -1989,8 +2661,7 @@ } asmlinkage long -sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, - struct rusage32 *ru) +sys32_wait4 (int pid, unsigned int *stat_addr, int options, struct rusage32 *ru) { if (!ru) return sys_wait4(pid, stat_addr, options, NULL); @@ -2000,37 +2671,38 @@ unsigned int status; mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); - set_fs (old_fs); - if (put_rusage (ru, &r)) return -EFAULT; - if (stat_addr && put_user (status, stat_addr)) + set_fs(old_fs); + if (put_rusage(ru, &r)) + return -EFAULT; + if (stat_addr && put_user(status, stat_addr)) return -EFAULT; return ret; } } asmlinkage long -sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options) +sys32_waitpid (int pid, unsigned int *stat_addr, int options) { return sys32_wait4(pid, stat_addr, options, NULL); } -extern asmlinkage long -sys_getrusage(int who, struct rusage *ru); +extern asmlinkage long sys_getrusage (int who, struct rusage *ru); asmlinkage long -sys32_getrusage(int who, struct rusage32 *ru) +sys32_getrusage (int who, struct rusage32 *ru) { struct rusage r; int ret; mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_getrusage(who, &r); - set_fs (old_fs); - if (put_rusage (ru, &r)) return -EFAULT; + set_fs(old_fs); + if (put_rusage (ru, &r)) + return -EFAULT; return ret; } @@ -2041,41 +2713,41 @@ __kernel_clock_t32 tms_cstime; }; -extern asmlinkage long sys_times(struct tms * tbuf); +extern asmlinkage long sys_times (struct tms * tbuf); asmlinkage long -sys32_times(struct tms32 *tbuf) +sys32_times (struct tms32 *tbuf) { + mm_segment_t old_fs = get_fs(); struct tms t; long ret; - mm_segment_t old_fs = get_fs (); int err; - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); ret = sys_times(tbuf ? &t : NULL); - set_fs (old_fs); + set_fs(old_fs); if (tbuf) { err = put_user (IA32_TICK(t.tms_utime), &tbuf->tms_utime); - err |= __put_user (IA32_TICK(t.tms_stime), &tbuf->tms_stime); - err |= __put_user (IA32_TICK(t.tms_cutime), &tbuf->tms_cutime); - err |= __put_user (IA32_TICK(t.tms_cstime), &tbuf->tms_cstime); + err |= put_user (IA32_TICK(t.tms_stime), &tbuf->tms_stime); + err |= put_user (IA32_TICK(t.tms_cutime), &tbuf->tms_cutime); + err |= put_user (IA32_TICK(t.tms_cstime), &tbuf->tms_cstime); if (err) ret = -EFAULT; } return IA32_TICK(ret); } -unsigned int +static unsigned int ia32_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr, unsigned int *val) { size_t copied; unsigned int ret; copied = access_process_vm(child, addr, val, sizeof(*val), 0); - return(copied != sizeof(ret) ? -EIO : 0); + return (copied != sizeof(ret)) ? -EIO : 0; } -unsigned int +static unsigned int ia32_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr, unsigned int val) { @@ -2105,135 +2777,87 @@ #define PT_UESP 15 #define PT_SS 16 -unsigned int -getreg(struct task_struct *child, int regno) +static unsigned int +getreg (struct task_struct *child, int regno) { struct pt_regs *child_regs; child_regs = ia64_task_regs(child); switch (regno / sizeof(int)) { - - case PT_EBX: - return(child_regs->r11); - case PT_ECX: - return(child_regs->r9); - case PT_EDX: - return(child_regs->r10); - case PT_ESI: - return(child_regs->r14); - case PT_EDI: - return(child_regs->r15); - case PT_EBP: - return(child_regs->r13); - case PT_EAX: - case PT_ORIG_EAX: - return(child_regs->r8); - case PT_EIP: - return(child_regs->cr_iip); - case PT_UESP: - return(child_regs->r12); - case PT_EFL: - return(child->thread.eflag); - case PT_DS: - case PT_ES: - case PT_FS: - case PT_GS: - case PT_SS: - return((unsigned int)__USER_DS); - case PT_CS: - return((unsigned int)__USER_CS); - default: - printk(KERN_ERR "getregs:unknown register %d\n", regno); + case PT_EBX: return child_regs->r11; + case PT_ECX: return child_regs->r9; + case PT_EDX: return child_regs->r10; + case PT_ESI: return child_regs->r14; + case PT_EDI: return child_regs->r15; + case PT_EBP: return child_regs->r13; + case PT_EAX: return child_regs->r8; + case PT_ORIG_EAX: return child_regs->r1; /* see dispatch_to_ia32_handler() */ + case PT_EIP: return child_regs->cr_iip; + case PT_UESP: return child_regs->r12; + case PT_EFL: return child->thread.eflag; + case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS: + return __USER_DS; + case PT_CS: return __USER_CS; + default: + printk(KERN_ERR "ia32.getreg(): unknown register %d\n", regno); break; - } - return(0); + return 0; } -void -putreg(struct task_struct *child, int regno, unsigned int value) +static void +putreg (struct task_struct *child, int regno, unsigned int value) { struct pt_regs *child_regs; child_regs = ia64_task_regs(child); switch (regno / sizeof(int)) { - - case PT_EBX: - child_regs->r11 = value; - break; - case PT_ECX: - child_regs->r9 = value; - break; - case PT_EDX: - child_regs->r10 = value; - break; - case PT_ESI: - child_regs->r14 = value; - break; - case PT_EDI: - child_regs->r15 = value; - break; - case PT_EBP: - child_regs->r13 = value; - break; - case PT_EAX: - case PT_ORIG_EAX: - child_regs->r8 = value; - break; - case PT_EIP: - child_regs->cr_iip = value; - break; - case PT_UESP: - child_regs->r12 = value; - break; - case PT_EFL: - child->thread.eflag = value; - break; - case PT_DS: - case PT_ES: - case PT_FS: - case PT_GS: - case PT_SS: + case PT_EBX: child_regs->r11 = value; break; + case PT_ECX: child_regs->r9 = value; break; + case PT_EDX: child_regs->r10 = value; break; + case PT_ESI: child_regs->r14 = value; break; + case PT_EDI: child_regs->r15 = value; break; + case PT_EBP: child_regs->r13 = value; break; + case PT_EAX: child_regs->r8 = value; break; + case PT_ORIG_EAX: child_regs->r1 = value; break; + case PT_EIP: child_regs->cr_iip = value; break; + case PT_UESP: child_regs->r12 = value; break; + case PT_EFL: child->thread.eflag = value; break; + case PT_DS: case PT_ES: case PT_FS: case PT_GS: case PT_SS: if (value != __USER_DS) - printk(KERN_ERR "setregs:try to set invalid segment register %d = %x\n", + printk(KERN_ERR + "ia32.putreg: attempt to set invalid segment register %d = %x\n", regno, value); break; - case PT_CS: + case PT_CS: if (value != __USER_CS) - printk(KERN_ERR "setregs:try to set invalid segment register %d = %x\n", + printk(KERN_ERR + "ia32.putreg: attempt to to set invalid segment register %d = %x\n", regno, value); break; - default: - printk(KERN_ERR "getregs:unknown register %d\n", regno); + default: + printk(KERN_ERR "ia32.putreg: unknown register %d\n", regno); break; - } } static inline void -ia32f2ia64f(void *dst, void *src) +ia32f2ia64f (void *dst, void *src) { - - __asm__ ("ldfe f6=[%1] ;;\n\t" - "stf.spill [%0]=f6" - : - : "r"(dst), "r"(src)); + asm volatile ("ldfe f6=[%1];; stf.spill [%0]=f6" :: "r"(dst), "r"(src) : "memory"); return; } static inline void -ia64f2ia32f(void *dst, void *src) +ia64f2ia32f (void *dst, void *src) { - - __asm__ ("ldf.fill f6=[%1] ;;\n\t" - "stfe [%0]=f6" - : - : "r"(dst), "r"(src)); + asm volatile ("ldf.fill f6=[%1];; stfe [%0]=f6" :: "r"(dst), "r"(src) : "memory"); return; } -void -put_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos) +static void +put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, + int tos) { struct _fpreg_ia32 *f; char buf[32]; @@ -2242,62 +2866,59 @@ if ((regno += tos) >= 8) regno -= 8; switch (regno) { - - case 0: + case 0: ia64f2ia32f(f, &ptp->f8); break; - case 1: + case 1: ia64f2ia32f(f, &ptp->f9); break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: ia64f2ia32f(f, &swp->f10 + (regno - 2)); break; - } - __copy_to_user(reg, f, sizeof(*reg)); + copy_to_user(reg, f, sizeof(*reg)); } -void -get_fpreg(int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, int tos) +static void +get_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp, + int tos) { if ((regno += tos) >= 8) regno -= 8; switch (regno) { - - case 0: - __copy_from_user(&ptp->f8, reg, sizeof(*reg)); + case 0: + copy_from_user(&ptp->f8, reg, sizeof(*reg)); break; - case 1: - __copy_from_user(&ptp->f9, reg, sizeof(*reg)); + case 1: + copy_from_user(&ptp->f9, reg, sizeof(*reg)); break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - __copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg)); + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg)); break; - } return; } -int -save_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save) +static int +save_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save) { struct switch_stack *swp; struct pt_regs *ptp; int i, tos; if (!access_ok(VERIFY_WRITE, save, sizeof(*save))) - return(-EIO); + return -EIO; __put_user(tsk->thread.fcr, &save->cw); __put_user(tsk->thread.fsr, &save->sw); __put_user(tsk->thread.fsr >> 32, &save->tag); @@ -2313,11 +2934,11 @@ tos = (tsk->thread.fsr >> 11) & 3; for (i = 0; i < 8; i++) put_fpreg(i, &save->_st[i], ptp, swp, tos); - return(0); + return 0; } -int -restore_ia32_fpstate(struct task_struct *tsk, struct _fpstate_ia32 *save) +static int +restore_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save) { struct switch_stack *swp; struct pt_regs *ptp; @@ -2340,10 +2961,11 @@ tos = (tsk->thread.fsr >> 11) & 3; for (i = 0; i < 8; i++) get_fpreg(i, &save->_st[i], ptp, swp, tos); - return(ret ? -EFAULT : 0); + return ret ? -EFAULT : 0; } -asmlinkage long sys_ptrace(long, pid_t, unsigned long, unsigned long, long, long, long, long, long); +extern asmlinkage long sys_ptrace (long, pid_t, unsigned long, unsigned long, long, long, long, + long, long); /* * Note that the IA32 version of `ptrace' calls the IA64 routine for @@ -2358,13 +2980,12 @@ { struct pt_regs *regs = (struct pt_regs *) &stack; struct task_struct *child; + unsigned int value, tmp; long i, ret; - unsigned int value; lock_kernel(); if (request == PTRACE_TRACEME) { - ret = sys_ptrace(request, pid, addr, data, - arg4, arg5, arg6, arg7, stack); + ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); goto out; } @@ -2379,8 +3000,7 @@ goto out; if (request == PTRACE_ATTACH) { - ret = sys_ptrace(request, pid, addr, data, - arg4, arg5, arg6, arg7, stack); + ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); goto out; } ret = -ESRCH; @@ -2398,21 +3018,32 @@ case PTRACE_PEEKDATA: /* read word at location addr */ ret = ia32_peek(regs, child, addr, &value); if (ret == 0) - ret = put_user(value, (unsigned int *)A(data)); + ret = put_user(value, (unsigned int *) A(data)); else ret = -EIO; goto out; case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ - ret = ia32_poke(regs, child, addr, (unsigned int)data); + ret = ia32_poke(regs, child, addr, data); goto out; case PTRACE_PEEKUSR: /* read word at addr in USER area */ - ret = 0; + ret = -EIO; + if ((addr & 3) || addr > 17*sizeof(int)) + break; + + tmp = getreg(child, addr); + if (!put_user(tmp, (unsigned int *) A(data))) + ret = 0; break; case PTRACE_POKEUSR: /* write word at addr in USER area */ + ret = -EIO; + if ((addr & 3) || addr > 17*sizeof(int)) + break; + + putreg(child, addr, data); ret = 0; break; @@ -2421,28 +3052,25 @@ ret = -EIO; break; } - for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) { - __put_user(getreg(child, i), (unsigned int *) A(data)); + for (i = 0; i < 17*sizeof(int); i += sizeof(int) ) { + put_user(getreg(child, i), (unsigned int *) A(data)); data += sizeof(int); } ret = 0; break; case IA32_PTRACE_SETREGS: - { - unsigned int tmp; if (!access_ok(VERIFY_READ, (int *) A(data), 17*sizeof(int))) { ret = -EIO; break; } - for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) { - __get_user(tmp, (unsigned int *) A(data)); + for (i = 0; i < 17*sizeof(int); i += sizeof(int) ) { + get_user(tmp, (unsigned int *) A(data)); putreg(child, i, tmp); data += sizeof(int); } ret = 0; break; - } case IA32_PTRACE_GETFPREGS: ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data)); @@ -2457,10 +3085,8 @@ case PTRACE_KILL: case PTRACE_SINGLESTEP: /* execute chile for one instruction */ case PTRACE_DETACH: /* detach a process */ - unlock_kernel(); - ret = sys_ptrace(request, pid, addr, data, - arg4, arg5, arg6, arg7, stack); - return(ret); + ret = sys_ptrace(request, pid, addr, data, arg4, arg5, arg6, arg7, stack); + break; default: ret = -EIO; @@ -2477,7 +3103,10 @@ { int err; - err = get_user(kfl->l_type, &ufl->l_type); + if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl))) + return -EFAULT; + + err = __get_user(kfl->l_type, &ufl->l_type); err |= __get_user(kfl->l_whence, &ufl->l_whence); err |= __get_user(kfl->l_start, &ufl->l_start); err |= __get_user(kfl->l_len, &ufl->l_len); @@ -2490,6 +3119,9 @@ { int err; + if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl))) + return -EFAULT; + err = __put_user(kfl->l_type, &ufl->l_type); err |= __put_user(kfl->l_whence, &ufl->l_whence); err |= __put_user(kfl->l_start, &ufl->l_start); @@ -2498,71 +3130,43 @@ return err; } -extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, - unsigned long arg); +extern asmlinkage long sys_fcntl (unsigned int fd, unsigned int cmd, unsigned long arg); asmlinkage long -sys32_fcntl(unsigned int fd, unsigned int cmd, int arg) +sys32_fcntl (unsigned int fd, unsigned int cmd, unsigned int arg) { - struct flock f; mm_segment_t old_fs; + struct flock f; long ret; switch (cmd) { - case F_GETLK: - case F_SETLK: - case F_SETLKW: - if(get_flock32(&f, (struct flock32 *)((long)arg))) + case F_GETLK: + case F_SETLK: + case F_SETLKW: + if (get_flock32(&f, (struct flock32 *) A(arg))) return -EFAULT; old_fs = get_fs(); set_fs(KERNEL_DS); - ret = sys_fcntl(fd, cmd, (unsigned long)&f); + ret = sys_fcntl(fd, cmd, (unsigned long) &f); set_fs(old_fs); - if(cmd == F_GETLK && put_flock32(&f, (struct flock32 *)((long)arg))) + if (cmd == F_GETLK && put_flock32(&f, (struct flock32 *) A(arg))) return -EFAULT; return ret; - default: + + default: /* * `sys_fcntl' lies about arg, for the F_SETOWN * sub-function arg can have a negative value. */ - return sys_fcntl(fd, cmd, (unsigned long)((long)arg)); - } -} - -asmlinkage long -sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset32_t mask; - - ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); - ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); - ret |= __get_user(mask, &act->sa_mask); - if (ret) - return ret; - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); - ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + return sys_fcntl(fd, cmd, arg); } - - return ret; } asmlinkage long sys_ni_syscall(void); asmlinkage long -sys32_ni_syscall(int dummy0, int dummy1, int dummy2, int dummy3, - int dummy4, int dummy5, int dummy6, int dummy7, int stack) +sys32_ni_syscall (int dummy0, int dummy1, int dummy2, int dummy3, int dummy4, int dummy5, + int dummy6, int dummy7, int stack) { struct pt_regs *regs = (struct pt_regs *)&stack; @@ -2577,7 +3181,7 @@ #define IOLEN ((65536 / 4) * 4096) asmlinkage long -sys_iopl (int level) +sys32_iopl (int level) { extern unsigned long ia64_iobase; int fd; @@ -2612,9 +3216,8 @@ up_write(¤t->mm->mmap_sem); if (addr >= 0) { - ia64_set_kr(IA64_KR_IO_BASE, addr); old = (old & ~0x3000) | (level << 12); - __asm__ __volatile__("mov ar.eflag=%0 ;;" :: "r"(old)); + asm volatile ("mov ar.eflag=%0;;" :: "r"(old)); } fput(file); @@ -2623,7 +3226,7 @@ } asmlinkage long -sys_ioperm (unsigned int from, unsigned int num, int on) +sys32_ioperm (unsigned int from, unsigned int num, int on) { /* @@ -2636,7 +3239,7 @@ * XXX proper ioperm() support should be emulated by * manipulating the page protections... */ - return sys_iopl(3); + return sys32_iopl(3); } typedef struct { @@ -2646,10 +3249,8 @@ } ia32_stack_t; asmlinkage long -sys32_sigaltstack (const ia32_stack_t *uss32, ia32_stack_t *uoss32, -long arg2, long arg3, long arg4, -long arg5, long arg6, long arg7, -long stack) +sys32_sigaltstack (ia32_stack_t *uss32, ia32_stack_t *uoss32, + long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *pt = (struct pt_regs *) &stack; stack_t uss, uoss; @@ -2658,8 +3259,8 @@ mm_segment_t old_fs = get_fs(); if (uss32) - if (copy_from_user(&buf32, (void *)A(uss32), sizeof(ia32_stack_t))) - return(-EFAULT); + if (copy_from_user(&buf32, uss32, sizeof(ia32_stack_t))) + return -EFAULT; uss.ss_sp = (void *) (long) buf32.ss_sp; uss.ss_flags = buf32.ss_flags; uss.ss_size = buf32.ss_size; @@ -2672,34 +3273,34 @@ buf32.ss_sp = (long) uoss.ss_sp; buf32.ss_flags = uoss.ss_flags; buf32.ss_size = uoss.ss_size; - if (copy_to_user((void*)A(uoss32), &buf32, sizeof(ia32_stack_t))) - return(-EFAULT); + if (copy_to_user(uoss32, &buf32, sizeof(ia32_stack_t))) + return -EFAULT; } - return(ret); + return ret; } asmlinkage int -sys_pause (void) +sys32_pause (void) { current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND; } -asmlinkage long sys_msync(unsigned long start, size_t len, int flags); +asmlinkage long sys_msync (unsigned long start, size_t len, int flags); asmlinkage int -sys32_msync(unsigned int start, unsigned int len, int flags) +sys32_msync (unsigned int start, unsigned int len, int flags) { unsigned int addr; if (OFFSET4K(start)) return -EINVAL; - addr = start & PAGE_MASK; - return(sys_msync(addr, len + (start - addr), flags)); + addr = PAGE_START(start); + return sys_msync(addr, len + (start - addr), flags); } -struct sysctl_ia32 { +struct sysctl32 { unsigned int name; int nlen; unsigned int oldval; @@ -2712,16 +3313,16 @@ extern asmlinkage long sys_sysctl(struct __sysctl_args *args); asmlinkage long -sys32_sysctl(struct sysctl_ia32 *args32) +sys32_sysctl (struct sysctl32 *args) { - struct sysctl_ia32 a32; + struct sysctl32 a32; mm_segment_t old_fs = get_fs (); void *oldvalp, *newvalp; size_t oldlen; int *namep; long ret; - if (copy_from_user(&a32, args32, sizeof (a32))) + if (copy_from_user(&a32, args, sizeof(a32))) return -EFAULT; /* @@ -2754,7 +3355,7 @@ } asmlinkage long -sys32_newuname(struct new_utsname * name) +sys32_newuname (struct new_utsname *name) { extern asmlinkage long sys_newuname(struct new_utsname * name); int ret = sys_newuname(name); @@ -2765,10 +3366,10 @@ return ret; } -extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +extern asmlinkage long sys_getresuid (uid_t *ruid, uid_t *euid, uid_t *suid); asmlinkage long -sys32_getresuid (u16 *ruid, u16 *euid, u16 *suid) +sys32_getresuid16 (u16 *ruid, u16 *euid, u16 *suid) { uid_t a, b, c; int ret; @@ -2786,7 +3387,7 @@ extern asmlinkage long sys_getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid); asmlinkage long -sys32_getresgid(u16 *rgid, u16 *egid, u16 *sgid) +sys32_getresgid16 (u16 *rgid, u16 *egid, u16 *sgid) { gid_t a, b, c; int ret; @@ -2796,15 +3397,13 @@ ret = sys_getresgid(&a, &b, &c); set_fs(old_fs); - if (!ret) { - ret = put_user(a, rgid); - ret |= put_user(b, egid); - ret |= put_user(c, sgid); - } - return ret; + if (ret) + return ret; + + return put_user(a, rgid) | put_user(b, egid) | put_user(c, sgid); } -int +asmlinkage long sys32_lseek (unsigned int fd, int offset, unsigned int whence) { extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin); @@ -2813,36 +3412,272 @@ return sys_lseek(fd, offset, whence); } -#ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ +extern asmlinkage long sys_getgroups (int gidsetsize, gid_t *grouplist); -/* In order to reduce some races, while at the same time doing additional - * checking and hopefully speeding things up, we copy filenames to the - * kernel data space before using them.. - * - * POSIX.1 2.4: an empty pathname is invalid (ENOENT). - */ -static inline int -do_getname32(const char *filename, char *page) +asmlinkage long +sys32_getgroups16 (int gidsetsize, short *grouplist) { - int retval; + mm_segment_t old_fs = get_fs(); + gid_t gl[NGROUPS]; + int ret, i; - /* 32bit pointer will be always far below TASK_SIZE :)) */ - retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE); - if (retval > 0) { - if (retval < PAGE_SIZE) - return 0; - return -ENAMETOOLONG; - } else if (!retval) - retval = -ENOENT; - return retval; + set_fs(KERNEL_DS); + ret = sys_getgroups(gidsetsize, gl); + set_fs(old_fs); + + if (gidsetsize && ret > 0 && ret <= NGROUPS) + for (i = 0; i < ret; i++, grouplist++) + if (put_user(gl[i], grouplist)) + return -EFAULT; + return ret; } -char * -getname32(const char *filename) +extern asmlinkage long sys_setgroups (int gidsetsize, gid_t *grouplist); + +asmlinkage long +sys32_setgroups16 (int gidsetsize, short *grouplist) { - char *tmp, *result; + mm_segment_t old_fs = get_fs(); + gid_t gl[NGROUPS]; + int ret, i; - result = ERR_PTR(-ENOMEM); + if ((unsigned) gidsetsize > NGROUPS) + return -EINVAL; + for (i = 0; i < gidsetsize; i++, grouplist++) + if (get_user(gl[i], grouplist)) + return -EFAULT; + set_fs(KERNEL_DS); + ret = sys_setgroups(gidsetsize, gl); + set_fs(old_fs); + return ret; +} + +/* + * Unfortunately, the x86 compiler aligns variables of type "long long" to a 4 byte boundary + * only, which means that the x86 version of "struct flock64" doesn't match the ia64 version + * of struct flock. + */ + +static inline long +ia32_put_flock (struct flock *l, unsigned long addr) +{ + return (put_user(l->l_type, (short *) addr) + | put_user(l->l_whence, (short *) (addr + 2)) + | put_user(l->l_start, (long *) (addr + 4)) + | put_user(l->l_len, (long *) (addr + 12)) + | put_user(l->l_pid, (int *) (addr + 20))); +} + +static inline long +ia32_get_flock (struct flock *l, unsigned long addr) +{ + unsigned int start_lo, start_hi, len_lo, len_hi; + int err = (get_user(l->l_type, (short *) addr) + | get_user(l->l_whence, (short *) (addr + 2)) + | get_user(start_lo, (int *) (addr + 4)) + | get_user(start_hi, (int *) (addr + 8)) + | get_user(len_lo, (int *) (addr + 12)) + | get_user(len_hi, (int *) (addr + 16)) + | get_user(l->l_pid, (int *) (addr + 20))); + l->l_start = ((unsigned long) start_hi << 32) | start_lo; + l->l_len = ((unsigned long) len_hi << 32) | len_lo; + return err; +} + +asmlinkage long +sys32_fcntl64 (unsigned int fd, unsigned int cmd, unsigned int arg) +{ + mm_segment_t old_fs; + struct flock f; + long ret; + + switch (cmd) { + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: + if (ia32_get_flock(&f, arg)) + return -EFAULT; + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_fcntl(fd, cmd, (unsigned long) &f); + set_fs(old_fs); + if (cmd == F_GETLK && ia32_put_flock(&f, arg)) + return -EFAULT; + break; + + default: + ret = sys32_fcntl(fd, cmd, arg); + break; + } + return ret; +} + +asmlinkage long +sys32_truncate64 (unsigned int path, unsigned int len_lo, unsigned int len_hi) +{ + extern asmlinkage long sys_truncate (const char *path, unsigned long length); + + return sys_truncate((const char *) A(path), ((unsigned long) len_hi << 32) | len_lo); +} + +asmlinkage long +sys32_ftruncate64 (int fd, unsigned int len_lo, unsigned int len_hi) +{ + extern asmlinkage long sys_ftruncate (int fd, unsigned long length); + + return sys_ftruncate(fd, ((unsigned long) len_hi << 32) | len_lo); +} + +static int +putstat64 (struct stat64 *ubuf, struct stat *kbuf) +{ + int err; + + if (clear_user(ubuf, sizeof(*ubuf))) + return 1; + + err = __put_user(kbuf->st_dev, &ubuf->st_dev); + err |= __put_user(kbuf->st_ino, &ubuf->__st_ino); + err |= __put_user(kbuf->st_ino, &ubuf->st_ino_lo); + err |= __put_user(kbuf->st_ino >> 32, &ubuf->st_ino_hi); + err |= __put_user(kbuf->st_mode, &ubuf->st_mode); + err |= __put_user(kbuf->st_nlink, &ubuf->st_nlink); + err |= __put_user(kbuf->st_uid, &ubuf->st_uid); + err |= __put_user(kbuf->st_gid, &ubuf->st_gid); + err |= __put_user(kbuf->st_rdev, &ubuf->st_rdev); + err |= __put_user(kbuf->st_size, &ubuf->st_size_lo); + err |= __put_user((kbuf->st_size >> 32), &ubuf->st_size_hi); + err |= __put_user(kbuf->st_atime, &ubuf->st_atime); + err |= __put_user(kbuf->st_mtime, &ubuf->st_mtime); + err |= __put_user(kbuf->st_ctime, &ubuf->st_ctime); + err |= __put_user(kbuf->st_blksize, &ubuf->st_blksize); + err |= __put_user(kbuf->st_blocks, &ubuf->st_blocks); + return err; +} + +asmlinkage long +sys32_stat64 (char *filename, struct stat64 *statbuf) +{ + mm_segment_t old_fs = get_fs(); + struct stat s; + long ret; + + set_fs(KERNEL_DS); + ret = sys_newstat(filename, &s); + set_fs(old_fs); + if (putstat64(statbuf, &s)) + return -EFAULT; + return ret; +} + +asmlinkage long +sys32_lstat64 (char *filename, struct stat64 *statbuf) +{ + mm_segment_t old_fs = get_fs(); + struct stat s; + long ret; + + set_fs(KERNEL_DS); + ret = sys_newlstat(filename, &s); + set_fs(old_fs); + if (putstat64(statbuf, &s)) + return -EFAULT; + return ret; +} + +asmlinkage long +sys32_fstat64 (unsigned int fd, struct stat64 *statbuf) +{ + mm_segment_t old_fs = get_fs(); + struct stat s; + long ret; + + set_fs(KERNEL_DS); + ret = sys_newfstat(fd, &s); + set_fs(old_fs); + if (putstat64(statbuf, &s)) + return -EFAULT; + return ret; +} + +asmlinkage long +sys32_sigpending (unsigned int *set) +{ + return do_sigpending(set, sizeof(*set)); +} + +struct sysinfo32 { + s32 uptime; + u32 loads[3]; + u32 totalram; + u32 freeram; + u32 sharedram; + u32 bufferram; + u32 totalswap; + u32 freeswap; + unsigned short procs; + char _f[22]; +}; + +asmlinkage long +sys32_sysinfo (struct sysinfo32 *info) +{ + extern asmlinkage long sys_sysinfo (struct sysinfo *); + mm_segment_t old_fs = get_fs(); + struct sysinfo s; + long ret, err; + + set_fs(KERNEL_DS); + ret = sys_sysinfo(&s); + set_fs(old_fs); + + if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) + return -EFAULT; + + err = __put_user(s.uptime, &info->uptime); + err |= __put_user(s.loads[0], &info->loads[0]); + err |= __put_user(s.loads[1], &info->loads[1]); + err |= __put_user(s.loads[2], &info->loads[2]); + err |= __put_user(s.totalram, &info->totalram); + err |= __put_user(s.freeram, &info->freeram); + err |= __put_user(s.sharedram, &info->sharedram); + err |= __put_user(s.bufferram, &info->bufferram); + err |= __put_user(s.totalswap, &info->totalswap); + err |= __put_user(s.freeswap, &info->freeswap); + err |= __put_user(s.procs, &info->procs); + if (err) + return -EFAULT; + return ret; +} + +/* In order to reduce some races, while at the same time doing additional + * checking and hopefully speeding things up, we copy filenames to the + * kernel data space before using them.. + * + * POSIX.1 2.4: an empty pathname is invalid (ENOENT). + */ +static inline int +do_getname32 (const char *filename, char *page) +{ + int retval; + + /* 32bit pointer will be always far below TASK_SIZE :)) */ + retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE); + if (retval > 0) { + if (retval < PAGE_SIZE) + return 0; + return -ENAMETOOLONG; + } else if (!retval) + retval = -ENOENT; + return retval; +} + +static char * +getname32 (const char *filename) +{ + char *tmp, *result; + + result = ERR_PTR(-ENOMEM); tmp = (char *)__get_free_page(GFP_KERNEL); if (tmp) { int retval = do_getname32(filename, tmp); @@ -2856,178 +3691,132 @@ return result; } -/* 32-bit timeval and related flotsam. */ - -extern asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); - -asmlinkage long -sys32_ioperm(u32 from, u32 num, int on) -{ - return sys_ioperm((unsigned long)from, (unsigned long)num, on); -} - struct dqblk32 { - __u32 dqb_bhardlimit; - __u32 dqb_bsoftlimit; - __u32 dqb_curblocks; - __u32 dqb_ihardlimit; - __u32 dqb_isoftlimit; - __u32 dqb_curinodes; - __kernel_time_t32 dqb_btime; - __kernel_time_t32 dqb_itime; + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u32 dqb_curblocks; + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; }; -extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, - caddr_t addr); - asmlinkage long -sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) +sys32_quotactl (int cmd, unsigned int special, int id, struct dqblk32 *addr) { + extern asmlinkage long sys_quotactl (int, const char *, int, caddr_t); int cmds = cmd >> SUBCMDSHIFT; - int err; - struct dqblk d; mm_segment_t old_fs; + struct dqblk d; char *spec; + long err; switch (cmds) { - case Q_GETQUOTA: + case Q_GETQUOTA: break; - case Q_SETQUOTA: - case Q_SETUSE: - case Q_SETQLIM: - if (copy_from_user (&d, (struct dqblk32 *)addr, - sizeof (struct dqblk32))) + case Q_SETQUOTA: + case Q_SETUSE: + case Q_SETQLIM: + if (copy_from_user (&d, addr, sizeof(struct dqblk32))) return -EFAULT; d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; break; - default: - return sys_quotactl(cmd, special, - id, (caddr_t)addr); + default: + return sys_quotactl(cmd, (void *) A(special), id, (caddr_t) addr); } - spec = getname32 (special); + spec = getname32((void *) A(special)); err = PTR_ERR(spec); - if (IS_ERR(spec)) return err; + if (IS_ERR(spec)) + return err; old_fs = get_fs (); - set_fs (KERNEL_DS); + set_fs(KERNEL_DS); err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); - set_fs (old_fs); - putname (spec); + set_fs(old_fs); + putname(spec); if (cmds == Q_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; ((struct dqblk32 *)&d)->dqb_itime = i; ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct dqblk32 *)addr, &d, - sizeof (struct dqblk32))) + if (copy_to_user(addr, &d, sizeof(struct dqblk32))) return -EFAULT; } return err; } -extern asmlinkage long sys_utime(char * filename, struct utimbuf * times); - -struct utimbuf32 { - __kernel_time_t32 actime, modtime; -}; - asmlinkage long -sys32_utime(char * filename, struct utimbuf32 *times) +sys32_sched_rr_get_interval (pid_t pid, struct timespec32 *interval) { - struct utimbuf t; - mm_segment_t old_fs; - int ret; - char *filenam; + extern asmlinkage long sys_sched_rr_get_interval (pid_t, struct timespec *); + mm_segment_t old_fs = get_fs(); + struct timespec t; + long ret; - if (!times) - return sys_utime(filename, NULL); - if (get_user (t.actime, ×->actime) || - __get_user (t.modtime, ×->modtime)) - return -EFAULT; - filenam = getname32 (filename); - ret = PTR_ERR(filenam); - if (!IS_ERR(filenam)) { - old_fs = get_fs(); - set_fs (KERNEL_DS); - ret = sys_utime(filenam, &t); - set_fs (old_fs); - putname (filenam); - } + set_fs(KERNEL_DS); + ret = sys_sched_rr_get_interval(pid, &t); + set_fs(old_fs); + if (put_user (t.tv_sec, &interval->tv_sec) || put_user (t.tv_nsec, &interval->tv_nsec)) + return -EFAULT; return ret; } -/* - * Ooo, nasty. We need here to frob 32-bit unsigned longs to - * 64-bit unsigned longs. - */ - -static inline int -get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset) +asmlinkage long +sys32_pread (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi) { - if (ufdset) { - unsigned long odd; - - if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32))) - return -EFAULT; + extern asmlinkage long sys_pread (unsigned int, char *, size_t, loff_t); + return sys_pread(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo); +} - odd = n & 1UL; - n &= ~1UL; - while (n) { - unsigned long h, l; - __get_user(l, ufdset); - __get_user(h, ufdset+1); - ufdset += 2; - *fdset++ = h << 32 | l; - n -= 2; - } - if (odd) - __get_user(*fdset, ufdset); - } else { - /* Tricky, must clear full unsigned long in the - * kernel fdset at the end, this makes sure that - * actually happens. - */ - memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32)); - } - return 0; +asmlinkage long +sys32_pwrite (unsigned int fd, void *buf, unsigned int count, u32 pos_lo, u32 pos_hi) +{ + extern asmlinkage long sys_pwrite (unsigned int, const char *, size_t, loff_t); + return sys_pwrite(fd, buf, count, ((unsigned long) pos_hi << 32) | pos_lo); } -static inline void -set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset) +asmlinkage long +sys32_sendfile (int out_fd, int in_fd, int *offset, unsigned int count) { - unsigned long odd; + extern asmlinkage long sys_sendfile (int, int, off_t *, size_t); + mm_segment_t old_fs = get_fs(); + long ret; + off_t of; - if (!ufdset) - return; + if (offset && get_user(of, offset)) + return -EFAULT; - odd = n & 1UL; - n &= ~1UL; - while (n) { - unsigned long h, l; - l = *fdset++; - h = l >> 32; - __put_user(l, ufdset); - __put_user(h, ufdset+1); - ufdset += 2; - n -= 2; - } - if (odd) - __put_user(*fdset, ufdset); -} + set_fs(KERNEL_DS); + ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); + set_fs(old_fs); + + if (!ret && offset && put_user(of, offset)) + return -EFAULT; -extern asmlinkage long sys_sysfs(int option, unsigned long arg1, - unsigned long arg2); + return ret; +} asmlinkage long -sys32_sysfs(int option, u32 arg1, u32 arg2) +sys32_personality (unsigned int personality) { - return sys_sysfs(option, arg1, arg2); + extern asmlinkage long sys_personality (unsigned long); + long ret; + + if (current->personality == PER_LINUX32 && personality == PER_LINUX) + personality = PER_LINUX32; + ret = sys_personality(personality); + if (ret == PER_LINUX32) + ret = PER_LINUX; + return ret; } +#ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ + struct ncp_mount_data32 { int version; unsigned int ncp_fd; __kernel_uid_t32 mounted_uid; - __kernel_pid_t32 wdog_pid; + int wdog_pid; unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; unsigned int time_out; unsigned int retry_count; @@ -3061,1485 +3850,169 @@ __kernel_uid_t32 uid; __kernel_gid_t32 gid; __kernel_mode_t32 file_mode; - __kernel_mode_t32 dir_mode; -}; - -static void * -do_smb_super_data_conv(void *raw_data) -{ - struct smb_mount_data *s = (struct smb_mount_data *)raw_data; - struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; - - s->version = s32->version; - s->mounted_uid = s32->mounted_uid; - s->uid = s32->uid; - s->gid = s32->gid; - s->file_mode = s32->file_mode; - s->dir_mode = s32->dir_mode; - return raw_data; -} - -static int -copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel) -{ - int i; - unsigned long page; - struct vm_area_struct *vma; - - *kernel = 0; - if(!user) - return 0; - vma = find_vma(current->mm, (unsigned long)user); - if(!vma || (unsigned long)user < vma->vm_start) - return -EFAULT; - if(!(vma->vm_flags & VM_READ)) - return -EFAULT; - i = vma->vm_end - (unsigned long) user; - if(PAGE_SIZE <= (unsigned long) i) - i = PAGE_SIZE - 1; - if(!(page = __get_free_page(GFP_KERNEL))) - return -ENOMEM; - if(copy_from_user((void *) page, user, i)) { - free_page(page); - return -EFAULT; - } - *kernel = page; - return 0; -} - -extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, - unsigned long new_flags, void *data); - -#define SMBFS_NAME "smbfs" -#define NCPFS_NAME "ncpfs" - -asmlinkage long -sys32_mount(char *dev_name, char *dir_name, char *type, - unsigned long new_flags, u32 data) -{ - unsigned long type_page; - int err, is_smb, is_ncp; - - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - is_smb = is_ncp = 0; - err = copy_mount_stuff_to_kernel((const void *)type, &type_page); - if(err) - return err; - if(type_page) { - is_smb = !strcmp((char *)type_page, SMBFS_NAME); - is_ncp = !strcmp((char *)type_page, NCPFS_NAME); - } - if(!is_smb && !is_ncp) { - if(type_page) - free_page(type_page); - return sys_mount(dev_name, dir_name, type, new_flags, - (void *)AA(data)); - } else { - unsigned long dev_page, dir_page, data_page; - - err = copy_mount_stuff_to_kernel((const void *)dev_name, - &dev_page); - if(err) - goto out; - err = copy_mount_stuff_to_kernel((const void *)dir_name, - &dir_page); - if(err) - goto dev_out; - err = copy_mount_stuff_to_kernel((const void *)AA(data), - &data_page); - if(err) - goto dir_out; - if(is_ncp) - do_ncp_super_data_conv((void *)data_page); - else if(is_smb) - do_smb_super_data_conv((void *)data_page); - else - panic("The problem is here..."); - err = do_mount((char *)dev_page, (char *)dir_page, - (char *)type_page, new_flags, - (void *)data_page); - if(data_page) - free_page(data_page); - dir_out: - if(dir_page) - free_page(dir_page); - dev_out: - if(dev_page) - free_page(dev_page); - out: - if(type_page) - free_page(type_page); - return err; - } -} - -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - unsigned short procs; - char _f[22]; -}; - -extern asmlinkage long sys_sysinfo(struct sysinfo *info); - -asmlinkage long -sys32_sysinfo(struct sysinfo32 *info) -{ - struct sysinfo s; - int ret, err; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_sysinfo(&s); - set_fs (old_fs); - err = put_user (s.uptime, &info->uptime); - err |= __put_user (s.loads[0], &info->loads[0]); - err |= __put_user (s.loads[1], &info->loads[1]); - err |= __put_user (s.loads[2], &info->loads[2]); - err |= __put_user (s.totalram, &info->totalram); - err |= __put_user (s.freeram, &info->freeram); - err |= __put_user (s.sharedram, &info->sharedram); - err |= __put_user (s.bufferram, &info->bufferram); - err |= __put_user (s.totalswap, &info->totalswap); - err |= __put_user (s.freeswap, &info->freeswap); - err |= __put_user (s.procs, &info->procs); - if (err) - return -EFAULT; - return ret; -} - -extern asmlinkage long sys_sched_rr_get_interval(pid_t pid, - struct timespec *interval); - -asmlinkage long -sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval) -{ - struct timespec t; - int ret; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_sched_rr_get_interval(pid, &t); - set_fs (old_fs); - if (put_user (t.tv_sec, &interval->tv_sec) || - __put_user (t.tv_nsec, &interval->tv_nsec)) - return -EFAULT; - return ret; -} - -extern asmlinkage long sys_sigprocmask(int how, old_sigset_t *set, - old_sigset_t *oset); - -asmlinkage long -sys32_sigprocmask(int how, old_sigset_t32 *set, old_sigset_t32 *oset) -{ - old_sigset_t s; - int ret; - mm_segment_t old_fs = get_fs(); - - if (set && get_user (s, set)) return -EFAULT; - set_fs (KERNEL_DS); - ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL); - set_fs (old_fs); - if (ret) return ret; - if (oset && put_user (s, oset)) return -EFAULT; - return 0; -} - -extern asmlinkage long sys_sigpending(old_sigset_t *set); - -asmlinkage long -sys32_sigpending(old_sigset_t32 *set) -{ - old_sigset_t s; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_sigpending(&s); - set_fs (old_fs); - if (put_user (s, set)) return -EFAULT; - return ret; -} - -extern asmlinkage long sys_rt_sigpending(sigset_t *set, size_t sigsetsize); - -asmlinkage long -sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize) -{ - sigset_t s; - sigset_t32 s32; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_rt_sigpending(&s, sigsetsize); - set_fs (old_fs); - if (!ret) { - switch (_NSIG_WORDS) { - case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; - case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; - case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; - case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; - } - if (copy_to_user (set, &s32, sizeof(sigset_t32))) - return -EFAULT; - } - return ret; -} - -siginfo_t32 * -siginfo64to32(siginfo_t32 *d, siginfo_t *s) -{ - memset(d, 0, sizeof(siginfo_t32)); - d->si_signo = s->si_signo; - d->si_errno = s->si_errno; - d->si_code = s->si_code; - if (s->si_signo >= SIGRTMIN) { - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - /* XXX: Ouch, how to find this out??? */ - d->si_int = s->si_int; - } else switch (s->si_signo) { - /* XXX: What about POSIX1.b timers */ - case SIGCHLD: - d->si_pid = s->si_pid; - d->si_status = s->si_status; - d->si_utime = s->si_utime; - d->si_stime = s->si_stime; - break; - case SIGSEGV: - case SIGBUS: - case SIGFPE: - case SIGILL: - d->si_addr = (long)(s->si_addr); - /* XXX: Do we need to translate this from ia64 to ia32 traps? */ - d->si_trapno = s->si_trapno; - break; - case SIGPOLL: - d->si_band = s->si_band; - d->si_fd = s->si_fd; - break; - default: - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - break; - } - return d; -} - -siginfo_t * -siginfo32to64(siginfo_t *d, siginfo_t32 *s) -{ - d->si_signo = s->si_signo; - d->si_errno = s->si_errno; - d->si_code = s->si_code; - if (s->si_signo >= SIGRTMIN) { - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - /* XXX: Ouch, how to find this out??? */ - d->si_int = s->si_int; - } else switch (s->si_signo) { - /* XXX: What about POSIX1.b timers */ - case SIGCHLD: - d->si_pid = s->si_pid; - d->si_status = s->si_status; - d->si_utime = s->si_utime; - d->si_stime = s->si_stime; - break; - case SIGSEGV: - case SIGBUS: - case SIGFPE: - case SIGILL: - d->si_addr = (void *)A(s->si_addr); - /* XXX: Do we need to translate this from ia32 to ia64 traps? */ - d->si_trapno = s->si_trapno; - break; - case SIGPOLL: - d->si_band = s->si_band; - d->si_fd = s->si_fd; - break; - default: - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - break; - } - return d; -} - -extern asmlinkage long -sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, - const struct timespec *uts, size_t sigsetsize); - -asmlinkage long -sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, - struct timespec32 *uts, __kernel_size_t32 sigsetsize) -{ - sigset_t s; - sigset_t32 s32; - struct timespec t; - int ret; - mm_segment_t old_fs = get_fs(); - siginfo_t info; - siginfo_t32 info32; - - if (copy_from_user (&s32, uthese, sizeof(sigset_t32))) - return -EFAULT; - switch (_NSIG_WORDS) { - case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); - case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); - case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); - case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); - } - if (uts) { - ret = get_user (t.tv_sec, &uts->tv_sec); - ret |= __get_user (t.tv_nsec, &uts->tv_nsec); - if (ret) - return -EFAULT; - } - set_fs (KERNEL_DS); - ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); - set_fs (old_fs); - if (ret >= 0 && uinfo) { - if (copy_to_user (uinfo, siginfo64to32(&info32, &info), - sizeof(siginfo_t32))) - return -EFAULT; - } - return ret; -} - -extern asmlinkage long -sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo); - -asmlinkage long -sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) -{ - siginfo_t info; - siginfo_t32 info32; - int ret; - mm_segment_t old_fs = get_fs(); - - if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32))) - return -EFAULT; - /* XXX: Is this correct? */ - siginfo32to64(&info, &info32); - set_fs (KERNEL_DS); - ret = sys_rt_sigqueueinfo(pid, sig, &info); - set_fs (old_fs); - return ret; -} - -extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid); - -asmlinkage long sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) -{ - uid_t sruid, seuid; - - sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); - seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); - return sys_setreuid(sruid, seuid); -} - -extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); - -asmlinkage long -sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid, - __kernel_uid_t32 suid) -{ - uid_t sruid, seuid, ssuid; - - sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); - seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); - ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid); - return sys_setresuid(sruid, seuid, ssuid); -} - -extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); - -asmlinkage long -sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid, - __kernel_uid_t32 *suid) -{ - uid_t a, b, c; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_getresuid(&a, &b, &c); - set_fs (old_fs); - if (put_user (a, ruid) || put_user (b, euid) || put_user (c, suid)) - return -EFAULT; - return ret; -} - -extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid); - -asmlinkage long -sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) -{ - gid_t srgid, segid; - - srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); - segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); - return sys_setregid(srgid, segid); -} - -extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); - -asmlinkage long -sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid, - __kernel_gid_t32 sgid) -{ - gid_t srgid, segid, ssgid; - - srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); - segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); - ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); - return sys_setresgid(srgid, segid, ssgid); -} - -extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist); - -asmlinkage long -sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist) -{ - gid_t gl[NGROUPS]; - int ret, i; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_getgroups(gidsetsize, gl); - set_fs (old_fs); - if (gidsetsize && ret > 0 && ret <= NGROUPS) - for (i = 0; i < ret; i++, grouplist++) - if (__put_user (gl[i], grouplist)) - return -EFAULT; - return ret; -} - -extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist); - -asmlinkage long -sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist) -{ - gid_t gl[NGROUPS]; - int ret, i; - mm_segment_t old_fs = get_fs (); - - if ((unsigned) gidsetsize > NGROUPS) - return -EINVAL; - for (i = 0; i < gidsetsize; i++, grouplist++) - if (__get_user (gl[i], grouplist)) - return -EFAULT; - set_fs (KERNEL_DS); - ret = sys_setgroups(gidsetsize, gl); - set_fs (old_fs); - return ret; -} - - -/* XXX These as well... */ -extern __inline__ struct socket * -socki_lookup(struct inode *inode) -{ - return &inode->u.socket_i; -} - -extern __inline__ struct socket * -sockfd_lookup(int fd, int *err) -{ - struct file *file; - struct inode *inode; - - if (!(file = fget(fd))) - { - *err = -EBADF; - return NULL; - } - - inode = file->f_dentry->d_inode; - if (!inode->i_sock || !socki_lookup(inode)) - { - *err = -ENOTSOCK; - fput(file); - return NULL; - } - - return socki_lookup(inode); -} - -struct msghdr32 { - u32 msg_name; - int msg_namelen; - u32 msg_iov; - __kernel_size_t32 msg_iovlen; - u32 msg_control; - __kernel_size_t32 msg_controllen; - unsigned msg_flags; -}; - -struct cmsghdr32 { - __kernel_size_t32 cmsg_len; - int cmsg_level; - int cmsg_type; -}; - -/* Bleech... */ -#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) \ - __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) -#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) \ - cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) - -#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) ) - -#define CMSG32_DATA(cmsg) \ - ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32)))) -#define CMSG32_SPACE(len) \ - (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len)) -#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len)) - -#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \ - (struct cmsghdr32 *)(ctl) : \ - (struct cmsghdr32 *)NULL) -#define CMSG32_FIRSTHDR(msg) \ - __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) - -__inline__ struct cmsghdr32 * -__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size, - struct cmsghdr32 *__cmsg, int __cmsg_len) -{ - struct cmsghdr32 * __ptr; - - __ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) + - CMSG32_ALIGN(__cmsg_len)); - if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size) - return NULL; - - return __ptr; -} - -__inline__ struct cmsghdr32 * -cmsg32_nxthdr (struct msghdr *__msg, struct cmsghdr32 *__cmsg, int __cmsg_len) -{ - return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen, - __cmsg, __cmsg_len); -} - -static inline int -iov_from_user32_to_kern(struct iovec *kiov, struct iovec32 *uiov32, int niov) -{ - int tot_len = 0; - - while(niov > 0) { - u32 len, buf; - - if(get_user(len, &uiov32->iov_len) || - get_user(buf, &uiov32->iov_base)) { - tot_len = -EFAULT; - break; - } - tot_len += len; - kiov->iov_base = (void *)A(buf); - kiov->iov_len = (__kernel_size_t) len; - uiov32++; - kiov++; - niov--; - } - return tot_len; -} - -static inline int -msghdr_from_user32_to_kern(struct msghdr *kmsg, struct msghdr32 *umsg) -{ - u32 tmp1, tmp2, tmp3; - int err; - - err = get_user(tmp1, &umsg->msg_name); - err |= __get_user(tmp2, &umsg->msg_iov); - err |= __get_user(tmp3, &umsg->msg_control); - if (err) - return -EFAULT; - - kmsg->msg_name = (void *)A(tmp1); - kmsg->msg_iov = (struct iovec *)A(tmp2); - kmsg->msg_control = (void *)A(tmp3); - - err = get_user(kmsg->msg_namelen, &umsg->msg_namelen); - err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen); - err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen); - err |= get_user(kmsg->msg_flags, &umsg->msg_flags); - - return err; -} - -/* I've named the args so it is easy to tell whose space the pointers are in. */ -static int -verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov, - char *kern_address, int mode) -{ - int tot_len; - - if(kern_msg->msg_namelen) { - if(mode==VERIFY_READ) { - int err = move_addr_to_kernel(kern_msg->msg_name, - kern_msg->msg_namelen, - kern_address); - if(err < 0) - return err; - } - kern_msg->msg_name = kern_address; - } else - kern_msg->msg_name = NULL; - - if(kern_msg->msg_iovlen > UIO_FASTIOV) { - kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec), - GFP_KERNEL); - if(!kern_iov) - return -ENOMEM; - } - - tot_len = iov_from_user32_to_kern(kern_iov, - (struct iovec32 *)kern_msg->msg_iov, - kern_msg->msg_iovlen); - if(tot_len >= 0) - kern_msg->msg_iov = kern_iov; - else if(kern_msg->msg_iovlen > UIO_FASTIOV) - kfree(kern_iov); - - return tot_len; -} - -/* There is a lot of hair here because the alignment rules (and - * thus placement) of cmsg headers and length are different for - * 32-bit apps. -DaveM - */ -static int -cmsghdr_from_user32_to_kern(struct msghdr *kmsg, unsigned char *stackbuf, - int stackbuf_size) -{ - struct cmsghdr32 *ucmsg; - struct cmsghdr *kcmsg, *kcmsg_base; - __kernel_size_t32 ucmlen; - __kernel_size_t kcmlen, tmp; - - kcmlen = 0; - kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; - ucmsg = CMSG32_FIRSTHDR(kmsg); - while(ucmsg != NULL) { - if(get_user(ucmlen, &ucmsg->cmsg_len)) - return -EFAULT; - - /* Catch bogons. */ - if(CMSG32_ALIGN(ucmlen) < - CMSG32_ALIGN(sizeof(struct cmsghdr32))) - return -EINVAL; - if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control) - + ucmlen) > kmsg->msg_controllen) - return -EINVAL; - - tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + - CMSG_ALIGN(sizeof(struct cmsghdr))); - kcmlen += tmp; - ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); - } - if(kcmlen == 0) - return -EINVAL; - - /* The kcmlen holds the 64-bit version of the control length. - * It may not be modified as we do not stick it into the kmsg - * until we have successfully copied over all of the data - * from the user. - */ - if(kcmlen > stackbuf_size) - kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL); - if(kcmsg == NULL) - return -ENOBUFS; - - /* Now copy them over neatly. */ - memset(kcmsg, 0, kcmlen); - ucmsg = CMSG32_FIRSTHDR(kmsg); - while(ucmsg != NULL) { - __get_user(ucmlen, &ucmsg->cmsg_len); - tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + - CMSG_ALIGN(sizeof(struct cmsghdr))); - kcmsg->cmsg_len = tmp; - __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); - __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); - - /* Copy over the data. */ - if(copy_from_user(CMSG_DATA(kcmsg), - CMSG32_DATA(ucmsg), - (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) - goto out_free_efault; - - /* Advance. */ - kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); - ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); - } - - /* Ok, looks like we made it. Hook it up and return success. */ - kmsg->msg_control = kcmsg_base; - kmsg->msg_controllen = kcmlen; - return 0; - -out_free_efault: - if(kcmsg_base != (struct cmsghdr *)stackbuf) - kfree(kcmsg_base); - return -EFAULT; -} - -static void -put_cmsg32(struct msghdr *kmsg, int level, int type, int len, void *data) -{ - struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; - struct cmsghdr32 cmhdr; - int cmlen = CMSG32_LEN(len); - - if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { - kmsg->msg_flags |= MSG_CTRUNC; - return; - } - - if(kmsg->msg_controllen < cmlen) { - kmsg->msg_flags |= MSG_CTRUNC; - cmlen = kmsg->msg_controllen; - } - cmhdr.cmsg_level = level; - cmhdr.cmsg_type = type; - cmhdr.cmsg_len = cmlen; - - if(copy_to_user(cm, &cmhdr, sizeof cmhdr)) - return; - if(copy_to_user(CMSG32_DATA(cm), data, - cmlen - sizeof(struct cmsghdr32))) - return; - cmlen = CMSG32_SPACE(len); - kmsg->msg_control += cmlen; - kmsg->msg_controllen -= cmlen; -} - -static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm) -{ - struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; - int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) - / sizeof(int); - int fdnum = scm->fp->count; - struct file **fp = scm->fp->fp; - int *cmfptr; - int err = 0, i; - - if (fdnum < fdmax) - fdmax = fdnum; - - for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); - i < fdmax; - i++, cmfptr++) { - int new_fd; - err = get_unused_fd(); - if (err < 0) - break; - new_fd = err; - err = put_user(new_fd, cmfptr); - if (err) { - put_unused_fd(new_fd); - break; - } - /* Bump the usage count and install the file. */ - fp[i]->f_count++; - current->files->fd[new_fd] = fp[i]; - } - - if (i > 0) { - int cmlen = CMSG32_LEN(i * sizeof(int)); - if (!err) - err = put_user(SOL_SOCKET, &cm->cmsg_level); - if (!err) - err = put_user(SCM_RIGHTS, &cm->cmsg_type); - if (!err) - err = put_user(cmlen, &cm->cmsg_len); - if (!err) { - cmlen = CMSG32_SPACE(i * sizeof(int)); - kmsg->msg_control += cmlen; - kmsg->msg_controllen -= cmlen; - } - } - if (i < fdnum) - kmsg->msg_flags |= MSG_CTRUNC; - - /* - * All of the files that fit in the message have had their - * usage counts incremented, so we just free the list. - */ - __scm_destroy(scm); -} - -/* In these cases we (currently) can just copy to data over verbatim - * because all CMSGs created by the kernel have well defined types which - * have the same layout in both the 32-bit and 64-bit API. One must add - * some special cased conversions here if we start sending control messages - * with incompatible types. - * - * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after - * we do our work. The remaining cases are: - * - * SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean - * IP_TTL int 32-bit clean - * IP_TOS __u8 32-bit clean - * IP_RECVOPTS variable length 32-bit clean - * IP_RETOPTS variable length 32-bit clean - * (these last two are clean because the types are defined - * by the IPv4 protocol) - * IP_RECVERR struct sock_extended_err + - * struct sockaddr_in 32-bit clean - * SOL_IPV6 IPV6_RECVERR struct sock_extended_err + - * struct sockaddr_in6 32-bit clean - * IPV6_PKTINFO struct in6_pktinfo 32-bit clean - * IPV6_HOPLIMIT int 32-bit clean - * IPV6_FLOWINFO u32 32-bit clean - * IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean - * IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean - * IPV6_RTHDR ipv6 routing exthdr 32-bit clean - * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean - */ -static void -cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr) -{ - unsigned char *workbuf, *wp; - unsigned long bufsz, space_avail; - struct cmsghdr *ucmsg; - - bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr; - space_avail = kmsg->msg_controllen + bufsz; - wp = workbuf = kmalloc(bufsz, GFP_KERNEL); - if(workbuf == NULL) - goto fail; - - /* To make this more sane we assume the kernel sends back properly - * formatted control messages. Because of how the kernel will truncate - * the cmsg_len for MSG_TRUNC cases, we need not check that case either. - */ - ucmsg = (struct cmsghdr *) orig_cmsg_uptr; - while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) { - struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; - int clen64, clen32; - - /* UCMSG is the 64-bit format CMSG entry in user-space. - * KCMSG32 is within the kernel space temporary buffer - * we use to convert into a 32-bit style CMSG. - */ - __get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len); - __get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level); - __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type); - - clen64 = kcmsg32->cmsg_len; - copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg), - clen64 - CMSG_ALIGN(sizeof(*ucmsg))); - clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) + - CMSG32_ALIGN(sizeof(struct cmsghdr32))); - kcmsg32->cmsg_len = clen32; - - ucmsg = (struct cmsghdr *) (((char *)ucmsg) + - CMSG_ALIGN(clen64)); - wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); - } - - /* Copy back fixed up data, and adjust pointers. */ - bufsz = (wp - workbuf); - copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz); - - kmsg->msg_control = (struct cmsghdr *) - (((char *)orig_cmsg_uptr) + bufsz); - kmsg->msg_controllen = space_avail - bufsz; - - kfree(workbuf); - return; - -fail: - /* If we leave the 64-bit format CMSG chunks in there, - * the application could get confused and crash. So to - * ensure greater recovery, we report no CMSGs. - */ - kmsg->msg_controllen += bufsz; - kmsg->msg_control = (void *) orig_cmsg_uptr; -} - -asmlinkage long -sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags) -{ - struct socket *sock; - char address[MAX_SOCK_ADDR]; - struct iovec iov[UIO_FASTIOV]; - unsigned char ctl[sizeof(struct cmsghdr) + 20]; - unsigned char *ctl_buf = ctl; - struct msghdr kern_msg; - int err, total_len; - - if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) - return -EFAULT; - if(kern_msg.msg_iovlen > UIO_MAXIOV) - return -EINVAL; - err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ); - if (err < 0) - goto out; - total_len = err; - - if(kern_msg.msg_controllen) { - err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl)); - if(err) - goto out_freeiov; - ctl_buf = kern_msg.msg_control; - } - kern_msg.msg_flags = user_flags; - - sock = sockfd_lookup(fd, &err); - if (sock != NULL) { - if (sock->file->f_flags & O_NONBLOCK) - kern_msg.msg_flags |= MSG_DONTWAIT; - err = sock_sendmsg(sock, &kern_msg, total_len); - sockfd_put(sock); - } - - /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */ - if(ctl_buf != ctl) - kfree(ctl_buf); -out_freeiov: - if(kern_msg.msg_iov != iov) - kfree(kern_msg.msg_iov); -out: - return err; -} - -asmlinkage long -sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags) -{ - struct iovec iovstack[UIO_FASTIOV]; - struct msghdr kern_msg; - char addr[MAX_SOCK_ADDR]; - struct socket *sock; - struct iovec *iov = iovstack; - struct sockaddr *uaddr; - int *uaddr_len; - unsigned long cmsg_ptr; - int err, total_len, len = 0; - - if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) - return -EFAULT; - if(kern_msg.msg_iovlen > UIO_MAXIOV) - return -EINVAL; - - uaddr = kern_msg.msg_name; - uaddr_len = &user_msg->msg_namelen; - err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE); - if (err < 0) - goto out; - total_len = err; - - cmsg_ptr = (unsigned long) kern_msg.msg_control; - kern_msg.msg_flags = 0; - - sock = sockfd_lookup(fd, &err); - if (sock != NULL) { - struct scm_cookie scm; - - if (sock->file->f_flags & O_NONBLOCK) - user_flags |= MSG_DONTWAIT; - memset(&scm, 0, sizeof(scm)); - lock_kernel(); - err = sock->ops->recvmsg(sock, &kern_msg, total_len, - user_flags, &scm); - if(err >= 0) { - len = err; - if(!kern_msg.msg_control) { - if(sock->passcred || scm.fp) - kern_msg.msg_flags |= MSG_CTRUNC; - if(scm.fp) - __scm_destroy(&scm); - } else { - /* If recvmsg processing itself placed some - * control messages into user space, it's is - * using 64-bit CMSG processing, so we need - * to fix it up before we tack on more stuff. - */ - if((unsigned long) kern_msg.msg_control - != cmsg_ptr) - cmsg32_recvmsg_fixup(&kern_msg, - cmsg_ptr); - - /* Wheee... */ - if(sock->passcred) - put_cmsg32(&kern_msg, - SOL_SOCKET, SCM_CREDENTIALS, - sizeof(scm.creds), - &scm.creds); - if(scm.fp != NULL) - scm_detach_fds32(&kern_msg, &scm); - } - } - unlock_kernel(); - sockfd_put(sock); - } - - if(uaddr != NULL && err >= 0) - err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, - uaddr_len); - if(cmsg_ptr != 0 && err >= 0) { - unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control); - __kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - - cmsg_ptr); - err |= __put_user(uclen, &user_msg->msg_controllen); - } - if(err >= 0) - err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); - if(kern_msg.msg_iov != iov) - kfree(kern_msg.msg_iov); -out: - if(err < 0) - return err; - return len; -} - -extern void check_pending(int signum); - -#ifdef CONFIG_MODULES - -extern asmlinkage unsigned long sys_create_module(const char *name_user, - size_t size); - -asmlinkage unsigned long -sys32_create_module(const char *name_user, __kernel_size_t32 size) -{ - return sys_create_module(name_user, (size_t)size); -} - -extern asmlinkage long sys_init_module(const char *name_user, - struct module *mod_user); - -/* Hey, when you're trying to init module, take time and prepare us a nice 64bit - * module structure, even if from 32bit modutils... Why to pollute kernel... :)) - */ -asmlinkage long -sys32_init_module(const char *name_user, struct module *mod_user) -{ - return sys_init_module(name_user, mod_user); -} - -extern asmlinkage long sys_delete_module(const char *name_user); - -asmlinkage long -sys32_delete_module(const char *name_user) -{ - return sys_delete_module(name_user); -} - -struct module_info32 { - u32 addr; - u32 size; - u32 flags; - s32 usecount; -}; - -/* Query various bits about modules. */ - -static inline long -get_mod_name(const char *user_name, char **buf) -{ - unsigned long page; - long retval; - - if ((unsigned long)user_name >= TASK_SIZE - && !segment_eq(get_fs (), KERNEL_DS)) - return -EFAULT; - - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE); - if (retval > 0) { - if (retval < PAGE_SIZE) { - *buf = (char *)page; - return retval; - } - retval = -ENAMETOOLONG; - } else if (!retval) - retval = -EINVAL; - - free_page(page); - return retval; -} - -static inline void -put_mod_name(char *buf) -{ - free_page((unsigned long)buf); -} - -static __inline__ struct module * -find_module(const char *name) -{ - struct module *mod; - - for (mod = module_list; mod ; mod = mod->next) { - if (mod->flags & MOD_DELETED) - continue; - if (!strcmp(mod->name, name)) - break; - } - - return mod; -} - -static int -qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret) -{ - struct module *mod; - size_t nmod, space, len; - - nmod = space = 0; - - for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) { - len = strlen(mod->name)+1; - if (len > bufsize) - goto calc_space_needed; - if (copy_to_user(buf, mod->name, len)) - return -EFAULT; - buf += len; - bufsize -= len; - space += len; - } - - if (put_user(nmod, ret)) - return -EFAULT; - else - return 0; - -calc_space_needed: - space += len; - while ((mod = mod->next)->next != NULL) - space += strlen(mod->name)+1; - - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; -} - -static int -qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) -{ - size_t i, space, len; - - if (mod->next == NULL) - return -EINVAL; - if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) - if (put_user(0, ret)) - return -EFAULT; - else - return 0; - - space = 0; - for (i = 0; i < mod->ndeps; ++i) { - const char *dep_name = mod->deps[i].dep->name; - - len = strlen(dep_name)+1; - if (len > bufsize) - goto calc_space_needed; - if (copy_to_user(buf, dep_name, len)) - return -EFAULT; - buf += len; - bufsize -= len; - space += len; - } - - if (put_user(i, ret)) - return -EFAULT; - else - return 0; - -calc_space_needed: - space += len; - while (++i < mod->ndeps) - space += strlen(mod->deps[i].dep->name)+1; - - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; -} - -static int -qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) -{ - size_t nrefs, space, len; - struct module_ref *ref; - - if (mod->next == NULL) - return -EINVAL; - if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) - if (put_user(0, ret)) - return -EFAULT; - else - return 0; - - space = 0; - for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) { - const char *ref_name = ref->ref->name; - - len = strlen(ref_name)+1; - if (len > bufsize) - goto calc_space_needed; - if (copy_to_user(buf, ref_name, len)) - return -EFAULT; - buf += len; - bufsize -= len; - space += len; - } - - if (put_user(nrefs, ret)) - return -EFAULT; - else - return 0; - -calc_space_needed: - space += len; - while ((ref = ref->next_ref) != NULL) - space += strlen(ref->ref->name)+1; - - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; -} - -static inline int -qm_symbols(struct module *mod, char *buf, size_t bufsize, - __kernel_size_t32 *ret) -{ - size_t i, space, len; - struct module_symbol *s; - char *strings; - unsigned *vals; - - if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) - if (put_user(0, ret)) - return -EFAULT; - else - return 0; - - space = mod->nsyms * 2*sizeof(u32); - - i = len = 0; - s = mod->syms; - - if (space > bufsize) - goto calc_space_needed; - - if (!access_ok(VERIFY_WRITE, buf, space)) - return -EFAULT; - - bufsize -= space; - vals = (unsigned *)buf; - strings = buf+space; - - for (; i < mod->nsyms ; ++i, ++s, vals += 2) { - len = strlen(s->name)+1; - if (len > bufsize) - goto calc_space_needed; - - if (copy_to_user(strings, s->name, len) - || __put_user(s->value, vals+0) - || __put_user(space, vals+1)) - return -EFAULT; - - strings += len; - bufsize -= len; - space += len; - } - - if (put_user(i, ret)) - return -EFAULT; - else - return 0; + __kernel_mode_t32 dir_mode; +}; -calc_space_needed: - for (; i < mod->nsyms; ++i, ++s) - space += strlen(s->name)+1; +static void * +do_smb_super_data_conv(void *raw_data) +{ + struct smb_mount_data *s = (struct smb_mount_data *)raw_data; + struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; - if (put_user(space, ret)) - return -EFAULT; - else - return -ENOSPC; + s->version = s32->version; + s->mounted_uid = s32->mounted_uid; + s->uid = s32->uid; + s->gid = s32->gid; + s->file_mode = s32->file_mode; + s->dir_mode = s32->dir_mode; + return raw_data; } -static inline int -qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +static int +copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel) { - int error = 0; - - if (mod->next == NULL) - return -EINVAL; - - if (sizeof(struct module_info32) <= bufsize) { - struct module_info32 info; - info.addr = (unsigned long)mod; - info.size = mod->size; - info.flags = mod->flags; - info.usecount = - ((mod_member_present(mod, can_unload) - && mod->can_unload) - ? -1 : atomic_read(&mod->uc.usecount)); - - if (copy_to_user(buf, &info, sizeof(struct module_info32))) - return -EFAULT; - } else - error = -ENOSPC; + int i; + unsigned long page; + struct vm_area_struct *vma; - if (put_user(sizeof(struct module_info32), ret)) + *kernel = 0; + if(!user) + return 0; + vma = find_vma(current->mm, (unsigned long)user); + if(!vma || (unsigned long)user < vma->vm_start) return -EFAULT; - - return error; + if(!(vma->vm_flags & VM_READ)) + return -EFAULT; + i = vma->vm_end - (unsigned long) user; + if(PAGE_SIZE <= (unsigned long) i) + i = PAGE_SIZE - 1; + if(!(page = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + if(copy_from_user((void *) page, user, i)) { + free_page(page); + return -EFAULT; + } + *kernel = page; + return 0; } +extern asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, + unsigned long new_flags, void *data); + +#define SMBFS_NAME "smbfs" +#define NCPFS_NAME "ncpfs" + asmlinkage long -sys32_query_module(char *name_user, int which, char *buf, - __kernel_size_t32 bufsize, u32 ret) +sys32_mount(char *dev_name, char *dir_name, char *type, + unsigned long new_flags, u32 data) { - struct module *mod; - int err; + unsigned long type_page; + int err, is_smb, is_ncp; - lock_kernel(); - if (name_user == 0) { - /* This finds "kernel_module" which is not exported. */ - for(mod = module_list; mod->next != NULL; mod = mod->next) - ; + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + is_smb = is_ncp = 0; + err = copy_mount_stuff_to_kernel((const void *)type, &type_page); + if(err) + return err; + if(type_page) { + is_smb = !strcmp((char *)type_page, SMBFS_NAME); + is_ncp = !strcmp((char *)type_page, NCPFS_NAME); + } + if(!is_smb && !is_ncp) { + if(type_page) + free_page(type_page); + return sys_mount(dev_name, dir_name, type, new_flags, + (void *)AA(data)); } else { - long namelen; - char *name; + unsigned long dev_page, dir_page, data_page; - if ((namelen = get_mod_name(name_user, &name)) < 0) { - err = namelen; - goto out; - } - err = -ENOENT; - if (namelen == 0) { - /* This finds "kernel_module" which is not exported. */ - for(mod = module_list; - mod->next != NULL; - mod = mod->next) ; - } else if ((mod = find_module(name)) == NULL) { - put_mod_name(name); + err = copy_mount_stuff_to_kernel((const void *)dev_name, + &dev_page); + if(err) goto out; - } - put_mod_name(name); - } - - switch (which) - { - case 0: - err = 0; - break; - case QM_MODULES: - err = qm_modules(buf, bufsize, (__kernel_size_t32 *)AA(ret)); - break; - case QM_DEPS: - err = qm_deps(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); - break; - case QM_REFS: - err = qm_refs(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); - break; - case QM_SYMBOLS: - err = qm_symbols(mod, buf, bufsize, - (__kernel_size_t32 *)AA(ret)); - break; - case QM_INFO: - err = qm_info(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); - break; - default: - err = -EINVAL; - break; + err = copy_mount_stuff_to_kernel((const void *)dir_name, + &dir_page); + if(err) + goto dev_out; + err = copy_mount_stuff_to_kernel((const void *)AA(data), + &data_page); + if(err) + goto dir_out; + if(is_ncp) + do_ncp_super_data_conv((void *)data_page); + else if(is_smb) + do_smb_super_data_conv((void *)data_page); + else + panic("The problem is here..."); + err = do_mount((char *)dev_page, (char *)dir_page, + (char *)type_page, new_flags, + (void *)data_page); + if(data_page) + free_page(data_page); + dir_out: + if(dir_page) + free_page(dir_page); + dev_out: + if(dev_page) + free_page(dev_page); + out: + if(type_page) + free_page(type_page); + return err; } -out: - unlock_kernel(); - return err; } -struct kernel_sym32 { - u32 value; - char name[60]; -}; - -extern asmlinkage long sys_get_kernel_syms(struct kernel_sym *table); +extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid); -asmlinkage long -sys32_get_kernel_syms(struct kernel_sym32 *table) +asmlinkage long sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) { - int len, i; - struct kernel_sym *tbl; - mm_segment_t old_fs; + uid_t sruid, seuid; - len = sys_get_kernel_syms(NULL); - if (!table) return len; - tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL); - if (!tbl) return -ENOMEM; - old_fs = get_fs(); - set_fs (KERNEL_DS); - sys_get_kernel_syms(tbl); - set_fs (old_fs); - for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) { - if (put_user (tbl[i].value, &table->value) || - copy_to_user (table->name, tbl[i].name, 60)) - break; - } - kfree (tbl); - return i; + sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); + seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); + return sys_setreuid(sruid, seuid); } -#else /* CONFIG_MODULES */ - -asmlinkage unsigned long -sys32_create_module(const char *name_user, size_t size) -{ - return -ENOSYS; -} +extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); asmlinkage long -sys32_init_module(const char *name_user, struct module *mod_user) +sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid, + __kernel_uid_t32 suid) { - return -ENOSYS; -} + uid_t sruid, seuid, ssuid; -asmlinkage long -sys32_delete_module(const char *name_user) -{ - return -ENOSYS; + sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); + seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); + ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid); + return sys_setresuid(sruid, seuid, ssuid); } +extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid); + asmlinkage long -sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize, - size_t *ret) +sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) { - /* Let the program know about the new interface. Not that - it'll do them much good. */ - if (which == 0) - return 0; + gid_t srgid, segid; - return -ENOSYS; + srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); + segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); + return sys_setregid(srgid, segid); } +extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); + asmlinkage long -sys32_get_kernel_syms(struct kernel_sym *table) +sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid, + __kernel_gid_t32 sgid) { - return -ENOSYS; -} + gid_t srgid, segid, ssgid; -#endif /* CONFIG_MODULES */ + srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); + segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); + ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); + return sys_setresgid(srgid, segid, ssgid); +} /* Stuff for NFS server syscalls... */ struct nfsctl_svc32 { @@ -4820,154 +4293,6 @@ return err; } -asmlinkage long sys_utimes(char *, struct timeval *); - -asmlinkage long -sys32_utimes(char *filename, struct timeval32 *tvs) -{ - char *kfilename; - struct timeval ktvs[2]; - mm_segment_t old_fs; - int ret; - - kfilename = getname32(filename); - ret = PTR_ERR(kfilename); - if (!IS_ERR(kfilename)) { - if (tvs) { - if (get_tv32(&ktvs[0], tvs) || - get_tv32(&ktvs[1], 1+tvs)) - return -EFAULT; - } - - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_utimes(kfilename, &ktvs[0]); - set_fs(old_fs); - - putname(kfilename); - } - return ret; -} - -/* These are here just in case some old ia32 binary calls it. */ -asmlinkage long -sys32_pause(void) -{ - current->state = TASK_INTERRUPTIBLE; - schedule(); - return -ERESTARTNOHAND; -} - -/* PCI config space poking. */ -extern asmlinkage long sys_pciconfig_read(unsigned long bus, - unsigned long dfn, - unsigned long off, - unsigned long len, - unsigned char *buf); - -extern asmlinkage long sys_pciconfig_write(unsigned long bus, - unsigned long dfn, - unsigned long off, - unsigned long len, - unsigned char *buf); - -asmlinkage long -sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) -{ - return sys_pciconfig_read((unsigned long) bus, - (unsigned long) dfn, - (unsigned long) off, - (unsigned long) len, - (unsigned char *)AA(ubuf)); -} - -asmlinkage long -sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) -{ - return sys_pciconfig_write((unsigned long) bus, - (unsigned long) dfn, - (unsigned long) off, - (unsigned long) len, - (unsigned char *)AA(ubuf)); -} - -extern asmlinkage long sys_prctl(int option, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5); - -asmlinkage long -sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) -{ - return sys_prctl(option, - (unsigned long) arg2, - (unsigned long) arg3, - (unsigned long) arg4, - (unsigned long) arg5); -} - - -extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf, - size_t count, loff_t pos); - -extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf, - size_t count, loff_t pos); - -typedef __kernel_ssize_t32 ssize_t32; - -asmlinkage ssize_t32 -sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count, - u32 poshi, u32 poslo) -{ - return sys_pread(fd, ubuf, count, - ((loff_t)AA(poshi) << 32) | AA(poslo)); -} - -asmlinkage ssize_t32 -sys32_pwrite(unsigned int fd, char *ubuf, __kernel_size_t32 count, - u32 poshi, u32 poslo) -{ - return sys_pwrite(fd, ubuf, count, - ((loff_t)AA(poshi) << 32) | AA(poslo)); -} - - -extern asmlinkage long sys_personality(unsigned long); - -asmlinkage long -sys32_personality(unsigned long personality) -{ - int ret; - if (current->personality == PER_LINUX32 && personality == PER_LINUX) - personality = PER_LINUX32; - ret = sys_personality(personality); - if (ret == PER_LINUX32) - ret = PER_LINUX; - return ret; -} - -extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, - size_t count); - -asmlinkage long -sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count) -{ - mm_segment_t old_fs = get_fs(); - int ret; - off_t of; - - if (offset && get_user(of, offset)) - return -EFAULT; - - set_fs(KERNEL_DS); - ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); - set_fs(old_fs); - - if (!ret && offset && put_user(of, offset)) - return -EFAULT; - - return ret; -} - /* Handle adjtimex compatability. */ struct timex32 { @@ -5041,4 +4366,4 @@ return ret; } -#endif // NOTYET +#endif /* NOTYET */ diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile --- v2.4.14/linux/arch/ia64/kernel/Makefile Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/Makefile Fri Nov 9 14:26:17 2001 @@ -16,7 +16,7 @@ obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o ivt.o \ machvec.o pal.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o -obj-$(CONFIG_IA64_GENERIC) += machvec.o iosapic.o +obj-$(CONFIG_IA64_GENERIC) += iosapic.o obj-$(CONFIG_IA64_DIG) += iosapic.o obj-$(CONFIG_IA64_PALINFO) += palinfo.o obj-$(CONFIG_EFI_VARS) += efivars.o diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c --- v2.4.14/linux/arch/ia64/kernel/acpi.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/acpi.c Fri Nov 9 14:26:17 2001 @@ -9,7 +9,7 @@ * Copyright (C) 2000 Hewlett-Packard Co. * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 2000 Intel Corp. - * Copyright (C) 2000 J.I. Lee <jung-ik.lee@intel.com> + * Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com> * ACPI based kernel configuration manager. * ACPI 2.0 & IA64 ext 0.71 */ @@ -23,6 +23,9 @@ #include <linux/string.h> #include <linux/types.h> #include <linux/irq.h> +#ifdef CONFIG_SERIAL_ACPI +#include <linux/acpi_serial.h> +#endif #include <asm/acpi-ext.h> #include <asm/acpikcfg.h> @@ -34,6 +37,9 @@ #undef ACPI_DEBUG /* Guess what this does? */ +/* global array to record platform interrupt vectors for generic int routing */ +int platform_irq_list[ACPI_MAX_PLATFORM_IRQS]; + /* These are ugly but will be reclaimed by the kernel */ int __initdata available_cpus; int __initdata total_cpus; @@ -41,8 +47,11 @@ void (*pm_idle) (void); void (*pm_power_off) (void); +asm (".weak iosapic_register_irq"); asm (".weak iosapic_register_legacy_irq"); +asm (".weak iosapic_register_platform_irq"); asm (".weak iosapic_init"); +asm (".weak iosapic_version"); const char * acpi_get_sysname (void) @@ -55,6 +64,8 @@ return "hpsim"; # elif defined (CONFIG_IA64_SGI_SN1) return "sn1"; +# elif defined (CONFIG_IA64_SGI_SN2) + return "sn2"; # elif defined (CONFIG_IA64_DIG) return "dig"; # else @@ -65,6 +76,25 @@ } /* + * Interrupt routing API for device drivers. + * Provides the interrupt vector for a generic platform event + * (currently only CPEI implemented) + */ +int +acpi_request_vector(u32 int_type) +{ + int vector = -1; + + if (int_type < ACPI_MAX_PLATFORM_IRQS) { + /* correctable platform error interrupt */ + vector = platform_irq_list[int_type]; + } else + printk("acpi_request_vector(): invalid interrupt type\n"); + + return vector; +} + +/* * Configure legacy IRQ information. */ static void __init @@ -139,15 +169,93 @@ } /* - * Info on platform interrupt sources: NMI. PMI, INIT, etc. + * Extract iosapic info from madt (again) to determine which iosapic + * this platform interrupt resides in + */ +static int __init +acpi20_which_iosapic (int global_vector, acpi_madt_t *madt, u32 *irq_base, char **iosapic_address) +{ + acpi_entry_iosapic_t *iosapic; + char *p, *end; + int ver, max_pin; + + p = (char *) (madt + 1); + end = p + (madt->header.length - sizeof(acpi_madt_t)); + + while (p < end) { + switch (*p) { + case ACPI20_ENTRY_IO_SAPIC: + /* collect IOSAPIC info for platform int use later */ + iosapic = (acpi_entry_iosapic_t *)p; + *irq_base = iosapic->irq_base; + *iosapic_address = ioremap(iosapic->address, 0); + /* is this the iosapic we're looking for? */ + ver = iosapic_version(*iosapic_address); + max_pin = (ver >> 16) & 0xff; + if ((global_vector - *irq_base) <= max_pin) + return 0; /* found it! */ + break; + default: + break; + } + p += p[1]; + } + return 1; +} + +/* + * Info on platform interrupt sources: NMI, PMI, INIT, etc. */ static void __init -acpi20_platform (char *p) +acpi20_platform (char *p, acpi_madt_t *madt) { + int vector; + u32 irq_base; + char *iosapic_address; + unsigned long polarity = 0, trigger = 0; acpi20_entry_platform_src_t *plat = (acpi20_entry_platform_src_t *) p; printk("PLATFORM: IOSAPIC %x -> Vector %x on CPU %.04u:%.04u\n", plat->iosapic_vector, plat->global_vector, plat->eid, plat->id); + + /* record platform interrupt vectors for generic int routing code */ + + if (!iosapic_register_platform_irq) { + printk("acpi20_platform(): no ACPI platform IRQ support\n"); + return; + } + + /* extract polarity and trigger info from flags */ + switch (plat->flags) { + case 0x5: polarity = 1; trigger = 1; break; + case 0x7: polarity = 0; trigger = 1; break; + case 0xd: polarity = 1; trigger = 0; break; + case 0xf: polarity = 0; trigger = 0; break; + default: + printk("acpi20_platform(): unknown flags 0x%x\n", plat->flags); + break; + } + + /* which iosapic does this IRQ belong to? */ + if (acpi20_which_iosapic(plat->global_vector, madt, &irq_base, &iosapic_address)) { + printk("acpi20_platform(): I/O SAPIC not found!\n"); + return; + } + + /* + * get vector assignment for this IRQ, set attributes, and program the IOSAPIC + * routing table + */ + vector = iosapic_register_platform_irq(plat->int_type, + plat->global_vector, + plat->iosapic_vector, + plat->eid, + plat->id, + polarity, + trigger, + irq_base, + iosapic_address); + platform_irq_list[plat->int_type] = vector; } /* @@ -173,8 +281,10 @@ static void __init acpi20_parse_madt (acpi_madt_t *madt) { - acpi_entry_iosapic_t *iosapic; + acpi_entry_iosapic_t *iosapic = NULL; + acpi20_entry_lsapic_t *lsapic = NULL; char *p, *end; + int i; /* Base address of IPI Message Block */ if (madt->lapic_address) { @@ -186,23 +296,27 @@ p = (char *) (madt + 1); end = p + (madt->header.length - sizeof(acpi_madt_t)); + /* Initialize platform interrupt vector array */ + for (i = 0; i < ACPI_MAX_PLATFORM_IRQS; i++) + platform_irq_list[i] = -1; + /* - * Splitted entry parsing to ensure ordering. + * Split-up entry parsing to ensure ordering. */ - while (p < end) { switch (*p) { - case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE: + case ACPI20_ENTRY_LOCAL_APIC_ADDR_OVERRIDE: printk("ACPI 2.0 MADT: LOCAL APIC Override\n"); acpi20_lapic_addr_override(p); break; - case ACPI20_ENTRY_LOCAL_SAPIC: + case ACPI20_ENTRY_LOCAL_SAPIC: printk("ACPI 2.0 MADT: LOCAL SAPIC\n"); + lsapic = (acpi20_entry_lsapic_t *) p; acpi20_lsapic(p); break; - case ACPI20_ENTRY_IO_SAPIC: + case ACPI20_ENTRY_IO_SAPIC: iosapic = (acpi_entry_iosapic_t *) p; if (iosapic_init) /* @@ -218,26 +332,25 @@ ); break; - case ACPI20_ENTRY_PLATFORM_INT_SOURCE: + case ACPI20_ENTRY_PLATFORM_INT_SOURCE: printk("ACPI 2.0 MADT: PLATFORM INT SOURCE\n"); - acpi20_platform(p); + acpi20_platform(p, madt); break; - case ACPI20_ENTRY_LOCAL_APIC: + case ACPI20_ENTRY_LOCAL_APIC: printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); break; - case ACPI20_ENTRY_IO_APIC: + case ACPI20_ENTRY_IO_APIC: printk("ACPI 2.0 MADT: IO APIC entry\n"); break; - case ACPI20_ENTRY_NMI_SOURCE: + case ACPI20_ENTRY_NMI_SOURCE: printk("ACPI 2.0 MADT: NMI SOURCE entry\n"); break; - case ACPI20_ENTRY_LOCAL_APIC_NMI: + case ACPI20_ENTRY_LOCAL_APIC_NMI: printk("ACPI 2.0 MADT: LOCAL APIC NMI entry\n"); break; - case ACPI20_ENTRY_INT_SRC_OVERRIDE: + case ACPI20_ENTRY_INT_SRC_OVERRIDE: break; - default: + default: printk("ACPI 2.0 MADT: unknown entry skip\n"); break; break; } - p += p[1]; } @@ -245,16 +358,35 @@ end = p + (madt->header.length - sizeof(acpi_madt_t)); while (p < end) { + switch (*p) { + case ACPI20_ENTRY_LOCAL_APIC: + if (lsapic) break; + printk("ACPI 2.0 MADT: LOCAL APIC entry\n"); + /* parse local apic if there's no local Sapic */ + break; + case ACPI20_ENTRY_IO_APIC: + if (iosapic) break; + printk("ACPI 2.0 MADT: IO APIC entry\n"); + /* parse ioapic if there's no ioSapic */ + break; + default: + break; + } + p += p[1]; + } + p = (char *) (madt + 1); + end = p + (madt->header.length - sizeof(acpi_madt_t)); + + while (p < end) { switch (*p) { - case ACPI20_ENTRY_INT_SRC_OVERRIDE: + case ACPI20_ENTRY_INT_SRC_OVERRIDE: printk("ACPI 2.0 MADT: INT SOURCE Override\n"); acpi_legacy_irq(p); break; - default: + default: break; } - p += p[1]; } @@ -269,6 +401,7 @@ # ifdef CONFIG_ACPI acpi_xsdt_t *xsdt; acpi_desc_table_hdr_t *hdrp; + acpi_madt_t *madt; int tables, i; if (strncmp(rsdp20->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) { @@ -310,9 +443,76 @@ ACPI_MADT_SIG, ACPI_MADT_SIG_LEN) != 0) continue; - acpi20_parse_madt((acpi_madt_t *) hdrp); + /* Save MADT pointer for later */ + madt = (acpi_madt_t *) hdrp; + acpi20_parse_madt(madt); } +#ifdef CONFIG_SERIAL_ACPI + /* + * Now we're interested in other tables. We want the iosapics already + * initialized, so we do it in a separate loop. + */ + for (i = 0; i < tables; i++) { + hdrp = (acpi_desc_table_hdr_t *) __va(readl_unaligned(&xsdt->entry_ptrs[i])); + /* + * search for SPCR and DBGP table entries so we can enable + * non-pci interrupts to IO-SAPICs. + */ + if (!strncmp(hdrp->signature, ACPI_SPCRT_SIG, ACPI_SPCRT_SIG_LEN) || + !strncmp(hdrp->signature, ACPI_DBGPT_SIG, ACPI_DBGPT_SIG_LEN)) + { + acpi_ser_t *spcr = (void *)hdrp; + unsigned long global_int; + + setup_serial_acpi(hdrp); + + /* + * ACPI is able to describe serial ports that live at non-standard + * memory space addresses and use SAPIC interrupts. If not also + * PCI devices, there would be no interrupt vector information for + * them. This checks for and fixes that situation. + */ + if (spcr->length < sizeof(acpi_ser_t)) + /* table is not long enough for full info, thus no int */ + break; + + /* + * If the device is not in PCI space, but uses a SAPIC interrupt, + * we need to program the SAPIC so that serial can autoprobe for + * the IA64 interrupt vector later on. If the device is in PCI + * space, it should already be setup via the PCI vectors + */ + if (spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE && + spcr->int_type == ACPI_SERIAL_INT_SAPIC) + { + u32 irq_base; + char *iosapic_address; + int vector; + + /* We have a UART in memory space with a SAPIC interrupt */ + global_int = ( (spcr->global_int[3] << 24) + | (spcr->global_int[2] << 16) + | (spcr->global_int[1] << 8) + | spcr->global_int[0]); + + if (!iosapic_register_irq) + continue; + + /* which iosapic does this IRQ belong to? */ + if (acpi20_which_iosapic(global_int, madt, &irq_base, + &iosapic_address) == 0) + { + vector = iosapic_register_irq(global_int, + 1, /* active high polarity */ + 1, /* edge triggered */ + irq_base, + iosapic_address); + } + } + } + } +#endif acpi_cf_terminate(); # ifdef CONFIG_SMP diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c --- v2.4.14/linux/arch/ia64/kernel/efi.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/efi.c Fri Nov 9 14:26:17 2001 @@ -6,8 +6,8 @@ * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999-2001 Hewlett-Packard Co. - * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 1999-2001 Stephane Eranian <eranian@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> * * All EFI Runtime Services are not implemented yet as EFI only * supports physical mode addressing on SoftSDV. This is to be fixed @@ -234,7 +234,7 @@ * The only ITLB entry in region 7 that is used is the one installed by * __start(). That entry covers a 64MB range. */ - mask = ~((1 << KERNEL_PG_SHIFT) - 1); + mask = ~((1 << KERNEL_TR_PAGE_SHIFT) - 1); vaddr = PAGE_OFFSET + md->phys_addr; /* @@ -242,29 +242,32 @@ * mapping. * * PAL code is guaranteed to be aligned on a power of 2 between 4k and - * 256KB. Also from the documentation, it seems like there is an implicit - * guarantee that you will need only ONE ITR to map it. This implies that - * the PAL code is always aligned on its size, i.e., the closest matching - * page size supported by the TLB. Therefore PAL code is guaranteed never - * to cross a 64MB unless it is bigger than 64MB (very unlikely!). So for + * 256KB and that only one ITR is needed to map it. This implies that the + * PAL code is always aligned on its size, i.e., the closest matching page + * size supported by the TLB. Therefore PAL code is guaranteed never to + * cross a 64MB unless it is bigger than 64MB (very unlikely!). So for * now the following test is enough to determine whether or not we need a * dedicated ITR for the PAL code. */ if ((vaddr & mask) == (KERNEL_START & mask)) { - printk(__FUNCTION__ " : no need to install ITR for PAL code\n"); + printk(__FUNCTION__ ": no need to install ITR for PAL code\n"); continue; } + if (md->num_pages << 12 > IA64_GRANULE_SIZE) + panic("Woah! PAL code size bigger than a granule!"); + + mask = ~((1 << IA64_GRANULE_SHIFT) - 1); printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12), - vaddr & mask, (vaddr & mask) + KERNEL_PG_SIZE); + vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE); /* * Cannot write to CRx with PSR.ic=1 */ ia64_clear_ic(flags); ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask, - pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), KERNEL_PG_SHIFT); + pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), IA64_GRANULE_SHIFT); local_irq_restore(flags); ia64_srlz_i(); } @@ -482,5 +485,7 @@ static void __exit efivars_exit(void) { +#ifdef CONFIG_PROC_FS remove_proc_entry(efi_dir->name, NULL); +#endif } diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/efi_stub.S linux/arch/ia64/kernel/efi_stub.S --- v2.4.14/linux/arch/ia64/kernel/efi_stub.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/efi_stub.S Fri Nov 9 14:26:17 2001 @@ -1,8 +1,8 @@ /* * EFI call stub. * - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger <davidm@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * David Mosberger <davidm@hpl.hp.com> * * This stub allows us to make EFI calls in physical mode with interrupts * turned off. We need this because we can't call SetVirtualMap() until @@ -68,17 +68,17 @@ ;; andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared mov out3=in4 - br.call.sptk.few rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode .ret0: mov out4=in5 mov out5=in6 mov out6=in7 - br.call.sptk.few rp=b6 // call the EFI function + br.call.sptk.many rp=b6 // call the EFI function .ret1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 - br.call.sptk.few rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode // return to virtual mode .ret2: mov ar.rsc=loc4 // restore RSE configuration mov ar.pfs=loc1 mov rp=loc0 mov gp=loc2 - br.ret.sptk.few rp + br.ret.sptk.many rp END(efi_call_phys) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/efivars.c linux/arch/ia64/kernel/efivars.c --- v2.4.14/linux/arch/ia64/kernel/efivars.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/efivars.c Fri Nov 9 14:26:17 2001 @@ -65,6 +65,7 @@ MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>"); MODULE_DESCRIPTION("/proc interface to EFI Variables"); +MODULE_LICENSE("GPL"); #define EFIVARS_VERSION "0.03 2001-Apr-20" @@ -276,21 +277,20 @@ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - spin_lock(&efivars_lock); MOD_INC_USE_COUNT; var_data = kmalloc(size, GFP_KERNEL); if (!var_data) { MOD_DEC_USE_COUNT; - spin_unlock(&efivars_lock); return -ENOMEM; } if (copy_from_user(var_data, buffer, size)) { MOD_DEC_USE_COUNT; - spin_unlock(&efivars_lock); + kfree(var_data); return -EFAULT; } + spin_lock(&efivars_lock); /* Since the data ptr we've currently got is probably for a different variable find the right variable. diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S --- v2.4.14/linux/arch/ia64/kernel/entry.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/entry.S Fri Nov 9 14:26:17 2001 @@ -4,7 +4,7 @@ * Kernel entry points. * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com> @@ -15,7 +15,7 @@ * kernel stack. This allows us to handle interrupts without changing * to physical mode. * - * Jonathan Nickin <nicklin@missioncriticallinux.com> + * Jonathan Nicklin <nicklin@missioncriticallinux.com> * Patrick O'Rourke <orourke@missioncriticallinux.com> * 11/07/2000 / @@ -55,7 +55,7 @@ mov out1=in1 // argv mov out2=in2 // envp add out3=16,sp // regs - br.call.sptk.few rp=sys_execve + br.call.sptk.many rp=sys_execve .ret0: cmp4.ge p6,p7=r8,r0 mov ar.pfs=loc1 // restore ar.pfs sxt4 r8=r8 // return 64-bit result @@ -64,7 +64,7 @@ (p6) cmp.ne pKern,pUser=r0,r0 // a successful execve() lands us in user-mode... mov rp=loc0 (p6) mov ar.pfs=r0 // clear ar.pfs on success -(p7) br.ret.sptk.few rp +(p7) br.ret.sptk.many rp /* * In theory, we'd have to zap this state only to prevent leaking of @@ -85,7 +85,7 @@ ldf.fill f26=[sp]; ldf.fill f27=[sp]; mov f28=f0 ldf.fill f29=[sp]; ldf.fill f30=[sp]; mov f31=f0 mov ar.lc=0 - br.ret.sptk.few rp + br.ret.sptk.many rp END(ia64_execve) GLOBAL_ENTRY(sys_clone2) @@ -99,7 +99,7 @@ mov out3=in2 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags - br.call.sptk.few rp=do_fork + br.call.sptk.many rp=do_fork .ret1: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov ar.pfs=loc1 @@ -118,7 +118,7 @@ mov out3=0 adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = ®s mov out0=in0 // out0 = clone_flags - br.call.sptk.few rp=do_fork + br.call.sptk.many rp=do_fork .ret2: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack mov ar.pfs=loc1 @@ -140,23 +140,23 @@ dep r20=0,in0,61,3 // physical address of "current" ;; st8 [r22]=sp // save kernel stack pointer of old task - shr.u r26=r20,KERNEL_PG_SHIFT - mov r16=KERNEL_PG_NUM + shr.u r26=r20,IA64_GRANULE_SHIFT + shr.u r17=r20,KERNEL_TR_PAGE_SHIFT ;; - cmp.ne p6,p7=r26,r16 // check >= 64M && < 128M + cmp.ne p6,p7=KERNEL_TR_PAGE_NUM,r17 adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 ;; /* - * If we've already mapped this task's page, we can skip doing it - * again. + * If we've already mapped this task's page, we can skip doing it again. */ (p6) cmp.eq p7,p6=r26,r27 -(p6) br.cond.dpnt.few .map +(p6) br.cond.dpnt .map ;; -.done: ld8 sp=[r21] // load kernel stack pointer of new task +.done: (p6) ssm psr.ic // if we we had to map, renable the psr.ic bit FIRST!!! ;; (p6) srlz.d + ld8 sp=[r21] // load kernel stack pointer of new task mov IA64_KR(CURRENT)=r20 // update "current" application register mov r8=r13 // return pointer to previously running task mov r13=in0 // set "current" pointer @@ -167,7 +167,7 @@ #ifdef CONFIG_SMP sync.i // ensure "fc"s done by this CPU are visible on other CPUs #endif - br.ret.sptk.few rp // boogie on out in new context + br.ret.sptk.many rp // boogie on out in new context .map: rsm psr.i | psr.ic @@ -175,7 +175,7 @@ ;; srlz.d or r23=r25,r20 // construct PA | page properties - mov r25=KERNEL_PG_SHIFT<<2 + mov r25=IA64_GRANULE_SHIFT<<2 ;; mov cr.itir=r25 mov cr.ifa=in0 // VA of next task... @@ -184,7 +184,7 @@ mov IA64_KR(CURRENT_STACK)=r26 // remember last page we mapped... ;; itr.d dtr[r25]=r23 // wire in new mapping... - br.cond.sptk.many .done + br.cond.sptk .done END(ia64_switch_to) /* @@ -212,24 +212,18 @@ .save @priunat,r17 mov r17=ar.unat // preserve caller's .body -#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) adds r3=80,sp ;; lfetch.fault.excl.nt1 [r3],128 -#endif mov ar.rsc=0 // put RSE in mode: enforced lazy, little endian, pl 0 -#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) adds r2=16+128,sp ;; lfetch.fault.excl.nt1 [r2],128 lfetch.fault.excl.nt1 [r3],128 -#endif adds r14=SW(R4)+16,sp -#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) ;; lfetch.fault.excl [r2] lfetch.fault.excl [r3] -#endif adds r15=SW(R5)+16,sp ;; mov r18=ar.fpsr // preserve fpsr @@ -309,7 +303,7 @@ st8 [r2]=r20 // save ar.bspstore st8 [r3]=r21 // save predicate registers mov ar.rsc=3 // put RSE back into eager mode, pl 0 - br.cond.sptk.few b7 + br.cond.sptk.many b7 END(save_switch_stack) /* @@ -321,11 +315,9 @@ ENTRY(load_switch_stack) .prologue .altrp b7 - .body -#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) + .body lfetch.fault.nt1 [sp] -#endif adds r2=SW(AR_BSPSTORE)+16,sp adds r3=SW(AR_UNAT)+16,sp mov ar.rsc=0 // put RSE into enforced lazy mode @@ -426,7 +418,7 @@ ;; (p6) st4 [r2]=r8 (p6) mov r8=-1 - br.ret.sptk.few rp + br.ret.sptk.many rp END(__ia64_syscall) /* @@ -441,11 +433,11 @@ .body mov loc2=b6 ;; - br.call.sptk.few rp=syscall_trace + br.call.sptk.many rp=syscall_trace .ret3: mov rp=loc0 mov ar.pfs=loc1 mov b6=loc2 - br.ret.sptk.few rp + br.ret.sptk.many rp END(invoke_syscall_trace) /* @@ -462,21 +454,21 @@ GLOBAL_ENTRY(ia64_trace_syscall) PT_REGS_UNWIND_INFO(0) - br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args -.ret6: br.call.sptk.few rp=b6 // do the syscall + br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch syscall args +.ret6: br.call.sptk.many rp=b6 // do the syscall strace_check_retval: cmp.lt p6,p0=r8,r0 // syscall failed? adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 mov r10=0 -(p6) br.cond.sptk.few strace_error // syscall failed -> +(p6) br.cond.sptk strace_error // syscall failed -> ;; // avoid RAW on r10 strace_save_retval: .mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 .mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 ia64_strace_leave_kernel: - br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value -.rety: br.cond.sptk.many ia64_leave_kernel + br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value +.rety: br.cond.sptk ia64_leave_kernel strace_error: ld8 r3=[r2] // load pt_regs.r8 @@ -487,7 +479,7 @@ ;; (p6) mov r10=-1 (p6) mov r8=r9 - br.cond.sptk.few strace_save_retval + br.cond.sptk strace_save_retval END(ia64_trace_syscall) GLOBAL_ENTRY(ia64_ret_from_clone) @@ -497,7 +489,7 @@ * Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the * address of the previously executing task. */ - br.call.sptk.few rp=invoke_schedule_tail + br.call.sptk.many rp=ia64_invoke_schedule_tail .ret8: adds r2=IA64_TASK_PTRACE_OFFSET,r13 ;; @@ -505,7 +497,7 @@ ;; mov r8=0 tbit.nz p6,p0=r2,PT_TRACESYS_BIT -(p6) br strace_check_retval +(p6) br.cond.spnt strace_check_retval ;; // added stop bits to prevent r8 dependency END(ia64_ret_from_clone) // fall through @@ -519,7 +511,7 @@ (p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit .mem.offset 8,0 (p6) st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit -(p7) br.cond.spnt.few handle_syscall_error // handle potential syscall failure +(p7) br.cond.spnt handle_syscall_error // handle potential syscall failure END(ia64_ret_from_syscall) // fall through GLOBAL_ENTRY(ia64_leave_kernel) @@ -527,22 +519,22 @@ lfetch.fault [sp] movl r14=.restart ;; - MOVBR(.ret.sptk,rp,r14,.restart) + mov.ret.sptk rp=r14,.restart .restart: adds r17=IA64_TASK_NEED_RESCHED_OFFSET,r13 adds r18=IA64_TASK_SIGPENDING_OFFSET,r13 #ifdef CONFIG_PERFMON - adds r19=IA64_TASK_PFM_NOTIFY_OFFSET,r13 + adds r19=IA64_TASK_PFM_MUST_BLOCK_OFFSET,r13 #endif ;; #ifdef CONFIG_PERFMON - ld8 r19=[r19] // load current->task.pfm_notify +(pUser) ld8 r19=[r19] // load current->thread.pfm_must_block #endif - ld8 r17=[r17] // load current->need_resched - ld4 r18=[r18] // load current->sigpending +(pUser) ld8 r17=[r17] // load current->need_resched +(pUser) ld4 r18=[r18] // load current->sigpending ;; #ifdef CONFIG_PERFMON - cmp.ne p9,p0=r19,r0 // current->task.pfm_notify != 0? +(pUser) cmp.ne.unc p9,p0=r19,r0 // current->thread.pfm_must_block != 0? #endif (pUser) cmp.ne.unc p7,p0=r17,r0 // current->need_resched != 0? (pUser) cmp.ne.unc p8,p0=r18,r0 // current->sigpending != 0? @@ -550,7 +542,7 @@ adds r2=PT(R8)+16,r12 adds r3=PT(R9)+16,r12 #ifdef CONFIG_PERFMON -(p9) br.call.spnt.many b7=pfm_overflow_notify +(p9) br.call.spnt.many b7=pfm_block_on_overflow #endif #if __GNUC__ < 3 (p7) br.call.spnt.many b7=invoke_schedule @@ -650,13 +642,13 @@ movl r17=PERCPU_ADDR+IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET ;; ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 -(pKern) br.cond.dpnt.few skip_rbs_switch +(pKern) br.cond.dpnt skip_rbs_switch /* * Restore user backing store. * * NOTE: alloc, loadrs, and cover can't be predicated. */ -(pNonSys) br.cond.dpnt.few dont_preserve_current_frame +(pNonSys) br.cond.dpnt dont_preserve_current_frame cover // add current frame into dirty partition ;; mov r19=ar.bsp // get new backing store pointer @@ -687,7 +679,7 @@ shladd in0=loc1,3,r17 mov in1=0 ;; - .align 32 +// .align 32 // gas-2.11.90 is unable to generate a stop bit after .align rse_clear_invalid: // cycle 0 { .mii @@ -706,7 +698,7 @@ }{ .mib mov loc3=0 mov loc4=0 -(pRecurse) br.call.sptk.few b6=rse_clear_invalid +(pRecurse) br.call.sptk.many b6=rse_clear_invalid }{ .mfi // cycle 2 mov loc5=0 @@ -715,7 +707,7 @@ }{ .mib mov loc6=0 mov loc7=0 -(pReturn) br.ret.sptk.few b6 +(pReturn) br.ret.sptk.many b6 } # undef pRecurse # undef pReturn @@ -761,24 +753,24 @@ ;; .mem.offset 0,0; st8.spill [r2]=r9 // store errno in pt_regs.r8 and set unat bit .mem.offset 8,0; st8.spill [r3]=r10 // store error indication in pt_regs.r10 and set unat bit - br.cond.sptk.many ia64_leave_kernel + br.cond.sptk ia64_leave_kernel END(handle_syscall_error) /* * Invoke schedule_tail(task) while preserving in0-in7, which may be needed * in case a system call gets restarted. */ -ENTRY(invoke_schedule_tail) +GLOBAL_ENTRY(ia64_invoke_schedule_tail) .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) alloc loc1=ar.pfs,8,2,1,0 mov loc0=rp mov out0=r8 // Address of previous task ;; - br.call.sptk.few rp=schedule_tail + br.call.sptk.many rp=schedule_tail .ret11: mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp -END(invoke_schedule_tail) +END(ia64_invoke_schedule_tail) #if __GNUC__ < 3 @@ -797,7 +789,7 @@ mov loc0=rp ;; .body - br.call.sptk.few rp=schedule + br.call.sptk.many rp=schedule .ret14: mov ar.pfs=loc1 mov rp=loc0 br.ret.sptk.many rp @@ -824,7 +816,7 @@ .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) st8 [sp]=r9,-16 // allocate space for ar.unat and save it .body - br.call.sptk.few rp=ia64_do_signal + br.call.sptk.many rp=ia64_do_signal .ret15: .restore sp adds sp=16,sp // pop scratch stack space ;; @@ -849,7 +841,7 @@ .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) st8 [sp]=r9,-16 // allocate space for ar.unat and save it .body - br.call.sptk.few rp=ia64_rt_sigsuspend + br.call.sptk.many rp=ia64_rt_sigsuspend .ret17: .restore sp adds sp=16,sp // pop scratch stack space ;; @@ -871,15 +863,15 @@ cmp.eq pNonSys,pSys=r0,r0 // sigreturn isn't a normal syscall... ;; adds out0=16,sp // out0 = &sigscratch - br.call.sptk.few rp=ia64_rt_sigreturn + br.call.sptk.many rp=ia64_rt_sigreturn .ret19: .restore sp 0 adds sp=16,sp ;; ld8 r9=[sp] // load new ar.unat - MOVBR(.sptk,b7,r8,ia64_leave_kernel) + mov.sptk b7=r8,ia64_leave_kernel ;; mov ar.unat=r9 - br b7 + br.many b7 END(sys_rt_sigreturn) GLOBAL_ENTRY(ia64_prepare_handle_unaligned) @@ -890,7 +882,7 @@ mov r16=r0 .prologue DO_SAVE_SWITCH_STACK - br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt + br.call.sptk.many rp=ia64_handle_unaligned // stack frame setup in ivt .ret21: .body DO_LOAD_SWITCH_STACK br.cond.sptk.many rp // goes to ia64_leave_kernel @@ -920,14 +912,14 @@ adds out0=16,sp // &info mov out1=r13 // current adds out2=16+EXTRA_FRAME_SIZE,sp // &switch_stack - br.call.sptk.few rp=unw_init_frame_info + br.call.sptk.many rp=unw_init_frame_info 1: adds out0=16,sp // &info mov b6=loc2 mov loc2=gp // save gp across indirect function call ;; ld8 gp=[in0] mov out1=in1 // arg - br.call.sptk.few rp=b6 // invoke the callback function + br.call.sptk.many rp=b6 // invoke the callback function 1: mov gp=loc2 // restore gp // For now, we don't allow changing registers from within @@ -1026,7 +1018,7 @@ data8 sys_setpriority data8 sys_statfs data8 sys_fstatfs - data8 ia64_ni_syscall // 1105 + data8 sys_gettid // 1105 data8 sys_semget data8 sys_semop data8 sys_semctl @@ -1137,7 +1129,7 @@ data8 sys_clone2 data8 sys_getdents64 data8 sys_getunwind // 1215 - data8 ia64_ni_syscall + data8 sys_readahead data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/entry.h linux/arch/ia64/kernel/entry.h --- v2.4.14/linux/arch/ia64/kernel/entry.h Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/entry.h Fri Nov 9 14:26:17 2001 @@ -1,12 +1,5 @@ #include <linux/config.h> -/* XXX fixme */ -#if defined(CONFIG_ITANIUM_B1_SPECIFIC) -# define MOVBR(type,br,gr,lbl) mov br=gr -#else -# define MOVBR(type,br,gr,lbl) mov##type br=gr,lbl -#endif - /* * Preserved registers that are shared between code in ivt.S and entry.S. Be * careful not to step on these! @@ -62,7 +55,7 @@ ;; \ .fframe IA64_SWITCH_STACK_SIZE; \ adds sp=-IA64_SWITCH_STACK_SIZE,sp; \ - MOVBR(.ret.sptk,b7,r28,1f); \ + mov.ret.sptk b7=r28,1f; \ SWITCH_STACK_SAVES(0); \ br.cond.sptk.many save_switch_stack; \ 1: @@ -71,7 +64,7 @@ movl r28=1f; \ ;; \ invala; \ - MOVBR(.ret.sptk,b7,r28,1f); \ + mov.ret.sptk b7=r28,1f; \ br.cond.sptk.many load_switch_stack; \ 1: .restore sp; \ adds sp=IA64_SWITCH_STACK_SIZE,sp diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/fw-emu.c linux/arch/ia64/kernel/fw-emu.c --- v2.4.14/linux/arch/ia64/kernel/fw-emu.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/fw-emu.c Fri Nov 9 14:26:17 2001 @@ -174,6 +174,43 @@ " ;;\n" " mov ar.lc=r9\n" " mov r8=r0\n" +" ;;\n" +"1: cmp.eq p6,p7=15,r28 /* PAL_PERF_MON_INFO */\n" +"(p7) br.cond.sptk.few 1f\n" +" mov r8=0 /* status = 0 */\n" +" movl r9 =0x12082004 /* generic=4 width=32 retired=8 cycles=18 */\n" +" mov r10=0 /* reserved */\n" +" mov r11=0 /* reserved */\n" +" mov r16=0xffff /* implemented PMC */\n" +" mov r17=0xffff /* implemented PMD */\n" +" add r18=8,r29 /* second index */\n" +" ;;\n" +" st8 [r29]=r16,16 /* store implemented PMC */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" +" st8 [r29]=r0,16 /* store implemented PMC */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" +" st8 [r29]=r17,16 /* store implemented PMD */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" mov r16=0xf0 /* cycles count capable PMC */\n" +" ;;\n" +" st8 [r29]=r0,16 /* store implemented PMC */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" mov r17=0x10 /* retired bundles capable PMC */\n" +" ;;\n" +" st8 [r29]=r16,16 /* store cycles capable */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" +" st8 [r29]=r0,16 /* store implemented PMC */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" +" st8 [r29]=r17,16 /* store retired bundle capable */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" +" st8 [r29]=r0,16 /* store implemented PMC */\n" +" st8 [r18]=r0,16 /* clear remaining bits */\n" +" ;;\n" "1: br.cond.sptk.few rp\n" "stacked:\n" " br.ret.sptk.few rp\n" @@ -414,11 +451,6 @@ #ifdef CONFIG_IA64_SDV strcpy(sal_systab->oem_id, "Intel"); strcpy(sal_systab->product_id, "SDV"); -#endif - -#ifdef CONFIG_IA64_SGI_SN1_SIM - strcpy(sal_systab->oem_id, "SGI"); - strcpy(sal_systab->product_id, "SN1"); #endif /* fill in an entry point: */ diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S --- v2.4.14/linux/arch/ia64/kernel/gate.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/gate.S Fri Nov 9 14:26:17 2001 @@ -3,7 +3,7 @@ * region. For now, it contains the signal trampoline code only. * * Copyright (C) 1999-2001 Hewlett-Packard Co - * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/asmmacro.h> @@ -18,7 +18,6 @@ # define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET) # define ARG1_OFF (16 + IA64_SIGFRAME_ARG1_OFFSET) # define ARG2_OFF (16 + IA64_SIGFRAME_ARG2_OFFSET) -# define RBS_BASE_OFF (16 + IA64_SIGFRAME_RBS_BASE_OFFSET) # define SIGHANDLER_OFF (16 + IA64_SIGFRAME_HANDLER_OFFSET) # define SIGCONTEXT_OFF (16 + IA64_SIGFRAME_SIGCONTEXT_OFFSET) @@ -32,6 +31,8 @@ # define PR_OFF IA64_SIGCONTEXT_PR_OFFSET # define RP_OFF IA64_SIGCONTEXT_B0_OFFSET # define SP_OFF IA64_SIGCONTEXT_R12_OFFSET +# define RBS_BASE_OFF IA64_SIGCONTEXT_RBS_BASE_OFFSET +# define LOADRS_OFF IA64_SIGCONTEXT_LOADRS_OFFSET # define base0 r2 # define base1 r3 /* @@ -73,34 +74,37 @@ .vframesp SP_OFF+SIGCONTEXT_OFF .body - .prologue + .label_state 1 + adds base0=SIGHANDLER_OFF,sp - adds base1=RBS_BASE_OFF,sp + adds base1=RBS_BASE_OFF+SIGCONTEXT_OFF,sp br.call.sptk.many rp=1f 1: ld8 r17=[base0],(ARG0_OFF-SIGHANDLER_OFF) // get pointer to signal handler's plabel - ld8 r15=[base1],(ARG1_OFF-RBS_BASE_OFF) // get address of new RBS base (or NULL) + ld8 r15=[base1] // get address of new RBS base (or NULL) cover // push args in interrupted frame onto backing store ;; + cmp.ne p8,p0=r15,r0 // do we need to switch the rbs? + mov.m r9=ar.bsp // fetch ar.bsp + .spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF +(p8) br.cond.spnt setup_rbs // yup -> (clobbers r14, r15, and r16) +back_from_setup_rbs: + .save ar.pfs, r8 alloc r8=ar.pfs,0,0,3,0 // get CFM0, EC0, and CPL0 into r8 ld8 out0=[base0],16 // load arg0 (signum) + adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1 ;; ld8 out1=[base1] // load arg1 (siginfop) ld8 r10=[r17],8 // get signal handler entry point ;; ld8 out2=[base0] // load arg2 (sigcontextp) ld8 gp=[r17] // get signal handler's global pointer - cmp.ne p8,p0=r15,r0 // do we need to switch the rbs? - mov.m r17=ar.bsp // fetch ar.bsp - .spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF -(p8) br.cond.spnt.few setup_rbs // yup -> (clobbers r14 and r16) -back_from_setup_rbs: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp ;; .spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF - st8 [base0]=r17,(CFM_OFF-BSP_OFF) // save sc_ar_bsp + st8 [base0]=r9,(CFM_OFF-BSP_OFF) // save sc_ar_bsp dep r8=0,r8,38,26 // clear EC0, CPL0 and reserved bits adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp ;; @@ -123,7 +127,7 @@ ;; stf.spill [base0]=f14,32 stf.spill [base1]=f15,32 - br.call.sptk.few rp=b6 // call the signal handler + br.call.sptk.many rp=b6 // call the signal handler .ret0: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp ;; ld8 r15=[base0],(CFM_OFF-BSP_OFF) // fetch sc_ar_bsp and advance to CFM_OFF @@ -131,7 +135,7 @@ ;; ld8 r8=[base0] // restore (perhaps modified) CFM0, EC0, and CPL0 cmp.ne p8,p0=r14,r15 // do we need to restore the rbs? -(p8) br.cond.spnt.few restore_rbs // yup -> (clobbers r14 and r16) +(p8) br.cond.spnt restore_rbs // yup -> (clobbers r14 and r16) ;; back_from_restore_rbs: adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp @@ -154,30 +158,52 @@ mov r15=__NR_rt_sigreturn break __BREAK_SYSCALL + .body + .copy_state 1 setup_rbs: - flushrs // must be first in insn mov ar.rsc=0 // put RSE into enforced lazy mode - adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp ;; - mov r14=ar.rnat // get rnat as updated by flushrs - mov ar.bspstore=r15 // set new register backing store area + .save ar.rnat, r16 + mov r16=ar.rnat // save RNaT before switching backing store area + adds r14=(RNAT_OFF+SIGCONTEXT_OFF),sp + + mov ar.bspstore=r15 // switch over to new register backing store area ;; .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF - st8 [r16]=r14 // save sc_ar_rnat + st8 [r14]=r16 // save sc_ar_rnat + adds r14=(LOADRS_OFF+SIGCONTEXT_OFF),sp + + mov.m r16=ar.bsp // sc_loadrs <- (new bsp - new bspstore) << 16 + ;; + invala + sub r15=r16,r15 + ;; + shl r15=r15,16 + ;; + st8 [r14]=r15 // save sc_loadrs mov ar.rsc=0xf // set RSE into eager mode, pl 3 - invala // invalidate ALAT - br.cond.sptk.many back_from_setup_rbs + br.cond.sptk back_from_setup_rbs + .prologue + .copy_state 1 + .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF + .body restore_rbs: - flushrs - mov ar.rsc=0 // put RSE into enforced lazy mode + alloc r2=ar.pfs,0,0,0,0 // alloc null frame + adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp + ;; + ld8 r14=[r16] adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp ;; + mov ar.rsc=r14 // put RSE into enforced lazy mode ld8 r14=[r16] // get new rnat - mov ar.bspstore=r15 // set old register backing store area ;; - mov ar.rnat=r14 // establish new rnat + loadrs // restore dirty partition + ;; + mov ar.bspstore=r15 // switch back to old register backing store area + ;; + mov ar.rnat=r14 // restore RNaT mov ar.rsc=0xf // (will be restored later on from sc_ar_rsc) // invala not necessary as that will happen when returning to user-mode - br.cond.sptk.many back_from_restore_rbs + br.cond.sptk back_from_restore_rbs END(ia64_sigtramp) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/head.S linux/arch/ia64/kernel/head.S --- v2.4.14/linux/arch/ia64/kernel/head.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/head.S Fri Nov 9 14:26:17 2001 @@ -6,8 +6,8 @@ * entry point. * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 2001 Stephane Eranian <eranian@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Intel Corp. @@ -63,17 +63,17 @@ * that maps the kernel's text and data: */ rsm psr.i | psr.ic - mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (KERNEL_PG_SHIFT << 2)) + mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (IA64_GRANULE_SHIFT << 2)) ;; srlz.i - mov r18=KERNEL_PG_SHIFT<<2 - movl r17=PAGE_OFFSET + KERNEL_PG_NUM*KERNEL_PG_SIZE + mov r18=KERNEL_TR_PAGE_SHIFT<<2 + movl r17=KERNEL_START ;; mov rr[r17]=r16 mov cr.itir=r18 mov cr.ifa=r17 mov r16=IA64_TR_KERNEL - movl r18=(KERNEL_PG_NUM*KERNEL_PG_SIZE | PAGE_KERNEL) + movl r18=((1 << KERNEL_TR_PAGE_SHIFT) | PAGE_KERNEL) ;; srlz.i ;; @@ -86,7 +86,8 @@ /* * Switch into virtual mode: */ - movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN) + movl r16=(IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN \ + |IA64_PSR_DI) ;; mov cr.ipsr=r16 movl r17=1f @@ -111,7 +112,7 @@ ;; #ifdef CONFIG_IA64_EARLY_PRINTK - mov r3=(6<<8) | (KERNEL_PG_SHIFT<<2) + mov r3=(6<<8) | (IA64_GRANULE_SHIFT<<2) movl r2=6<<61 ;; mov rr[r2]=r3 @@ -144,6 +145,7 @@ cmp4.ne isAP,isBP=r3,r0 ;; // RAW on r2 extr r3=r2,0,61 // r3 == phys addr of task struct + mov r16=KERNEL_TR_PAGE_NUM ;; // load the "current" pointer (r13) and ar.k6 with the current task @@ -151,7 +153,7 @@ mov IA64_KR(CURRENT)=r3 // Physical address // initialize k4 to a safe value (64-128MB is mapped by TR_KERNEL) - mov IA64_KR(CURRENT_STACK)=1 + mov IA64_KR(CURRENT_STACK)=r16 /* * Reserve space at the top of the stack for "struct pt_regs". Kernel threads * don't store interesting values in that structure, but the space still needs @@ -183,31 +185,31 @@ alloc r2=ar.pfs,0,0,2,0 movl out0=alive_msg ;; - br.call.sptk.few rp=early_printk + br.call.sptk.many rp=early_printk 1: // force new bundle #endif /* CONFIG_IA64_EARLY_PRINTK */ #ifdef CONFIG_SMP -(isAP) br.call.sptk.few rp=start_secondary +(isAP) br.call.sptk.many rp=start_secondary .ret0: -(isAP) br.cond.sptk.few self +(isAP) br.cond.sptk self #endif // This is executed by the bootstrap processor (bsp) only: #ifdef CONFIG_IA64_FW_EMU // initialize PAL & SAL emulator: - br.call.sptk.few rp=sys_fw_init + br.call.sptk.many rp=sys_fw_init .ret1: #endif - br.call.sptk.few rp=start_kernel + br.call.sptk.many rp=start_kernel .ret2: addl r3=@ltoff(halt_msg),gp ;; alloc r2=ar.pfs,8,0,2,0 ;; ld8 out0=[r3] - br.call.sptk.few b0=console_print -self: br.sptk.few self // endless loop + br.call.sptk.many b0=console_print +self: br.sptk.many self // endless loop END(_start) GLOBAL_ENTRY(ia64_save_debug_regs) @@ -218,7 +220,7 @@ add r19=IA64_NUM_DBG_REGS*8,in0 ;; 1: mov r16=dbr[r18] -#if defined(CONFIG_ITANIUM_C0_SPECIFIC) +#ifdef CONFIG_ITANIUM ;; srlz.d #endif @@ -227,17 +229,15 @@ ;; st8.nta [in0]=r16,8 st8.nta [r19]=r17,8 - br.cloop.sptk.few 1b + br.cloop.sptk.many 1b ;; mov ar.lc=r20 // restore ar.lc - br.ret.sptk.few rp + br.ret.sptk.many rp END(ia64_save_debug_regs) GLOBAL_ENTRY(ia64_load_debug_regs) alloc r16=ar.pfs,1,0,0,0 -#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) lfetch.nta [in0] -#endif mov r20=ar.lc // preserve ar.lc add r19=IA64_NUM_DBG_REGS*8,in0 mov ar.lc=IA64_NUM_DBG_REGS-1 @@ -248,15 +248,15 @@ add r18=1,r18 ;; mov dbr[r18]=r16 -#if defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) || defined(CONFIG_ITANIUM_C0_SPECIFIC) +#ifdef CONFIG_ITANIUM ;; - srlz.d + srlz.d // Errata 132 (NoFix status) #endif mov ibr[r18]=r17 - br.cloop.sptk.few 1b + br.cloop.sptk.many 1b ;; mov ar.lc=r20 // restore ar.lc - br.ret.sptk.few rp + br.ret.sptk.many rp END(ia64_load_debug_regs) GLOBAL_ENTRY(__ia64_save_fpu) @@ -406,7 +406,7 @@ ;; stf.spill.nta [in0]=f126,32 stf.spill.nta [ r3]=f127,32 - br.ret.sptk.few rp + br.ret.sptk.many rp END(__ia64_save_fpu) GLOBAL_ENTRY(__ia64_load_fpu) @@ -556,7 +556,7 @@ ;; ldf.fill.nta f126=[in0],32 ldf.fill.nta f127=[ r3],32 - br.ret.sptk.few rp + br.ret.sptk.many rp END(__ia64_load_fpu) GLOBAL_ENTRY(__ia64_init_fpu) @@ -690,7 +690,7 @@ ;; ldf.fill f126=[sp] mov f127=f0 - br.ret.sptk.few rp + br.ret.sptk.many rp END(__ia64_init_fpu) /* @@ -738,7 +738,7 @@ rfi // must be last insn in group ;; 1: mov rp=r14 - br.ret.sptk.few rp + br.ret.sptk.many rp END(ia64_switch_mode) #ifdef CONFIG_IA64_BRL_EMU @@ -752,7 +752,7 @@ alloc r16=ar.pfs,1,0,0,0; \ mov reg=r32; \ ;; \ - br.ret.sptk rp; \ + br.ret.sptk.many rp; \ END(ia64_set_##reg) SET_REG(b1); @@ -816,12 +816,11 @@ ;; cmp.ne p15,p0=tmp,r0 mov tmp=ar.itc -(p15) br.cond.sptk.few .retry // lock is still busy +(p15) br.cond.sptk .retry // lock is still busy ;; // try acquiring lock (we know ar.ccv is still zero!): mov tmp=1 ;; - IA64_SEMFIX_INSN cmpxchg4.acq tmp=[r31],tmp,ar.ccv ;; cmp.eq p15,p0=tmp,r0 diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/ia64_ksyms.c linux/arch/ia64/kernel/ia64_ksyms.c --- v2.4.14/linux/arch/ia64/kernel/ia64_ksyms.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/ia64_ksyms.c Fri Nov 9 14:26:17 2001 @@ -69,6 +69,8 @@ #include <asm/pgalloc.h> +EXPORT_SYMBOL(flush_tlb_range); + #ifdef CONFIG_SMP EXPORT_SYMBOL(smp_flush_tlb_all); @@ -145,4 +147,3 @@ #include <linux/proc_fs.h> extern struct proc_dir_entry *efi_dir; EXPORT_SYMBOL(efi_dir); - diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/iosapic.c linux/arch/ia64/kernel/iosapic.c --- v2.4.14/linux/arch/ia64/kernel/iosapic.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/iosapic.c Fri Nov 9 14:26:17 2001 @@ -53,6 +53,7 @@ #include <asm/acpi-ext.h> #include <asm/acpikcfg.h> #include <asm/delay.h> +#include <asm/hw_irq.h> #include <asm/io.h> #include <asm/iosapic.h> #include <asm/machvec.h> @@ -325,7 +326,7 @@ set_affinity: iosapic_set_affinity }; -static unsigned int +unsigned int iosapic_version (char *addr) { /* @@ -342,6 +343,113 @@ } /* + * ACPI can describe IOSAPIC interrupts via static tables and namespace + * methods. This provides an interface to register those interrupts and + * program the IOSAPIC RTE. + */ +int +iosapic_register_irq (u32 global_vector, unsigned long polarity, unsigned long + edge_triggered, u32 base_irq, char *iosapic_address) +{ + irq_desc_t *idesc; + struct hw_interrupt_type *irq_type; + int vector; + + vector = iosapic_irq_to_vector(global_vector); + if (vector < 0) + vector = ia64_alloc_irq(); + + /* fill in information from this vector's IOSAPIC */ + iosapic_irq[vector].addr = iosapic_address; + iosapic_irq[vector].base_irq = base_irq; + iosapic_irq[vector].pin = global_vector - iosapic_irq[vector].base_irq; + iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; + iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; + + if (edge_triggered) { + iosapic_irq[vector].trigger = IOSAPIC_EDGE; + irq_type = &irq_type_iosapic_edge; + } else { + iosapic_irq[vector].trigger = IOSAPIC_LEVEL; + irq_type = &irq_type_iosapic_level; + } + + idesc = irq_desc(vector); + if (idesc->handler != irq_type) { + if (idesc->handler != &no_irq_type) + printk("iosapic_register_irq(): changing vector 0x%02x from" + "%s to %s\n", vector, idesc->handler->typename, irq_type->typename); + idesc->handler = irq_type; + } + + printk("IOSAPIC %x(%s,%s) -> Vector %x\n", global_vector, + (polarity ? "high" : "low"), (edge_triggered ? "edge" : "level"), vector); + + /* program the IOSAPIC routing table */ + set_rte(vector, (ia64_get_lid() >> 16) & 0xffff); + return vector; +} + +/* + * ACPI calls this when it finds an entry for a platform interrupt. + * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). + */ +int +iosapic_register_platform_irq (u32 int_type, u32 global_vector, u32 iosapic_vector, + u16 eid, u16 id, unsigned long polarity, + unsigned long edge_triggered, u32 base_irq, char *iosapic_address) +{ + struct hw_interrupt_type *irq_type; + irq_desc_t *idesc; + int vector; + + switch (int_type) { + case ACPI20_ENTRY_PIS_CPEI: + vector = IA64_PCE_VECTOR; + iosapic_irq[vector].dmode = IOSAPIC_LOWEST_PRIORITY; + break; + case ACPI20_ENTRY_PIS_INIT: + vector = ia64_alloc_irq(); + iosapic_irq[vector].dmode = IOSAPIC_INIT; + break; + default: + printk("iosapic_register_platform_irq(): invalid int type\n"); + return -1; + } + + /* fill in information from this vector's IOSAPIC */ + iosapic_irq[vector].addr = iosapic_address; + iosapic_irq[vector].base_irq = base_irq; + iosapic_irq[vector].pin = global_vector - iosapic_irq[vector].base_irq; + iosapic_irq[vector].polarity = polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW; + + if (edge_triggered) { + iosapic_irq[vector].trigger = IOSAPIC_EDGE; + irq_type = &irq_type_iosapic_edge; + } else { + iosapic_irq[vector].trigger = IOSAPIC_LEVEL; + irq_type = &irq_type_iosapic_level; + } + + idesc = irq_desc(vector); + if (idesc->handler != irq_type) { + if (idesc->handler != &no_irq_type) + printk("iosapic_register_platform_irq(): changing vector 0x%02x from" + "%s to %s\n", vector, idesc->handler->typename, irq_type->typename); + idesc->handler = irq_type; + } + + printk("PLATFORM int %x: IOSAPIC %x(%s,%s) -> Vector %x CPU %.02u:%.02u\n", + int_type, global_vector, (polarity ? "high" : "low"), + (edge_triggered ? "edge" : "level"), vector, eid, id); + + /* program the IOSAPIC routing table */ + set_rte(vector, ((id << 8) | eid) & 0xffff); + return vector; +} + + +/* * ACPI calls this when it finds an entry for a legacy ISA interrupt. Note that the * irq_base and IOSAPIC address must be set in iosapic_init(). */ @@ -436,7 +544,7 @@ /* the interrupt route is for another controller... */ continue; - if (irq < 16) + if (pcat_compat && (irq < 16)) vector = isa_irq_to_vector(irq); else { vector = iosapic_irq_to_vector(irq); @@ -515,6 +623,23 @@ printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> 0x%02x\n", dev->bus->number, PCI_SLOT(dev->devfn), pin, vector); dev->irq = vector; + +#ifdef CONFIG_SMP + /* + * For platforms that do not support interrupt redirect + * via the XTP interface, we can round-robin the PCI + * device interrupts to the processors + */ + if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) { + static int cpu_index = 0; + + set_rte(vector, cpu_physical_id(cpu_index) & 0xffff); + + cpu_index++; + if (cpu_index >= smp_num_cpus) + cpu_index = 0; + } +#endif } } /* diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c --- v2.4.14/linux/arch/ia64/kernel/irq.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/irq.c Fri Nov 9 14:26:17 2001 @@ -33,6 +33,7 @@ #include <linux/irq.h> #include <linux/proc_fs.h> +#include <asm/atomic.h> #include <asm/io.h> #include <asm/smp.h> #include <asm/system.h> @@ -121,7 +122,10 @@ end_none }; -volatile unsigned long irq_err_count; +atomic_t irq_err_count; +#if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG) +atomic_t irq_mis_count; +#endif /* * Generic, controller-independent functions: @@ -164,14 +168,17 @@ p += sprintf(p, "%10u ", nmi_count(cpu_logical_map(j))); p += sprintf(p, "\n"); -#if defined(CONFIG_SMP) && defined(__i386__) +#if defined(CONFIG_SMP) && defined(CONFIG_X86) 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); + p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); +#if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG) + p += sprintf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); +#endif return p - buf; } @@ -183,7 +190,7 @@ #ifdef CONFIG_SMP unsigned int global_irq_holder = NO_PROC_ID; -volatile unsigned long global_irq_lock; /* long for set_bit --RR */ +unsigned volatile long global_irq_lock; /* pedantic: long for set_bit --RR */ extern void show_stack(unsigned long* esp); @@ -201,14 +208,14 @@ printk(" %d",bh_count(i)); printk(" ]\nStack dumps:"); -#if defined(__ia64__) +#if defined(CONFIG_IA64) /* * We can't unwind the stack of another CPU without access to * the registers of that CPU. And sending an IPI when we're * in a potentially wedged state doesn't sound like a smart * idea. */ -#elif defined(__i386__) +#elif defined(CONFIG_X86) for(i=0;i< smp_num_cpus;i++) { unsigned long esp; if(i==cpu) @@ -261,7 +268,7 @@ /* * We have to allow irqs to arrive between __sti and __cli */ -# ifdef __ia64__ +# ifdef CONFIG_IA64 # define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop 0") # else # define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") @@ -331,6 +338,9 @@ /* Uhhuh.. Somebody else got it. Wait.. */ do { do { +#ifdef CONFIG_X86 + rep_nop(); +#endif } while (test_bit(0,&global_irq_lock)); } while (test_and_set_bit(0,&global_irq_lock)); } @@ -364,7 +374,7 @@ { unsigned int flags; -#ifdef __ia64__ +#ifdef CONFIG_IA64 __save_flags(flags); if (flags & IA64_PSR_I) { __cli(); @@ -403,7 +413,7 @@ int cpu = smp_processor_id(); __save_flags(flags); -#ifdef __ia64__ +#ifdef CONFIG_IA64 local_enabled = (flags & IA64_PSR_I) != 0; #else local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; @@ -476,13 +486,19 @@ 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. +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables and Enables are + * nested. + * Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. */ -void inline disable_irq_nosync(unsigned int irq) + +inline void disable_irq_nosync(unsigned int irq) { irq_desc_t *desc = irq_desc(irq); unsigned long flags; @@ -495,10 +511,19 @@ spin_unlock_irqrestore(&desc->lock, flags); } -/* - * Synchronous version of the above, making sure the IRQ is - * no longer running on any other IRQ.. +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Enables and Disables are + * nested. + * This function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. */ + void disable_irq(unsigned int irq) { disable_irq_nosync(irq); @@ -512,6 +537,17 @@ #endif } +/** + * enable_irq - enable handling of an irq + * @irq: Interrupt to enable + * + * Undoes the effect of one call to disable_irq(). If this + * matches the last disable, processing of interrupts on this + * IRQ line is re-enabled. + * + * This function may be called from IRQ context. + */ + void enable_irq(unsigned int irq) { irq_desc_t *desc = irq_desc(irq); @@ -533,7 +569,8 @@ desc->depth--; break; case 0: - printk("enable_irq() unbalanced from %p\n", (void *) __builtin_return_address(0)); + printk("enable_irq(%u) unbalanced from %p\n", + irq, (void *) __builtin_return_address(0)); } spin_unlock_irqrestore(&desc->lock, flags); } @@ -626,11 +663,41 @@ desc->handler->end(irq); spin_unlock(&desc->lock); } - if (local_softirq_pending()) - do_softirq(); return 1; } +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ + int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, @@ -676,6 +743,24 @@ return retval; } +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function may be called from interrupt context. + * + * Bugs: Attempting to free an irq in a handler for the same irq hangs + * the machine. + */ + void free_irq(unsigned int irq, void *dev_id) { irq_desc_t *desc; @@ -726,6 +811,17 @@ * with "IRQ_WAITING" cleared and the interrupt * disabled. */ + +static DECLARE_MUTEX(probe_sem); + +/** + * probe_irq_on - begin an interrupt autodetect + * + * Commence probing for an interrupt. The interrupts are scanned + * and a mask of potential interrupt lines is returned. + * + */ + unsigned long probe_irq_on(void) { unsigned int i; @@ -733,6 +829,7 @@ unsigned long val; unsigned long delay; + down(&probe_sem); /* * something may have generated an irq long ago and we want to * flush such a longstanding irq before considering it as spurious. @@ -799,10 +896,19 @@ return val; } -/* - * Return a mask of triggered interrupts (this - * can handle only legacy ISA interrupts). +/** + * probe_irq_mask - scan a bitmap of interrupt lines + * @val: mask of interrupts to consider + * + * Scan the ISA bus interrupt lines and return a bitmap of + * active interrupts. The interrupt probe logic state is then + * returned to its previous value. + * + * Note: we need to scan all the irq's even though we will + * only return ISA irq numbers - just so that we reset them + * all to a known state. */ + unsigned int probe_irq_mask(unsigned long val) { int i; @@ -825,14 +931,29 @@ } spin_unlock_irq(&desc->lock); } + up(&probe_sem); return mask & val; } -/* - * Return the one interrupt that triggered (this can - * handle any interrupt source) +/** + * probe_irq_off - end an interrupt autodetect + * @val: mask of potential interrupts (unused) + * + * Scans the unused interrupt lines and returns the line which + * appears to have triggered the interrupt. If no interrupt was + * found then zero is returned. If more than one interrupt is + * found then minus the first candidate is returned to indicate + * their is doubt. + * + * The interrupt probe logic state is returned to its previous + * value. + * + * BUGS: When used in a module (which arguably shouldnt happen) + * nothing prevents two IRQ probe callers from overlapping. The + * results of this are non-optimal. */ + int probe_irq_off(unsigned long val) { int i, irq_found, nr_irqs; @@ -857,6 +978,7 @@ } spin_unlock_irq(&desc->lock); } + up(&probe_sem); if (nr_irqs > 1) irq_found = -irq_found; @@ -911,7 +1033,7 @@ if (!shared) { desc->depth = 0; - desc->status &= ~IRQ_DISABLED; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING); desc->handler->startup(irq); } spin_unlock_irqrestore(&desc->lock,flags); @@ -922,20 +1044,9 @@ static struct proc_dir_entry * root_irq_dir; static struct proc_dir_entry * irq_dir [NR_IRQS]; -static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; - -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; #define HEX_DIGITS 8 -static int irq_affinity_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - if (count < HEX_DIGITS+1) - return -EINVAL; - return sprintf (page, "%08lx\n", irq_affinity[(long)data]); -} - static unsigned int parse_hex_value (const char *buffer, unsigned long count, unsigned long *ret) { @@ -973,6 +1084,20 @@ return 0; } +#if CONFIG_SMP + +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; + +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", irq_affinity[(long)data]); +} + static int irq_affinity_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) { @@ -984,7 +1109,6 @@ err = parse_hex_value(buffer, count, &new_value); -#if CONFIG_SMP /* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least @@ -992,7 +1116,6 @@ */ if (!(new_value & cpu_online_map)) return -EINVAL; -#endif irq_affinity[irq] = new_value; irq_desc(irq)->handler->set_affinity(irq, new_value); @@ -1000,6 +1123,8 @@ return full_count; } +#endif /* CONFIG_SMP */ + static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -1027,7 +1152,6 @@ static void register_irq_proc (unsigned int irq) { - struct proc_dir_entry *entry; char name [MAX_NAMELEN]; if (!root_irq_dir || (irq_desc(irq)->handler == &no_irq_type)) @@ -1039,15 +1163,22 @@ /* create /proc/irq/1234 */ irq_dir[irq] = proc_mkdir(name, root_irq_dir); - /* create /proc/irq/1234/smp_affinity */ - entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); - - entry->nlink = 1; - entry->data = (void *)(long)irq; - entry->read_proc = irq_affinity_read_proc; - entry->write_proc = irq_affinity_write_proc; +#if CONFIG_SMP + { + struct proc_dir_entry *entry; + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); + + if (entry) { + entry->nlink = 1; + entry->data = (void *)(long)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + } - smp_affinity_entry[irq] = entry; + smp_affinity_entry[irq] = entry; + } +#endif } unsigned long prof_cpu_mask = -1; @@ -1062,6 +1193,9 @@ /* create /proc/irq/prof_cpu_mask */ entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); + + if (!entry) + return; entry->nlink = 1; entry->data = (void *)&prof_cpu_mask; diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/irq_ia64.c linux/arch/ia64/kernel/irq_ia64.c --- v2.4.14/linux/arch/ia64/kernel/irq_ia64.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/irq_ia64.c Fri Nov 9 14:26:17 2001 @@ -1,9 +1,9 @@ /* * linux/arch/ia64/kernel/irq.c * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> - * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Stephane Eranian <eranian@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> * * 6/10/99: Updated to bring in sync with x86 version to facilitate * support for SMP and different interrupt controllers. @@ -131,6 +131,13 @@ ia64_eoi(); vector = ia64_get_ivr(); } + /* + * This must be done *after* the ia64_eoi(). For example, the keyboard softirq + * handler needs to be able to wait for further keyboard interrupts, which can't + * come through until ia64_eoi() has been done. + */ + if (local_softirq_pending()) + do_softirq(); } #ifdef CONFIG_SMP diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S --- v2.4.14/linux/arch/ia64/kernel/ivt.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/ivt.S Fri Nov 9 14:26:17 2001 @@ -2,8 +2,8 @@ * arch/ia64/kernel/ivt.S * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> - * Copyright (C) 1998-2001 David Mosberger <davidm@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> + * David Mosberger <davidm@hpl.hp.com> * * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> TLB handling for SMP * 00/12/20 David Mosberger-Tang <davidm@hpl.hp.com> DTLB/ITLB handler now uses virtual PT. @@ -157,7 +157,7 @@ ;; (p10) itc.i r18 // insert the instruction TLB entry (p11) itc.d r18 // insert the data TLB entry -(p6) br.spnt.many page_fault // handle bad address/page not present (page fault) +(p6) br.cond.spnt.many page_fault // handle bad address/page not present (page fault) mov cr.ifa=r22 /* @@ -213,7 +213,7 @@ ;; mov b0=r29 tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? -(p6) br.cond.spnt.many page_fault +(p6) br.cond.spnt page_fault ;; itc.i r18 ;; @@ -251,7 +251,7 @@ ;; mov b0=r29 tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? -(p6) br.cond.spnt.many page_fault +(p6) br.cond.spnt page_fault ;; itc.d r18 ;; @@ -286,7 +286,7 @@ ;; (p8) mov cr.iha=r17 (p8) mov r29=b0 // save b0 -(p8) br.cond.dptk.many itlb_fault +(p8) br.cond.dptk itlb_fault #endif extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl shr.u r18=r16,57 // move address bit 61 to bit 4 @@ -297,7 +297,7 @@ dep r19=r17,r19,0,12 // insert PTE control bits into r19 ;; or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 -(p8) br.cond.spnt.many page_fault +(p8) br.cond.spnt page_fault ;; itc.i r19 // insert the TLB entry mov pr=r31,-1 @@ -324,7 +324,7 @@ ;; (p8) mov cr.iha=r17 (p8) mov r29=b0 // save b0 -(p8) br.cond.dptk.many dtlb_fault +(p8) br.cond.dptk dtlb_fault #endif extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? @@ -333,7 +333,7 @@ ;; andcm r18=0x10,r18 // bit 4=~address-bit(61) cmp.ne p8,p0=r0,r23 -(p8) br.cond.spnt.many page_fault +(p8) br.cond.spnt page_fault dep r21=-1,r21,IA64_PSR_ED_BIT,1 dep r19=r17,r19,0,12 // insert PTE control bits into r19 @@ -429,7 +429,7 @@ ;; (p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry -(p6) br.cond.spnt.many page_fault +(p6) br.cond.spnt page_fault mov b0=r30 br.sptk.many b0 // return to continuation point END(nested_dtlb_miss) @@ -534,15 +534,6 @@ ;; 1: ld8 r18=[r17] ;; -# if defined(CONFIG_IA32_SUPPORT) && defined(CONFIG_ITANIUM_B0_SPECIFIC) - /* - * Erratum 85 (Access bit fault could be reported before page not present fault) - * If the PTE is indicates the page is not present, then just turn this into a - * page fault. - */ - tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? -(p6) br.sptk page_fault // page wasn't present -# endif mov ar.ccv=r18 // set compare value for cmpxchg or r25=_PAGE_A,r18 // set the accessed bit ;; @@ -564,15 +555,6 @@ ;; 1: ld8 r18=[r17] ;; -# if defined(CONFIG_IA32_SUPPORT) && defined(CONFIG_ITANIUM_B0_SPECIFIC) - /* - * Erratum 85 (Access bit fault could be reported before page not present fault) - * If the PTE is indicates the page is not present, then just turn this into a - * page fault. - */ - tbit.z p6,p0=r18,_PAGE_P_BIT // page present bit cleared? -(p6) br.sptk page_fault // page wasn't present -# endif or r18=_PAGE_A,r18 // set the accessed bit mov b0=r29 // restore b0 ;; @@ -640,7 +622,7 @@ mov r31=pr // prepare to save predicates ;; cmp.eq p0,p7=r16,r17 // is this a system call? (p7 <- false, if so) -(p7) br.cond.spnt.many non_syscall +(p7) br.cond.spnt non_syscall SAVE_MIN // uses r31; defines r2: @@ -656,7 +638,7 @@ adds r3=8,r2 // set up second base pointer for SAVE_REST ;; SAVE_REST - br.call.sptk rp=demine_args // clear NaT bits in (potential) syscall args + br.call.sptk.many rp=demine_args // clear NaT bits in (potential) syscall args mov r3=255 adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 @@ -698,7 +680,7 @@ st8 [r16]=r18 // store new value for cr.isr (p8) br.call.sptk.many b6=b6 // ignore this return addr - br.cond.sptk.many ia64_trace_syscall + br.cond.sptk ia64_trace_syscall // NOT REACHED END(break_fault) @@ -811,8 +793,8 @@ mov b6=r8 ;; cmp.ne p6,p0=0,r8 -(p6) br.call.dpnt b6=b6 // call returns to ia64_leave_kernel - br.sptk ia64_leave_kernel +(p6) br.call.dpnt.many b6=b6 // call returns to ia64_leave_kernel + br.sptk.many ia64_leave_kernel END(dispatch_illegal_op_fault) .align 1024 @@ -855,30 +837,30 @@ adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp ;; cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 - st8 [r15]=r8 // save orignal EAX in r1 (IA32 procs don't use the GP) + st8 [r15]=r8 // save original EAX in r1 (IA32 procs don't use the GP) ;; alloc r15=ar.pfs,0,0,6,0 // must first in an insn group ;; - ld4 r8=[r14],8 // r8 == EAX (syscall number) - mov r15=222 // sys_vfork - last implemented system call + ld4 r8=[r14],8 // r8 == eax (syscall number) + mov r15=230 // number of entries in ia32 system call table ;; - cmp.leu.unc p6,p7=r8,r15 - ld4 out1=[r14],8 // r9 == ecx + cmp.ltu.unc p6,p7=r8,r15 + ld4 out1=[r14],8 // r9 == ecx ;; - ld4 out2=[r14],8 // r10 == edx + ld4 out2=[r14],8 // r10 == edx ;; - ld4 out0=[r14] // r11 == ebx + ld4 out0=[r14] // r11 == ebx adds r14=(IA64_PT_REGS_R8_OFFSET-(8*3)) + 16,sp ;; - ld4 out5=[r14],8 // r13 == ebp + ld4 out5=[r14],8 // r13 == ebp ;; - ld4 out3=[r14],8 // r14 == esi + ld4 out3=[r14],8 // r14 == esi adds r2=IA64_TASK_PTRACE_OFFSET,r13 // r2 = ¤t->ptrace ;; - ld4 out4=[r14] // R15 == edi + ld4 out4=[r14] // r15 == edi movl r16=ia32_syscall_table ;; -(p6) shladd r16=r8,3,r16 // Force ni_syscall if not valid syscall number +(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number ld8 r2=[r2] // r2 = current->ptrace ;; ld8 r16=[r16] @@ -889,12 +871,12 @@ ;; mov rp=r15 (p8) br.call.sptk.many b6=b6 - br.cond.sptk.many ia32_trace_syscall + br.cond.sptk ia32_trace_syscall non_ia32_syscall: alloc r15=ar.pfs,0,0,2,0 - mov out0=r14 // interrupt # - add out1=16,sp // pointer to pt_regs + mov out0=r14 // interrupt # + add out1=16,sp // pointer to pt_regs ;; // avoid WAW on CFM br.call.sptk.many rp=ia32_bad_interrupt .ret1: movl r15=ia64_leave_kernel @@ -1085,7 +1067,7 @@ mov r31=pr ;; cmp4.eq p6,p0=0,r16 -(p6) br.sptk dispatch_illegal_op_fault +(p6) br.sptk.many dispatch_illegal_op_fault ;; mov r19=24 // fault number br.sptk.many dispatch_to_fault_handler diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/mca.c linux/arch/ia64/kernel/mca.c --- v2.4.14/linux/arch/ia64/kernel/mca.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/mca.c Fri Nov 9 14:26:17 2001 @@ -3,12 +3,20 @@ * Purpose: Generic MCA handling layer * * Updated for latest kernel + * Copyright (C) 2001 Intel + * Copyright (C) Fred Lewis (frederick.v.lewis@intel.com) + * * Copyright (C) 2000 Intel * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com) * * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * + * 01/01/03 F. Lewis Added setup of CMCI and CPEI IRQs, logging of corrected + * platform errors, completed code for logging of + * corrected & uncorrected machine check errors, and + * updated for conformance with Nov. 2000 revision of the + * SAL 3.0 spec. * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, * added min save state dump, added INIT handler. */ @@ -16,6 +24,7 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/sched.h> +#include <linux/interrupt.h> #include <linux/irq.h> #include <linux/smp_lock.h> @@ -27,8 +36,10 @@ #include <asm/mca.h> #include <asm/irq.h> -#include <asm/machvec.h> +#include <asm/hw_irq.h> +#include <asm/acpi-ext.h> +#undef MCA_PRT_XTRA_DATA typedef struct ia64_fptr { unsigned long fp; @@ -38,22 +49,67 @@ ia64_mc_info_t ia64_mc_info; ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state; -u64 ia64_mca_proc_state_dump[256]; +u64 ia64_mca_proc_state_dump[512]; u64 ia64_mca_stack[1024]; u64 ia64_mca_stackframe[32]; u64 ia64_mca_bspstore[1024]; u64 ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16))); -static void ia64_mca_cmc_vector_setup(int enable, - int_vector_t cmc_vector); static void ia64_mca_wakeup_ipi_wait(void); static void ia64_mca_wakeup(int cpu); static void ia64_mca_wakeup_all(void); -static void ia64_log_init(int,int); -static void ia64_log_get(int,int, prfunc_t); -static void ia64_log_clear(int,int,int, prfunc_t); +static void ia64_log_init(int); extern void ia64_monarch_init_handler (void); extern void ia64_slave_init_handler (void); +extern struct hw_interrupt_type irq_type_iosapic_level; + +static struct irqaction cmci_irqaction = { + handler: ia64_mca_cmc_int_handler, + flags: SA_INTERRUPT, + name: "cmc_hndlr" +}; + +static struct irqaction mca_rdzv_irqaction = { + handler: ia64_mca_rendez_int_handler, + flags: SA_INTERRUPT, + name: "mca_rdzv" +}; + +static struct irqaction mca_wkup_irqaction = { + handler: ia64_mca_wakeup_int_handler, + flags: SA_INTERRUPT, + name: "mca_wkup" +}; + +static struct irqaction mca_cpe_irqaction = { + handler: ia64_mca_cpe_int_handler, + flags: SA_INTERRUPT, + name: "cpe_hndlr" +}; + +/* + * ia64_mca_log_sal_error_record + * + * This function retrieves a specified error record type from SAL, sends it to + * the system log, and notifies SALs to clear the record from its non-volatile + * memory. + * + * Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT) + * Outputs : None + */ +void +ia64_mca_log_sal_error_record(int sal_info_type) +{ + /* Get the MCA error record */ + if (!ia64_log_get(sal_info_type, (prfunc_t)printk)) + return; // no record retrieved + + /* Log the error record */ + ia64_log_print(sal_info_type, (prfunc_t)printk); + + /* Clear the CMC SAL logs now that they have been logged */ + ia64_sal_clear_state_info(sal_info_type); +} /* * hack for now, add platform dependent handlers @@ -67,10 +123,14 @@ } void -cmci_handler_platform (int cmc_irq, void *arg, struct pt_regs *ptregs) +ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) { + IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq); + /* Get the CMC error record and log it */ + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); } + /* * This routine will be used to deal with platform specific handling * of the init, i.e. drop into the kernel debugger on server machine, @@ -81,17 +141,72 @@ init_handler_platform (struct pt_regs *regs) { /* if a kernel debugger is available call it here else just dump the registers */ + show_regs(regs); /* dump the state info */ + while (1); /* hang city if no debugger */ } +/* + * ia64_mca_init_platform + * + * External entry for platform specific MCA initialization. + * + * Inputs + * None + * + * Outputs + * None + */ void -log_print_platform ( void *cur_buff_ptr, prfunc_t prfunc) +ia64_mca_init_platform (void) { + } +/* + * ia64_mca_check_errors + * + * External entry to check for error records which may have been posted by SAL + * for a prior failure which resulted in a machine shutdown before an the + * error could be logged. This function must be called after the filesystem + * is initialized. + * + * Inputs : None + * + * Outputs : None + */ void -ia64_mca_init_platform (void) +ia64_mca_check_errors (void) +{ + /* + * If there is an MCA error record pending, get it and log it. + */ + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); +} + +/* + * ia64_mca_register_cpev + * + * Register the corrected platform error vector with SAL. + * + * Inputs + * cpev Corrected Platform Error Vector number + * + * Outputs + * None + */ +static void +ia64_mca_register_cpev (int cpev) { + /* Register the CPE interrupt vector with SAL */ + if (ia64_sal_mc_set_params(SAL_MC_PARAM_CPE_INT, SAL_MC_PARAM_MECHANISM_INT, cpev, 0, 0)) { + printk("ia64_mca_platform_init: failed to register Corrected " + "Platform Error interrupt vector with SAL.\n"); + return; + } + + IA64_MCA_DEBUG("ia64_mca_platform_init: corrected platform error " + "vector %#x setup and enabled\n", cpev); } #endif /* PLATFORM_MCA_HANDLERS */ @@ -140,30 +255,36 @@ && !ia64_pmss_dump_bank0)) printk("\n"); } - /* hang city for now, until we include debugger or copy to ptregs to show: */ - while (1); } /* * ia64_mca_cmc_vector_setup - * Setup the correctable machine check vector register in the processor + * + * Setup the corrected machine check vector register in the processor and + * unmask interrupt. This function is invoked on a per-processor basis. + * * Inputs - * Enable (1 - enable cmc interrupt , 0 - disable) - * CMC handler entry point (if enabled) + * None * * Outputs * None */ -static void -ia64_mca_cmc_vector_setup(int enable, - int_vector_t cmc_vector) +void +ia64_mca_cmc_vector_setup (void) { cmcv_reg_t cmcv; cmcv.cmcv_regval = 0; - cmcv.cmcv_mask = enable; - cmcv.cmcv_vector = cmc_vector; + cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ + cmcv.cmcv_vector = IA64_CMC_VECTOR; ia64_set_cmcv(cmcv.cmcv_regval); + + IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected " + "machine check vector %#x setup and enabled.\n", + smp_processor_id(), IA64_CMC_VECTOR); + + IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d CMCV = %#016lx\n", + smp_processor_id(), ia64_get_cmcv()); } @@ -174,26 +295,58 @@ void mca_test(void) { - slpi_buf.slpi_valid.slpi_psi = 1; - slpi_buf.slpi_valid.slpi_cache_check = 1; - slpi_buf.slpi_valid.slpi_tlb_check = 1; - slpi_buf.slpi_valid.slpi_bus_check = 1; - slpi_buf.slpi_valid.slpi_minstate = 1; - slpi_buf.slpi_valid.slpi_bank1_gr = 1; - slpi_buf.slpi_valid.slpi_br = 1; - slpi_buf.slpi_valid.slpi_cr = 1; - slpi_buf.slpi_valid.slpi_ar = 1; - slpi_buf.slpi_valid.slpi_rr = 1; - slpi_buf.slpi_valid.slpi_fr = 1; + slpi_buf.valid.psi_static_struct = 1; + slpi_buf.valid.num_cache_check = 1; + slpi_buf.valid.num_tlb_check = 1; + slpi_buf.valid.num_bus_check = 1; + slpi_buf.valid.processor_static_info.minstate = 1; + slpi_buf.valid.processor_static_info.br = 1; + slpi_buf.valid.processor_static_info.cr = 1; + slpi_buf.valid.processor_static_info.ar = 1; + slpi_buf.valid.processor_static_info.rr = 1; + slpi_buf.valid.processor_static_info.fr = 1; ia64_os_mca_dispatch(); } #endif /* #if defined(MCA_TEST) */ + +/* + * verify_guid + * + * Compares a test guid to a target guid and returns result. + * + * Inputs + * test_guid * (ptr to guid to be verified) + * target_guid * (ptr to standard guid to be verified against) + * + * Outputs + * 0 (test verifies against target) + * non-zero (test guid does not verify) + */ +static int +verify_guid (efi_guid_t *test, efi_guid_t *target) +{ + int rc; + + if ((rc = memcmp((void *)test, (void *)target, sizeof(efi_guid_t)))) { + IA64_MCA_DEBUG("ia64_mca_print: invalid guid = " + "{ %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, " + "%#02x, %#02x, %#02x, %#02x, } } \n ", + test->data1, test->data2, test->data3, test->data4[0], + test->data4[1], test->data4[2], test->data4[3], + test->data4[4], test->data4[5], test->data4[6], + test->data4[7]); + } + + return rc; +} + /* * ia64_mca_init - * Do all the mca specific initialization on a per-processor basis. + * + * Do all the system level mca specific initialization. * * 1. Register spinloop and wakeup request interrupt vectors * @@ -201,77 +354,80 @@ * * 3. Register OS_INIT handler entry point * - * 4. Initialize CMCV register to enable/disable CMC interrupt on the - * processor and hook a handler in the platform-specific ia64_mca_init. + * 4. Initialize MCA/CMC/INIT related log buffers maintained by the OS. * - * 5. Initialize MCA/CMC/INIT related log buffers maintained by the OS. + * Note that this initialization is done very early before some kernel + * services are available. * - * Inputs - * None - * Outputs - * None + * Inputs : None + * + * Outputs : None */ void __init ia64_mca_init(void) { ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; + ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; int i; + s64 rc; - IA64_MCA_DEBUG("ia64_mca_init : begin\n"); + IA64_MCA_DEBUG("ia64_mca_init: begin\n"); /* Clear the Rendez checkin flag for all cpus */ - for(i = 0 ; i < IA64_MAXCPUS; i++) + for(i = 0 ; i < NR_CPUS; i++) ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; - /* NOTE : The actual irqs for the rendez, wakeup and - * cmc interrupts are requested in the platform-specific - * mca initialization code. - */ /* * Register the rendezvous spinloop and wakeup mechanism with SAL */ /* Register the rendezvous interrupt vector with SAL */ - if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, - SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_RENDEZ_VECTOR, - IA64_MCA_RENDEZ_TIMEOUT, - 0)) + if ((rc = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, + SAL_MC_PARAM_MECHANISM_INT, + IA64_MCA_RENDEZ_VECTOR, + IA64_MCA_RENDEZ_TIMEOUT, + 0))) + { + printk("ia64_mca_init: Failed to register rendezvous interrupt " + "with SAL. rc = %ld\n", rc); return; + } /* Register the wakeup interrupt vector with SAL */ - if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, - SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_WAKEUP_VECTOR, - 0, - 0)) + if ((rc = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, + SAL_MC_PARAM_MECHANISM_INT, + IA64_MCA_WAKEUP_VECTOR, + 0, 0))) + { + printk("ia64_mca_init: Failed to register wakeup interrupt with SAL. rc = %ld\n", + rc); return; + } - IA64_MCA_DEBUG("ia64_mca_init : registered mca rendezvous spinloop and wakeup mech.\n"); - /* - * Setup the correctable machine check vector - */ - ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, IA64_CMC_VECTOR); - - IA64_MCA_DEBUG("ia64_mca_init : correctable mca vector setup done\n"); + IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n"); - ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch); + ia64_mc_info.imi_mca_handler = __pa(mca_hldlr_ptr->fp); /* * XXX - disable SAL checksum by setting size to 0; should be * __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); */ ia64_mc_info.imi_mca_handler_size = 0; - /* Register the os mca handler with SAL */ - if (ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, - ia64_mc_info.imi_mca_handler, - __pa(ia64_get_gp()), - ia64_mc_info.imi_mca_handler_size, - 0,0,0)) + /* Register the os mca handler with SAL */ + if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, + ia64_mc_info.imi_mca_handler, + mca_hldlr_ptr->gp, + ia64_mc_info.imi_mca_handler_size, + 0, 0, 0))) + { + printk("ia64_mca_init: Failed to register os mca handler with SAL. rc = %ld\n", + rc); return; + } - IA64_MCA_DEBUG("ia64_mca_init : registered os mca handler with SAL\n"); + IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n", + ia64_mc_info.imi_mca_handler, mca_hldlr_ptr->gp); /* * XXX - disable SAL checksum by setting size to 0, should be @@ -282,53 +438,87 @@ ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); ia64_mc_info.imi_slave_init_handler_size = 0; - IA64_MCA_DEBUG("ia64_mca_init : os init handler at %lx\n",ia64_mc_info.imi_monarch_init_handler); + IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n", + ia64_mc_info.imi_monarch_init_handler); /* Register the os init handler with SAL */ - if (ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, - ia64_mc_info.imi_monarch_init_handler, - __pa(ia64_get_gp()), - ia64_mc_info.imi_monarch_init_handler_size, - ia64_mc_info.imi_slave_init_handler, - __pa(ia64_get_gp()), - ia64_mc_info.imi_slave_init_handler_size)) + if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, + ia64_mc_info.imi_monarch_init_handler, + __pa(ia64_get_gp()), + ia64_mc_info.imi_monarch_init_handler_size, + ia64_mc_info.imi_slave_init_handler, + __pa(ia64_get_gp()), + ia64_mc_info.imi_slave_init_handler_size))) + { + printk("ia64_mca_init: Failed to register m/s init handlers with SAL. rc = %ld\n", + rc); + return; + } + IA64_MCA_DEBUG("ia64_mca_init: registered os init handler with SAL\n"); - return; + /* + * Configure the CMCI vector and handler. Interrupts for CMC are + * per-processor, so AP CMC interrupts are setup in smp_callin() (smp.c). + */ + register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction); + ia64_mca_cmc_vector_setup(); /* Setup vector on BSP & enable */ + + /* Setup the MCA rendezvous interrupt vector */ + register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction); - IA64_MCA_DEBUG("ia64_mca_init : registered os init handler with SAL\n"); + /* Setup the MCA wakeup interrupt vector */ + register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); + + /* Setup the CPE interrupt vector */ + { + irq_desc_t *desc; + unsigned int irq; + int cpev = acpi_request_vector(ACPI20_ENTRY_PIS_CPEI); + + if (cpev >= 0) { + for (irq = 0; irq < NR_IRQS; ++irq) + if (irq_to_vector(irq) == cpev) { + desc = irq_desc(irq); + desc->status |= IRQ_PER_CPU; + desc->handler = &irq_type_iosapic_level; + setup_irq(irq, &mca_cpe_irqaction); + } + ia64_mca_register_cpev(cpev); + } else + printk("ia64_mca_init: Failed to get routed CPEI vector from ACPI.\n"); + } /* Initialize the areas set aside by the OS to buffer the * platform/processor error states for MCA/INIT/CMC * handling. */ - ia64_log_init(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR); - ia64_log_init(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM); - ia64_log_init(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR); - ia64_log_init(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM); - ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR); - ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM); - - ia64_mca_init_platform(); - - IA64_MCA_DEBUG("ia64_mca_init : platform-specific mca handling setup done\n"); + ia64_log_init(SAL_INFO_TYPE_MCA); + ia64_log_init(SAL_INFO_TYPE_INIT); + ia64_log_init(SAL_INFO_TYPE_CMC); + ia64_log_init(SAL_INFO_TYPE_CPE); #if defined(MCA_TEST) mca_test(); #endif /* #if defined(MCA_TEST) */ printk("Mca related initialization done\n"); + +#if 0 // Too early in initialization -- error log is lost + /* Do post-failure MCA error logging */ + ia64_mca_check_errors(); +#endif // Too early in initialization -- error log is lost } /* * ia64_mca_wakeup_ipi_wait + * * Wait for the inter-cpu interrupt to be sent by the * monarch processor once it is done with handling the * MCA. - * Inputs - * None - * Outputs - * None + * + * Inputs : None + * Outputs : None */ void ia64_mca_wakeup_ipi_wait(void) @@ -339,16 +529,16 @@ do { switch(irr_num) { - case 0: + case 0: irr = ia64_get_irr0(); break; - case 1: + case 1: irr = ia64_get_irr1(); break; - case 2: + case 2: irr = ia64_get_irr2(); break; - case 3: + case 3: irr = ia64_get_irr3(); break; } @@ -357,26 +547,28 @@ /* * ia64_mca_wakeup + * * Send an inter-cpu interrupt to wake-up a particular cpu * and mark that cpu to be out of rendez. - * Inputs - * cpuid - * Outputs - * None + * + * Inputs : cpuid + * Outputs : None */ void ia64_mca_wakeup(int cpu) { platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0); ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; + } + /* * ia64_mca_wakeup_all + * * Wakeup all the cpus which have rendez'ed previously. - * Inputs - * None - * Outputs - * None + * + * Inputs : None + * Outputs : None */ void ia64_mca_wakeup_all(void) @@ -389,15 +581,16 @@ ia64_mca_wakeup(cpu); } + /* * ia64_mca_rendez_interrupt_handler + * * This is handler used to put slave processors into spinloop * while the monarch processor does the mca handling and later * wake each slave up once the monarch is done. - * Inputs - * None - * Outputs - * None + * + * Inputs : None + * Outputs : None */ void ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) @@ -423,23 +616,22 @@ /* Enable all interrupts */ restore_flags(flags); - - } /* * ia64_mca_wakeup_int_handler + * * The interrupt handler for processing the inter-cpu interrupt to the * slave cpu which was spinning in the rendez loop. * Since this spinning is done by turning off the interrupts and * polling on the wakeup-interrupt bit in the IRR, there is * nothing useful to be done in the handler. - * Inputs - * wakeup_irq (Wakeup-interrupt bit) + * + * Inputs : wakeup_irq (Wakeup-interrupt bit) * arg (Interrupt handler specific argument) * ptregs (Exception frame at the time of the interrupt) - * Outputs + * Outputs : None * */ void @@ -450,16 +642,16 @@ /* * ia64_return_to_sal_check + * * This is function called before going back from the OS_MCA handler * to the OS_MCA dispatch code which finally takes the control back * to the SAL. * The main purpose of this routine is to setup the OS_MCA to SAL * return state which can be used by the OS_MCA dispatch code * just before going back to SAL. - * Inputs - * None - * Outputs - * None + * + * Inputs : None + * Outputs : None */ void @@ -474,11 +666,13 @@ ia64_os_to_sal_handoff_state.imots_sal_check_ra = ia64_sal_to_os_handoff_state.imsto_sal_check_ra; - /* For now ignore the MCA */ - ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; + /* Cold Boot for uncorrectable MCA */ + ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; } + /* * ia64_mca_ucmc_handler + * * This is uncorrectable machine check handler called from OS_MCA * dispatch code which is in turn called from SAL_CHECK(). * This is the place where the core of OS MCA handling is done. @@ -487,93 +681,92 @@ * monarch processor. Once the monarch is done with MCA handling * further MCA logging is enabled by clearing logs. * Monarch also has the duty of sending wakeup-IPIs to pull the - * slave processors out of rendez. spinloop. - * Inputs - * None - * Outputs - * None + * slave processors out of rendezvous spinloop. + * + * Inputs : None + * Outputs : None */ void ia64_mca_ucmc_handler(void) { +#if 0 /* stubbed out @FVL */ + /* + * Attempting to log a DBE error Causes "reserved register/field panic" + * in printk. + */ - /* Get the MCA processor log */ - ia64_log_get(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); - /* Get the MCA platform log */ - ia64_log_get(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); - - ia64_log_print(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); + /* Get the MCA error record and log it */ + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); +#endif /* stubbed out @FVL */ /* - * Do some error handling - Platform-specific mca handler is called at this point + * Do Platform-specific mca error handling if required. */ - mca_handler_platform() ; - /* Clear the SAL MCA logs */ - ia64_log_clear(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, 1, printk); - ia64_log_clear(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM, 1, printk); - - /* Wakeup all the processors which are spinning in the rendezvous - * loop. + /* + * Wakeup all the processors which are spinning in the rendezvous + * loop. */ ia64_mca_wakeup_all(); + + /* Return to SAL */ ia64_return_to_sal_check(); } /* * ia64_mca_cmc_int_handler - * This is correctable machine check interrupt handler. + * + * This is corrected machine check interrupt handler. * Right now the logs are extracted and displayed in a well-defined * format. + * * Inputs - * None + * interrupt number + * client data arg ptr + * saved registers ptr + * * Outputs * None */ void ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs) { - /* Get the CMC processor log */ - ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); - /* Get the CMC platform log */ - ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); - + IA64_MCA_DEBUG("ia64_mca_cmc_int_handler: received interrupt vector = %#x on CPU %d\n", + cmc_irq, smp_processor_id()); - ia64_log_print(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); - cmci_handler_platform(cmc_irq, arg, ptregs); - - /* Clear the CMC SAL logs now that they have been saved in the OS buffer */ - ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC); + /* Get the CMC error record and log it */ + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC); } /* * IA64_MCA log support */ #define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */ -#define IA64_MAX_LOG_TYPES 3 /* MCA, CMC, INIT */ -#define IA64_MAX_LOG_SUBTYPES 2 /* Processor, Platform */ +#define IA64_MAX_LOG_TYPES 4 /* MCA, INIT, CMC, CPE */ -typedef struct ia64_state_log_s { +typedef struct ia64_state_log_s +{ spinlock_t isl_lock; int isl_index; - ia64_psilog_t isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ + ia64_err_rec_t isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ } ia64_state_log_t; -static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES][IA64_MAX_LOG_SUBTYPES]; +static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; -#define IA64_LOG_LOCK_INIT(it, sit) spin_lock_init(&ia64_state_log[it][sit].isl_lock) -#define IA64_LOG_LOCK(it, sit) spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s) -#define IA64_LOG_UNLOCK(it, sit) spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\ - s) -#define IA64_LOG_NEXT_INDEX(it, sit) ia64_state_log[it][sit].isl_index -#define IA64_LOG_CURR_INDEX(it, sit) 1 - ia64_state_log[it][sit].isl_index -#define IA64_LOG_INDEX_INC(it, sit) \ - ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index -#define IA64_LOG_INDEX_DEC(it, sit) \ - ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index -#define IA64_LOG_NEXT_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)])) -#define IA64_LOG_CURR_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)])) +/* Note: Some of these macros assume IA64_MAX_LOGS is always 2. Should be */ +/* fixed. @FVL */ +#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock) +#define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s) +#define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s) +#define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index +#define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index +#define IA64_LOG_INDEX_INC(it) \ + ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index +#define IA64_LOG_INDEX_DEC(it) \ + ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index +#define IA64_LOG_NEXT_BUFFER(it) (void *)(&(ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)])) +#define IA64_LOG_CURR_BUFFER(it) (void *)(&(ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) /* * C portion of the OS INIT handler @@ -584,123 +777,217 @@ * * Returns: * 0 if SAL must warm boot the System - * 1 if SAL must retrun to interrupted context using PAL_MC_RESUME + * 1 if SAL must return to interrupted context using PAL_MC_RESUME * */ - void ia64_init_handler (struct pt_regs *regs) { sal_log_processor_info_t *proc_ptr; - ia64_psilog_t *plog_ptr; + ia64_err_rec_t *plog_ptr; printk("Entered OS INIT handler\n"); /* Get the INIT processor log */ - ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); - /* Get the INIT platform log */ - ia64_log_get(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); + if (!ia64_log_get(SAL_INFO_TYPE_INIT, (prfunc_t)printk)) + return; // no record retrieved #ifdef IA64_DUMP_ALL_PROC_INFO - ia64_log_print(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); + ia64_log_print(SAL_INFO_TYPE_INIT, (prfunc_t)printk); #endif /* * get pointer to min state save area * */ - plog_ptr=(ia64_psilog_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT, - SAL_SUB_INFO_TYPE_PROCESSOR); - proc_ptr = &plog_ptr->devlog.proclog; + plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT); + proc_ptr = &plog_ptr->proc_err; - ia64_process_min_state_save(&proc_ptr->slpi_min_state_area,regs); - - init_handler_platform(regs); /* call platform specific routines */ + ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area, + regs); /* Clear the INIT SAL logs now that they have been saved in the OS buffer */ ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT); + + init_handler_platform(regs); /* call platform specific routines */ +} + +/* + * ia64_log_prt_guid + * + * Print a formatted GUID. + * + * Inputs : p_guid (ptr to the GUID) + * prfunc (print function) + * Outputs : None + * + */ +void +ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc) +{ + printk("GUID = { %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, " + "%#02x, %#02x, %#02x, %#02x, } } \n ", p_guid->data1, + p_guid->data2, p_guid->data3, p_guid->data4[0], p_guid->data4[1], + p_guid->data4[2], p_guid->data4[3], p_guid->data4[4], + p_guid->data4[5], p_guid->data4[6], p_guid->data4[7]); +} + +static void +ia64_log_hexdump(unsigned char *p, unsigned long n_ch, prfunc_t prfunc) +{ + int i, j; + + if (!p) + return; + + for (i = 0; i < n_ch;) { + prfunc("%p ", (void *)p); + for (j = 0; (j < 16) && (i < n_ch); i++, j++, p++) { + prfunc("%02x ", *p); + } + prfunc("\n"); + } +} + +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + +static void +ia64_log_prt_record_header (sal_log_record_header_t *rh, prfunc_t prfunc) +{ + prfunc("SAL RECORD HEADER: Record buffer = %p, header size = %ld\n", + (void *)rh, sizeof(sal_log_record_header_t)); + ia64_log_hexdump((unsigned char *)rh, sizeof(sal_log_record_header_t), + (prfunc_t)prfunc); + prfunc("Total record length = %d\n", rh->len); + ia64_log_prt_guid(&rh->platform_guid, prfunc); + prfunc("End of SAL RECORD HEADER\n"); +} + +static void +ia64_log_prt_section_header (sal_log_section_hdr_t *sh, prfunc_t prfunc) +{ + prfunc("SAL SECTION HEADER: Record buffer = %p, header size = %ld\n", + (void *)sh, sizeof(sal_log_section_hdr_t)); + ia64_log_hexdump((unsigned char *)sh, sizeof(sal_log_section_hdr_t), + (prfunc_t)prfunc); + prfunc("Length of section & header = %d\n", sh->len); + ia64_log_prt_guid(&sh->guid, prfunc); + prfunc("End of SAL SECTION HEADER\n"); } +#endif // MCA_PRT_XTRA_DATA for test only @FVL /* * ia64_log_init * Reset the OS ia64 log buffer - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) - * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) * Outputs : None */ void -ia64_log_init(int sal_info_type, int sal_sub_info_type) +ia64_log_init(int sal_info_type) { - IA64_LOG_LOCK_INIT(sal_info_type, sal_sub_info_type); - IA64_LOG_NEXT_INDEX(sal_info_type, sal_sub_info_type) = 0; - memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0, - sizeof(ia64_psilog_t) * IA64_MAX_LOGS); + IA64_LOG_LOCK_INIT(sal_info_type); + IA64_LOG_NEXT_INDEX(sal_info_type) = 0; + memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, + sizeof(ia64_err_rec_t) * IA64_MAX_LOGS); } /* * ia64_log_get + * * Get the current MCA log from SAL and copy it into the OS log buffer. - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) - * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * Outputs : None + * + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) + * prfunc (fn ptr of log output function) + * Outputs : size (total record length) * */ -void -ia64_log_get(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc) +u64 +ia64_log_get(int sal_info_type, prfunc_t prfunc) { - sal_log_header_t *log_buffer; - int s,total_len=0; - - IA64_LOG_LOCK(sal_info_type, sal_sub_info_type); + sal_log_record_header_t *log_buffer; + u64 total_len = 0; + int s; + IA64_LOG_LOCK(sal_info_type); /* Get the process state information */ - log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type); - - if (!(total_len=ia64_sal_get_state_info(sal_info_type,(u64 *)log_buffer))) - prfunc("ia64_mca_log_get : Getting processor log failed\n"); + log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type); - IA64_MCA_DEBUG("ia64_log_get: retrieved %d bytes of error information\n",total_len); - - IA64_LOG_INDEX_INC(sal_info_type, sal_sub_info_type); - - IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type); + total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer); + if (total_len) { + IA64_LOG_INDEX_INC(sal_info_type); + IA64_LOG_UNLOCK(sal_info_type); + IA64_MCA_DEBUG("ia64_log_get: SAL error record type %d retrieved. " + "Record length = %ld\n", sal_info_type, total_len); + return total_len; + } else { + IA64_LOG_UNLOCK(sal_info_type); + prfunc("ia64_log_get: Failed to retrieve SAL error record type %d\n", + sal_info_type); + return 0; + } } /* - * ia64_log_clear - * Clear the current MCA log from SAL and dpending on the clear_os_buffer flags - * clear the OS log buffer also - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) - * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) - * clear_os_buffer + * ia64_log_prt_oem_data + * + * Print OEM specific data if included. + * + * Inputs : header_len (length passed in section header) + * sect_len (default length of section type) + * p_data (ptr to data) * prfunc (print function) * Outputs : None * */ void -ia64_log_clear(int sal_info_type, int sal_sub_info_type, int clear_os_buffer, prfunc_t prfunc) +ia64_log_prt_oem_data (int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) { - if (ia64_sal_clear_state_info(sal_info_type)) - prfunc("ia64_mca_log_get : Clearing processor log failed\n"); - - if (clear_os_buffer) { - sal_log_header_t *log_buffer; - int s; - - IA64_LOG_LOCK(sal_info_type, sal_sub_info_type); - - /* Get the process state information */ - log_buffer = IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type); - - memset(log_buffer, 0, sizeof(ia64_psilog_t)); + int oem_data_len, i; - IA64_LOG_INDEX_DEC(sal_info_type, sal_sub_info_type); - - IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type); + if ((oem_data_len = header_len - sect_len) > 0) { + prfunc(" OEM Specific Data:"); + for (i = 0; i < oem_data_len; i++, p_data++) + prfunc(" %02x", *p_data); } + prfunc("\n"); +} +/* + * ia64_log_rec_header_print + * + * Log info from the SAL error record header. + * + * Inputs : lh * (ptr to SAL log error record header) + * prfunc (fn ptr of log output function to use) + * Outputs : None + */ +void +ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc) +{ + char str_buf[32]; + + sprintf(str_buf, "%2d.%02d", + (lh->revision.major >> 4) * 10 + (lh->revision.major & 0xf), + (lh->revision.minor >> 4) * 10 + (lh->revision.minor & 0xf)); + prfunc("+Err Record ID: %d SAL Rev: %s\n", lh->id, str_buf); + sprintf(str_buf, "%02d/%02d/%04d/ %02d:%02d:%02d", + (lh->timestamp.slh_month >> 4) * 10 + + (lh->timestamp.slh_month & 0xf), + (lh->timestamp.slh_day >> 4) * 10 + + (lh->timestamp.slh_day & 0xf), + (lh->timestamp.slh_century >> 4) * 1000 + + (lh->timestamp.slh_century & 0xf) * 100 + + (lh->timestamp.slh_year >> 4) * 10 + + (lh->timestamp.slh_year & 0xf), + (lh->timestamp.slh_hour >> 4) * 10 + + (lh->timestamp.slh_hour & 0xf), + (lh->timestamp.slh_minute >> 4) * 10 + + (lh->timestamp.slh_minute & 0xf), + (lh->timestamp.slh_second >> 4) * 10 + + (lh->timestamp.slh_second & 0xf)); + prfunc("+Time: %s Severity %d\n", str_buf, lh->severity); } /* @@ -729,6 +1016,33 @@ prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]); } +/* + * ia64_log_processor_fp_regs_print + * Print the contents of the saved floating page register(s) in the format + * <reg_prefix>[<index>] <value> + * + * Inputs: ia64_fpreg (Register save buffer) + * reg_num (# of registers) + * reg_class (application/banked/control/bank1_general) + * reg_prefix (ar/br/cr/b1_gr) + * Outputs: None + * + */ +void +ia64_log_processor_fp_regs_print (struct ia64_fpreg *regs, + int reg_num, + char *reg_class, + char *reg_prefix, + prfunc_t prfunc) +{ + int i; + + prfunc("+%s Registers\n", reg_class); + for (i = 0; i < reg_num; i++) + prfunc("+ %s[%d] 0x%lx%016lx\n", reg_prefix, i, regs[i].u.bits[1], + regs[i].u.bits[0]); +} + static char *pal_mesi_state[] = { "Invalid", "Shared", @@ -754,69 +1068,91 @@ /* * ia64_log_cache_check_info_print * Display the machine check information related to cache error(s). - * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * Inputs: i (Multiple errors are logged, i - index of logged error) + * cc_info * (Ptr to cache check info logged by the PAL and later * captured by the SAL) - * target_addr (Address which caused the cache error) - * Outputs : None + * prfunc (fn ptr of print function to be used for output) + * Outputs: None */ void -ia64_log_cache_check_info_print(int i, - pal_cache_check_info_t info, - u64 target_addr, - prfunc_t prfunc) +ia64_log_cache_check_info_print (int i, + sal_log_mod_error_info_t *cache_check_info, + prfunc_t prfunc) { + pal_cache_check_info_t *info; + u64 target_addr; + + if (!cache_check_info->valid.check_info) { + IA64_MCA_DEBUG("ia64_mca_log_print: invalid cache_check_info[%d]\n",i); + return; /* If check info data not valid, skip it */ + } + + info = (pal_cache_check_info_t *)&cache_check_info->check_info; + target_addr = cache_check_info->target_identifier; + prfunc("+ Cache check info[%d]\n+", i); - prfunc(" Level: L%d",info.level); - if (info.mv) - prfunc(" ,Mesi: %s",pal_mesi_state[info.mesi]); - prfunc(" ,Index: %d,", info.index); - if (info.ic) - prfunc(" ,Cache: Instruction"); - if (info.dc) - prfunc(" ,Cache: Data"); - if (info.tl) - prfunc(" ,Line: Tag"); - if (info.dl) - prfunc(" ,Line: Data"); - prfunc(" ,Operation: %s,", pal_cache_op[info.op]); - if (info.wv) - prfunc(" ,Way: %d,", info.way); - if (info.tv) - prfunc(" ,Target Addr: 0x%lx", target_addr); - if (info.mc) - prfunc(" ,MC: Corrected"); + prfunc(" Level: L%d,",info->level); + if (info->mv) + prfunc(" Mesi: %s,",pal_mesi_state[info->mesi]); + prfunc(" Index: %d,", info->index); + if (info->ic) + prfunc(" Cache: Instruction,"); + if (info->dc) + prfunc(" Cache: Data,"); + if (info->tl) + prfunc(" Line: Tag,"); + if (info->dl) + prfunc(" Line: Data,"); + prfunc(" Operation: %s,", pal_cache_op[info->op]); + if (info->wv) + prfunc(" Way: %d,", info->way); + if (cache_check_info->valid.target_identifier) + /* Hope target address is saved in target_identifier */ + if (info->tv) + prfunc(" Target Addr: 0x%lx,", target_addr); + if (info->mc) + prfunc(" MC: Corrected"); prfunc("\n"); } /* * ia64_log_tlb_check_info_print * Display the machine check information related to tlb error(s). - * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * Inputs: i (Multiple errors are logged, i - index of logged error) + * tlb_info * (Ptr to machine check info logged by the PAL and later * captured by the SAL) - * Outputs : None + * prfunc (fn ptr of print function to be used for output) + * Outputs: None */ - void -ia64_log_tlb_check_info_print(int i, - pal_tlb_check_info_t info, - prfunc_t prfunc) +ia64_log_tlb_check_info_print (int i, + sal_log_mod_error_info_t *tlb_check_info, + prfunc_t prfunc) + { + pal_tlb_check_info_t *info; + + if (!tlb_check_info->valid.check_info) { + IA64_MCA_DEBUG("ia64_mca_log_print: invalid tlb_check_info[%d]\n", i); + return; /* If check info data not valid, skip it */ + } + + info = (pal_tlb_check_info_t *)&tlb_check_info->check_info; + prfunc("+ TLB Check Info [%d]\n+", i); - if (info.itc) + if (info->itc) prfunc(" Failure: Instruction Translation Cache"); - if (info.dtc) + if (info->dtc) prfunc(" Failure: Data Translation Cache"); - if (info.itr) { + if (info->itr) { prfunc(" Failure: Instruction Translation Register"); - prfunc(" ,Slot: %d", info.tr_slot); + prfunc(" ,Slot: %d", info->tr_slot); } - if (info.dtr) { + if (info->dtr) { prfunc(" Failure: Data Translation Register"); - prfunc(" ,Slot: %d", info.tr_slot); + prfunc(" ,Slot: %d", info->tr_slot); } - if (info.mc) + if (info->mc) prfunc(" ,MC: Corrected"); prfunc("\n"); } @@ -824,159 +1160,721 @@ /* * ia64_log_bus_check_info_print * Display the machine check information related to bus error(s). - * Inputs : i (Multiple errors are logged, i - index of logged error) - * info (Machine check info logged by the PAL and later + * Inputs: i (Multiple errors are logged, i - index of logged error) + * bus_info * (Ptr to machine check info logged by the PAL and later * captured by the SAL) - * req_addr (Address of the requestor of the transaction) - * resp_addr (Address of the responder of the transaction) - * target_addr (Address where the data was to be delivered to or - * obtained from) - * Outputs : None + * prfunc (fn ptr of print function to be used for output) + * Outputs: None */ void -ia64_log_bus_check_info_print(int i, - pal_bus_check_info_t info, - u64 req_addr, - u64 resp_addr, - u64 targ_addr, - prfunc_t prfunc) -{ +ia64_log_bus_check_info_print (int i, + sal_log_mod_error_info_t *bus_check_info, + prfunc_t prfunc) +{ + pal_bus_check_info_t *info; + u64 req_addr; /* Address of the requestor of the transaction */ + u64 resp_addr; /* Address of the responder of the transaction */ + u64 targ_addr; /* Address where the data was to be delivered to */ + /* or obtained from */ + + if (!bus_check_info->valid.check_info) { + IA64_MCA_DEBUG("ia64_mca_log_print: invalid bus_check_info[%d]\n", i); + return; /* If check info data not valid, skip it */ + } + + info = (pal_bus_check_info_t *)&bus_check_info->check_info; + req_addr = bus_check_info->requestor_identifier; + resp_addr = bus_check_info->responder_identifier; + targ_addr = bus_check_info->target_identifier; + prfunc("+ BUS Check Info [%d]\n+", i); - prfunc(" Status Info: %d", info.bsi); - prfunc(" ,Severity: %d", info.sev); - prfunc(" ,Transaction Type: %d", info.type); - prfunc(" ,Transaction Size: %d", info.size); - if (info.cc) + prfunc(" Status Info: %d", info->bsi); + prfunc(" ,Severity: %d", info->sev); + prfunc(" ,Transaction Type: %d", info->type); + prfunc(" ,Transaction Size: %d", info->size); + if (info->cc) prfunc(" ,Cache-cache-transfer"); - if (info.ib) + if (info->ib) prfunc(" ,Error: Internal"); - if (info.eb) + if (info->eb) prfunc(" ,Error: External"); - if (info.mc) + if (info->mc) prfunc(" ,MC: Corrected"); - if (info.tv) + if (info->tv) prfunc(" ,Target Address: 0x%lx", targ_addr); - if (info.rq) + if (info->rq) prfunc(" ,Requestor Address: 0x%lx", req_addr); - if (info.tv) + if (info->tv) prfunc(" ,Responder Address: 0x%lx", resp_addr); prfunc("\n"); } /* + * ia64_log_mem_dev_err_info_print + * + * Format and log the platform memory device error record section data. + * + * Inputs: mem_dev_err_info * (Ptr to memory device error record section + * returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_mem_dev_err_info_print (sal_log_mem_dev_err_info_t *mdei, + prfunc_t prfunc) +{ + prfunc("+ Mem Error Detail: "); + + if (mdei->valid.error_status) + prfunc(" Error Status: %#lx,", mdei->error_status); + if (mdei->valid.physical_addr) + prfunc(" Physical Address: %#lx,", mdei->physical_addr); + if (mdei->valid.addr_mask) + prfunc(" Address Mask: %#lx,", mdei->addr_mask); + if (mdei->valid.node) + prfunc(" Node: %d,", mdei->node); + if (mdei->valid.card) + prfunc(" Card: %d,", mdei->card); + if (mdei->valid.module) + prfunc(" Module: %d,", mdei->module); + if (mdei->valid.bank) + prfunc(" Bank: %d,", mdei->bank); + if (mdei->valid.device) + prfunc(" Device: %d,", mdei->device); + if (mdei->valid.row) + prfunc(" Row: %d,", mdei->row); + if (mdei->valid.column) + prfunc(" Column: %d,", mdei->column); + if (mdei->valid.bit_position) + prfunc(" Bit Position: %d,", mdei->bit_position); + if (mdei->valid.target_id) + prfunc(" ,Target Address: %#lx,", mdei->target_id); + if (mdei->valid.requestor_id) + prfunc(" ,Requestor Address: %#lx,", mdei->requestor_id); + if (mdei->valid.responder_id) + prfunc(" ,Responder Address: %#lx,", mdei->responder_id); + if (mdei->valid.bus_spec_data) + prfunc(" Bus Specific Data: %#lx,", mdei->bus_spec_data); + prfunc("\n"); + + if (mdei->valid.oem_id) { + u8 *p_data = &(mdei->oem_id[0]); + int i; + + prfunc(" OEM Memory Controller ID:"); + for (i = 0; i < 16; i++, p_data++) + prfunc(" %02x", *p_data); + prfunc("\n"); + } + + if (mdei->valid.oem_data) { + ia64_log_prt_oem_data((int)mdei->header.len, + (int)sizeof(sal_log_mem_dev_err_info_t) - 1, + &(mdei->oem_data[0]), prfunc); + } +} + +/* + * ia64_log_sel_dev_err_info_print + * + * Format and log the platform SEL device error record section data. + * + * Inputs: sel_dev_err_info * (Ptr to the SEL device error record section + * returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_sel_dev_err_info_print (sal_log_sel_dev_err_info_t *sdei, + prfunc_t prfunc) +{ + int i; + + prfunc("+ SEL Device Error Detail: "); + + if (sdei->valid.record_id) + prfunc(" Record ID: %#x", sdei->record_id); + if (sdei->valid.record_type) + prfunc(" Record Type: %#x", sdei->record_type); + prfunc(" Time Stamp: "); + for (i = 0; i < 4; i++) + prfunc("%1d", sdei->timestamp[i]); + if (sdei->valid.generator_id) + prfunc(" Generator ID: %#x", sdei->generator_id); + if (sdei->valid.evm_rev) + prfunc(" Message Format Version: %#x", sdei->evm_rev); + if (sdei->valid.sensor_type) + prfunc(" Sensor Type: %#x", sdei->sensor_type); + if (sdei->valid.sensor_num) + prfunc(" Sensor Number: %#x", sdei->sensor_num); + if (sdei->valid.event_dir) + prfunc(" Event Direction Type: %#x", sdei->event_dir); + if (sdei->valid.event_data1) + prfunc(" Data1: %#x", sdei->event_data1); + if (sdei->valid.event_data2) + prfunc(" Data2: %#x", sdei->event_data2); + if (sdei->valid.event_data3) + prfunc(" Data3: %#x", sdei->event_data3); + prfunc("\n"); + +} + +/* + * ia64_log_pci_bus_err_info_print + * + * Format and log the platform PCI bus error record section data. + * + * Inputs: pci_bus_err_info * (Ptr to the PCI bus error record section + * returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_pci_bus_err_info_print (sal_log_pci_bus_err_info_t *pbei, + prfunc_t prfunc) +{ + prfunc("+ PCI Bus Error Detail: "); + + if (pbei->valid.err_status) + prfunc(" Error Status: %#lx", pbei->err_status); + if (pbei->valid.err_type) + prfunc(" Error Type: %#x", pbei->err_type); + if (pbei->valid.bus_id) + prfunc(" Bus ID: %#x", pbei->bus_id); + if (pbei->valid.bus_address) + prfunc(" Bus Address: %#lx", pbei->bus_address); + if (pbei->valid.bus_data) + prfunc(" Bus Data: %#lx", pbei->bus_data); + if (pbei->valid.bus_cmd) + prfunc(" Bus Command: %#lx", pbei->bus_cmd); + if (pbei->valid.requestor_id) + prfunc(" Requestor ID: %#lx", pbei->requestor_id); + if (pbei->valid.responder_id) + prfunc(" Responder ID: %#lx", pbei->responder_id); + if (pbei->valid.target_id) + prfunc(" Target ID: %#lx", pbei->target_id); + if (pbei->valid.oem_data) + prfunc("\n"); + + if (pbei->valid.oem_data) { + ia64_log_prt_oem_data((int)pbei->header.len, + (int)sizeof(sal_log_pci_bus_err_info_t) - 1, + &(pbei->oem_data[0]), prfunc); + } +} + +/* + * ia64_log_smbios_dev_err_info_print + * + * Format and log the platform SMBIOS device error record section data. + * + * Inputs: smbios_dev_err_info * (Ptr to the SMBIOS device error record + * section returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_smbios_dev_err_info_print (sal_log_smbios_dev_err_info_t *sdei, + prfunc_t prfunc) +{ + u8 i; + + prfunc("+ SMBIOS Device Error Detail: "); + + if (sdei->valid.event_type) + prfunc(" Event Type: %#x", sdei->event_type); + if (sdei->valid.time_stamp) { + prfunc(" Time Stamp: "); + for (i = 0; i < 6; i++) + prfunc("%d", sdei->time_stamp[i]); + } + if ((sdei->valid.data) && (sdei->valid.length)) { + prfunc(" Data: "); + for (i = 0; i < sdei->length; i++) + prfunc(" %02x", sdei->data[i]); + } + prfunc("\n"); +} + +/* + * ia64_log_pci_comp_err_info_print + * + * Format and log the platform PCI component error record section data. + * + * Inputs: pci_comp_err_info * (Ptr to the PCI component error record section + * returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_pci_comp_err_info_print(sal_log_pci_comp_err_info_t *pcei, + prfunc_t prfunc) +{ + u32 n_mem_regs, n_io_regs; + u64 i, n_pci_data; + u64 *p_reg_data; + u8 *p_oem_data; + + prfunc("+ PCI Component Error Detail: "); + + if (pcei->valid.err_status) + prfunc(" Error Status: %#lx\n", pcei->err_status); + if (pcei->valid.comp_info) + prfunc(" Component Info: Vendor Id = %#x, Device Id = %#x," + " Class Code = %#x, Seg/Bus/Dev/Func = %d/%d/%d/%d\n", + pcei->comp_info.vendor_id, pcei->comp_info.device_id, + pcei->comp_info.class_code, pcei->comp_info.seg_num, + pcei->comp_info.bus_num, pcei->comp_info.dev_num, + pcei->comp_info.func_num); + + n_mem_regs = (pcei->valid.num_mem_regs) ? pcei->num_mem_regs : 0; + n_io_regs = (pcei->valid.num_io_regs) ? pcei->num_io_regs : 0; + p_reg_data = &(pcei->reg_data_pairs[0]); + p_oem_data = (u8 *)p_reg_data + + (n_mem_regs + n_io_regs) * 2 * sizeof(u64); + n_pci_data = p_oem_data - (u8 *)pcei; + + if (n_pci_data > pcei->header.len) { + prfunc(" Invalid PCI Component Error Record format: length = %ld, " + " Size PCI Data = %d, Num Mem-Map/IO-Map Regs = %ld/%ld\n", + pcei->header.len, n_pci_data, n_mem_regs, n_io_regs); + return; + } + + if (n_mem_regs) { + prfunc(" Memory Mapped Registers\n Address \tValue\n"); + for (i = 0; i < pcei->num_mem_regs; i++) { + prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]); + p_reg_data += 2; + } + } + if (n_io_regs) { + prfunc(" I/O Mapped Registers\n Address \tValue\n"); + for (i = 0; i < pcei->num_io_regs; i++) { + prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]); + p_reg_data += 2; + } + } + if (pcei->valid.oem_data) { + ia64_log_prt_oem_data((int)pcei->header.len, n_pci_data, + p_oem_data, prfunc); + prfunc("\n"); + } +} + +/* + * ia64_log_plat_specific_err_info_print + * + * Format and log the platform specifie error record section data. + * + * Inputs: sel_dev_err_info * (Ptr to the platform specific error record + * section returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_plat_specific_err_info_print (sal_log_plat_specific_err_info_t *psei, + prfunc_t prfunc) +{ + prfunc("+ Platform Specific Error Detail: "); + + if (psei->valid.err_status) + prfunc(" Error Status: %#lx", psei->err_status); + if (psei->valid.guid) { + prfunc(" GUID: "); + ia64_log_prt_guid(&psei->guid, prfunc); + } + if (psei->valid.oem_data) { + ia64_log_prt_oem_data((int)psei->header.len, + (int)sizeof(sal_log_plat_specific_err_info_t) - 1, + &(psei->oem_data[0]), prfunc); + } + prfunc("\n"); +} + +/* + * ia64_log_host_ctlr_err_info_print + * + * Format and log the platform host controller error record section data. + * + * Inputs: host_ctlr_err_info * (Ptr to the host controller error record + * section returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_host_ctlr_err_info_print (sal_log_host_ctlr_err_info_t *hcei, + prfunc_t prfunc) +{ + prfunc("+ Host Controller Error Detail: "); + + if (hcei->valid.err_status) + prfunc(" Error Status: %#lx", hcei->err_status); + if (hcei->valid.requestor_id) + prfunc(" Requestor ID: %#lx", hcei->requestor_id); + if (hcei->valid.responder_id) + prfunc(" Responder ID: %#lx", hcei->responder_id); + if (hcei->valid.target_id) + prfunc(" Target ID: %#lx", hcei->target_id); + if (hcei->valid.bus_spec_data) + prfunc(" Bus Specific Data: %#lx", hcei->bus_spec_data); + if (hcei->valid.oem_data) { + ia64_log_prt_oem_data((int)hcei->header.len, + (int)sizeof(sal_log_host_ctlr_err_info_t) - 1, + &(hcei->oem_data[0]), prfunc); + } + prfunc("\n"); +} + +/* + * ia64_log_plat_bus_err_info_print + * + * Format and log the platform bus error record section data. + * + * Inputs: plat_bus_err_info * (Ptr to the platform bus error record section + * returned by SAL) + * prfunc (fn ptr of print function to be used for output) + * Outputs: None + */ +void +ia64_log_plat_bus_err_info_print (sal_log_plat_bus_err_info_t *pbei, + prfunc_t prfunc) +{ + prfunc("+ Platform Bus Error Detail: "); + + if (pbei->valid.err_status) + prfunc(" Error Status: %#lx", pbei->err_status); + if (pbei->valid.requestor_id) + prfunc(" Requestor ID: %#lx", pbei->requestor_id); + if (pbei->valid.responder_id) + prfunc(" Responder ID: %#lx", pbei->responder_id); + if (pbei->valid.target_id) + prfunc(" Target ID: %#lx", pbei->target_id); + if (pbei->valid.bus_spec_data) + prfunc(" Bus Specific Data: %#lx", pbei->bus_spec_data); + if (pbei->valid.oem_data) { + ia64_log_prt_oem_data((int)pbei->header.len, + (int)sizeof(sal_log_plat_bus_err_info_t) - 1, + &(pbei->oem_data[0]), prfunc); + } + prfunc("\n"); +} + +/* + * ia64_log_proc_dev_err_info_print + * + * Display the processor device error record. + * + * Inputs: sal_log_processor_info_t * (Ptr to processor device error record + * section body). + * prfunc (fn ptr of print function to be used + * for output). + * Outputs: None + */ +void +ia64_log_proc_dev_err_info_print (sal_log_processor_info_t *slpi, + prfunc_t prfunc) +{ +#ifdef MCA_PRT_XTRA_DATA + size_t d_len = slpi->header.len - sizeof(sal_log_section_hdr_t); +#endif + sal_processor_static_info_t *spsi; + int i; + sal_log_mod_error_info_t *p_data; + + prfunc("+Processor Device Error Info Section\n"); + +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + { + char *p_data = (char *)&slpi->valid; + + prfunc("SAL_PROC_DEV_ERR SECTION DATA: Data buffer = %p, " + "Data size = %ld\n", (void *)p_data, d_len); + ia64_log_hexdump(p_data, d_len, prfunc); + prfunc("End of SAL_PROC_DEV_ERR SECTION DATA\n"); + } +#endif // MCA_PRT_XTRA_DATA for test only @FVL + + if (slpi->valid.proc_error_map) + prfunc(" Processor Error Map: %#lx\n", slpi->proc_error_map); + + if (slpi->valid.proc_state_param) + prfunc(" Processor State Param: %#lx\n", slpi->proc_state_parameter); + + if (slpi->valid.proc_cr_lid) + prfunc(" Processor LID: %#lx\n", slpi->proc_cr_lid); + + /* + * Note: March 2001 SAL spec states that if the number of elements in any + * of the MOD_ERROR_INFO_STRUCT arrays is zero, the entire array is + * absent. Also, current implementations only allocate space for number of + * elements used. So we walk the data pointer from here on. + */ + p_data = &slpi->cache_check_info[0]; + + /* Print the cache check information if any*/ + for (i = 0 ; i < slpi->valid.num_cache_check; i++, p_data++) + ia64_log_cache_check_info_print(i, p_data, prfunc); + + /* Print the tlb check information if any*/ + for (i = 0 ; i < slpi->valid.num_tlb_check; i++, p_data++) + ia64_log_tlb_check_info_print(i, p_data, prfunc); + + /* Print the bus check information if any*/ + for (i = 0 ; i < slpi->valid.num_bus_check; i++, p_data++) + ia64_log_bus_check_info_print(i, p_data, prfunc); + + /* Print the reg file check information if any*/ + for (i = 0 ; i < slpi->valid.num_reg_file_check; i++, p_data++) + ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t), + prfunc); /* Just hex dump for now */ + + /* Print the ms check information if any*/ + for (i = 0 ; i < slpi->valid.num_ms_check; i++, p_data++) + ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t), + prfunc); /* Just hex dump for now */ + + /* Print CPUID registers if any*/ + if (slpi->valid.cpuid_info) { + u64 *p = (u64 *)p_data; + + prfunc(" CPUID Regs: %#lx %#lx %#lx %#lx\n", p[0], p[1], p[2], p[3]); + p_data++; + } + + /* Print processor static info if any */ + if (slpi->valid.psi_static_struct) { + spsi = (sal_processor_static_info_t *)p_data; + + /* Print branch register contents if valid */ + if (spsi->valid.br) + ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br", + prfunc); + + /* Print control register contents if valid */ + if (spsi->valid.cr) + ia64_log_processor_regs_print(spsi->cr, 128, "Control", "cr", + prfunc); + + /* Print application register contents if valid */ + if (spsi->valid.ar) + ia64_log_processor_regs_print(spsi->ar, 128, "Application", + "ar", prfunc); + + /* Print region register contents if valid */ + if (spsi->valid.rr) + ia64_log_processor_regs_print(spsi->rr, 8, "Region", "rr", + prfunc); + + /* Print floating-point register contents if valid */ + if (spsi->valid.fr) + ia64_log_processor_fp_regs_print(spsi->fr, 128, "Floating-point", "fr", + prfunc); + } +} + +/* * ia64_log_processor_info_print + * * Display the processor-specific information logged by PAL as a part * of MCA or INIT or CMC. - * Inputs : lh (Pointer of the sal log header which specifies the format - * of SAL state info as specified by the SAL spec). + * + * Inputs : lh (Pointer of the sal log header which specifies the + * format of SAL state info as specified by the SAL spec). + * prfunc (fn ptr of print function to be used for output). * Outputs : None */ void -ia64_log_processor_info_print(sal_log_header_t *lh, prfunc_t prfunc) +ia64_log_processor_info_print(sal_log_record_header_t *lh, prfunc_t prfunc) { - sal_log_processor_info_t *slpi; - int i; + sal_log_section_hdr_t *slsh; + int n_sects; + int ercd_pos; if (!lh) return; - if (lh->slh_log_type != SAL_SUB_INFO_TYPE_PROCESSOR) +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + ia64_log_prt_record_header(lh, prfunc); +#endif // MCA_PRT_XTRA_DATA for test only @FVL + + if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) { + IA64_MCA_DEBUG("ia64_mca_log_print: " + "truncated SAL CMC error record. len = %d\n", + lh->len); return; + } - slpi = (sal_log_processor_info_t *)((char *)lh+sizeof(sal_log_header_t)); /* point to proc info */ + /* Print record header info */ + ia64_log_rec_header_print(lh, prfunc); - if (!slpi) { - prfunc("No Processor Error Log found\n"); - return; + for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) { + /* point to next section header */ + slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos); + +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + ia64_log_prt_section_header(slsh, prfunc); +#endif // MCA_PRT_XTRA_DATA for test only @FVL + + if (verify_guid((void *)&slsh->guid, (void *)&(SAL_PROC_DEV_ERR_SECT_GUID))) { + IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n"); + continue; + } + + /* + * Now process processor device error record section + */ + ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, + printk); } - /* Print branch register contents if valid */ - if (slpi->slpi_valid.slpi_br) - ia64_log_processor_regs_print(slpi->slpi_br, 8, "Branch", "br", prfunc); + IA64_MCA_DEBUG("ia64_mca_log_print: " + "found %d sections in SAL CMC error record. len = %d\n", + n_sects, lh->len); + if (!n_sects) { + prfunc("No Processor Device Error Info Section found\n"); + return; + } +} - /* Print control register contents if valid */ - if (slpi->slpi_valid.slpi_cr) - ia64_log_processor_regs_print(slpi->slpi_cr, 128, "Control", "cr", prfunc); +/* + * ia64_log_platform_info_print + * + * Format and Log the SAL Platform Error Record. + * + * Inputs : lh (Pointer to the sal error record header with format + * specified by the SAL spec). + * prfunc (fn ptr of log output function to use) + * Outputs : None + */ +void +ia64_log_platform_info_print (sal_log_record_header_t *lh, prfunc_t prfunc) +{ + sal_log_section_hdr_t *slsh; + int n_sects; + int ercd_pos; - /* Print application register contents if valid */ - if (slpi->slpi_valid.slpi_ar) - ia64_log_processor_regs_print(slpi->slpi_br, 128, "Application", "ar", prfunc); + if (!lh) + return; - /* Print region register contents if valid */ - if (slpi->slpi_valid.slpi_rr) - ia64_log_processor_regs_print(slpi->slpi_rr, 8, "Region", "rr", prfunc); +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + ia64_log_prt_record_header(lh, prfunc); +#endif // MCA_PRT_XTRA_DATA for test only @FVL + + if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) { + IA64_MCA_DEBUG("ia64_mca_log_print: " + "truncated SAL error record. len = %d\n", + lh->len); + return; + } - /* Print floating-point register contents if valid */ - if (slpi->slpi_valid.slpi_fr) - ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr", - prfunc); + /* Print record header info */ + ia64_log_rec_header_print(lh, prfunc); - /* Print the cache check information if any*/ - for (i = 0 ; i < MAX_CACHE_ERRORS; i++) - ia64_log_cache_check_info_print(i, - slpi->slpi_cache_check_info[i].slpi_cache_check, - slpi->slpi_cache_check_info[i].slpi_target_address, - prfunc); - /* Print the tlb check information if any*/ - for (i = 0 ; i < MAX_TLB_ERRORS; i++) - ia64_log_tlb_check_info_print(i,slpi->slpi_tlb_check_info[i], prfunc); + for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) { + /* point to next section header */ + slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos); + +#ifdef MCA_PRT_XTRA_DATA // for test only @FVL + ia64_log_prt_section_header(slsh, prfunc); + + if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) != 0) { + size_t d_len = slsh->len - sizeof(sal_log_section_hdr_t); + char *p_data = (char *)&((sal_log_mem_dev_err_info_t *)slsh)->valid; + + prfunc("Start of Platform Err Data Section: Data buffer = %p, " + "Data size = %ld\n", (void *)p_data, d_len); + ia64_log_hexdump(p_data, d_len, prfunc); + prfunc("End of Platform Err Data Section\n"); + } +#endif // MCA_PRT_XTRA_DATA for test only @FVL - /* Print the bus check information if any*/ - for (i = 0 ; i < MAX_BUS_ERRORS; i++) - ia64_log_bus_check_info_print(i, - slpi->slpi_bus_check_info[i].slpi_bus_check, - slpi->slpi_bus_check_info[i].slpi_requestor_addr, - slpi->slpi_bus_check_info[i].slpi_responder_addr, - slpi->slpi_bus_check_info[i].slpi_target_addr, - prfunc); + /* + * Now process CPE error record section + */ + if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) == 0) { + ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) { + prfunc("+Platform Memory Device Error Info Section\n"); + ia64_log_mem_dev_err_info_print((sal_log_mem_dev_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID) == 0) { + prfunc("+Platform SEL Device Error Info Section\n"); + ia64_log_sel_dev_err_info_print((sal_log_sel_dev_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID) == 0) { + prfunc("+Platform PCI Bus Error Info Section\n"); + ia64_log_pci_bus_err_info_print((sal_log_pci_bus_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID) == 0) { + prfunc("+Platform SMBIOS Device Error Info Section\n"); + ia64_log_smbios_dev_err_info_print((sal_log_smbios_dev_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID) == 0) { + prfunc("+Platform PCI Component Error Info Section\n"); + ia64_log_pci_comp_err_info_print((sal_log_pci_comp_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) { + prfunc("+Platform Specific Error Info Section\n"); + ia64_log_plat_specific_err_info_print((sal_log_plat_specific_err_info_t *) + slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID) == 0) { + prfunc("+Platform Host Controller Error Info Section\n"); + ia64_log_host_ctlr_err_info_print((sal_log_host_ctlr_err_info_t *)slsh, + prfunc); + } else if (efi_guidcmp(slsh->guid, SAL_PLAT_BUS_ERR_SECT_GUID) == 0) { + prfunc("+Platform Bus Error Info Section\n"); + ia64_log_plat_bus_err_info_print((sal_log_plat_bus_err_info_t *)slsh, + prfunc); + } else { + IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n"); + continue; + } + } + IA64_MCA_DEBUG("ia64_mca_log_print: found %d sections in SAL error record. len = %d\n", + n_sects, lh->len); + if (!n_sects) { + prfunc("No Platform Error Info Sections found\n"); + return; + } } /* * ia64_log_print - * Display the contents of the OS error log information - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) - * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) + * + * Displays the contents of the OS error log information + * + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) + * prfunc (fn ptr of log output function to use) * Outputs : None */ void -ia64_log_print(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc) +ia64_log_print(int sal_info_type, prfunc_t prfunc) { - char *info_type, *sub_info_type; - switch(sal_info_type) { - case SAL_INFO_TYPE_MCA: - info_type = "MCA"; + case SAL_INFO_TYPE_MCA: + prfunc("+BEGIN HARDWARE ERROR STATE AT MCA\n"); + ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); + prfunc("+END HARDWARE ERROR STATE AT MCA\n"); break; - case SAL_INFO_TYPE_INIT: - info_type = "INIT"; + case SAL_INFO_TYPE_INIT: + prfunc("+MCA INIT ERROR LOG (UNIMPLEMENTED)\n"); break; - case SAL_INFO_TYPE_CMC: - info_type = "CMC"; + case SAL_INFO_TYPE_CMC: + prfunc("+BEGIN HARDWARE ERROR STATE AT CMC\n"); + ia64_log_processor_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); + prfunc("+END HARDWARE ERROR STATE AT CMC\n"); break; - default: - info_type = "UNKNOWN"; + case SAL_INFO_TYPE_CPE: + prfunc("+BEGIN HARDWARE ERROR STATE AT CPE\n"); + ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); + prfunc("+END HARDWARE ERROR STATE AT CPE\n"); break; - } - - switch(sal_sub_info_type) { - case SAL_SUB_INFO_TYPE_PROCESSOR: - sub_info_type = "PROCESSOR"; - break; - case SAL_SUB_INFO_TYPE_PLATFORM: - sub_info_type = "PLATFORM"; - break; - default: - sub_info_type = "UNKNOWN"; + default: + prfunc("+MCA UNKNOWN ERROR LOG (UNIMPLEMENTED)\n"); break; } - - prfunc("+BEGIN HARDWARE ERROR STATE [%s %s]\n", info_type, sub_info_type); - if (sal_sub_info_type == SAL_SUB_INFO_TYPE_PROCESSOR) - ia64_log_processor_info_print( - IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type), - prfunc); - else - log_print_platform(IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type),prfunc); - prfunc("+END HARDWARE ERROR STATE [%s %s]\n", info_type, sub_info_type); } diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/mca_asm.S linux/arch/ia64/kernel/mca_asm.S --- v2.4.14/linux/arch/ia64/kernel/mca_asm.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/mca_asm.S Fri Nov 9 14:26:17 2001 @@ -9,6 +9,7 @@ // #include <linux/config.h> +#include <asm/asmmacro.h> #include <asm/pgtable.h> #include <asm/processor.h> #include <asm/mca_asm.h> @@ -23,7 +24,7 @@ #include "minstate.h" /* - * SAL_TO_OS_MCA_HANDOFF_STATE + * SAL_TO_OS_MCA_HANDOFF_STATE (SAL 3.0 spec) * 1. GR1 = OS GP * 2. GR8 = PAL_PROC physical address * 3. GR9 = SAL_PROC physical address @@ -33,6 +34,7 @@ */ #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ movl _tmp=ia64_sal_to_os_handoff_state;; \ + DATA_VA_TO_PA(_tmp);; \ st8 [_tmp]=r1,0x08;; \ st8 [_tmp]=r8,0x08;; \ st8 [_tmp]=r9,0x08;; \ @@ -41,47 +43,29 @@ st8 [_tmp]=r12,0x08;; /* - * OS_MCA_TO_SAL_HANDOFF_STATE - * 1. GR8 = OS_MCA status - * 2. GR9 = SAL GP (physical) - * 3. GR22 = New min state save area pointer + * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec) + * 1. GR8 = OS_MCA return status + * 2. GR9 = SAL GP (physical) + * 3. GR10 = 0/1 returning same/new context + * 4. GR22 = New min state save area pointer + * returns ptr to SAL rtn save loc in _tmp */ -#define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ - movl _tmp=ia64_os_to_sal_handoff_state;; \ - DATA_VA_TO_PA(_tmp);; \ - ld8 r8=[_tmp],0x08;; \ - ld8 r9=[_tmp],0x08;; \ - ld8 r22=[_tmp],0x08;; - -/* - * BRANCH - * Jump to the instruction referenced by - * "to_label". - * Branch is taken only if the predicate - * register "p" is true. - * "ip" is the address of the instruction - * located at "from_label". - * "temp" is a scratch register like r2 - * "adjust" needed for HP compiler. - * A screwup somewhere with constant arithmetic. - */ -#define BRANCH(to_label, temp, p, adjust) \ -100: (p) mov temp=ip; \ - ;; \ - (p) adds temp=to_label-100b,temp;\ - ;; \ - (p) adds temp=adjust,temp; \ - ;; \ - (p) mov b1=temp ; \ - (p) br b1 +#define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ + movl _tmp=ia64_os_to_sal_handoff_state;; \ + DATA_VA_TO_PA(_tmp);; \ + ld8 r8=[_tmp],0x08;; \ + ld8 r9=[_tmp],0x08;; \ + ld8 r10=[_tmp],0x08;; \ + ld8 r22=[_tmp],0x08;; \ + movl _tmp=ia64_sal_to_os_handoff_state;; \ + DATA_VA_TO_PA(_tmp);; \ + add _tmp=0x28,_tmp;; // point to SAL rtn save location .global ia64_os_mca_dispatch .global ia64_os_mca_dispatch_end .global ia64_sal_to_os_handoff_state .global ia64_os_to_sal_handoff_state - .global ia64_os_mca_ucmc_handler .global ia64_mca_proc_state_dump - .global ia64_mca_proc_state_restore .global ia64_mca_stack .global ia64_mca_stackframe .global ia64_mca_bspstore @@ -100,7 +84,7 @@ #endif /* #if defined(MCA_TEST) */ // Save the SAL to OS MCA handoff state as defined - // by SAL SPEC 2.5 + // by SAL SPEC 3.0 // NOTE : The order in which the state gets saved // is dependent on the way the C-structure // for ia64_mca_sal_to_os_state_t has been @@ -110,15 +94,20 @@ // LOG PROCESSOR STATE INFO FROM HERE ON.. ;; begin_os_mca_dump: - BRANCH(ia64_os_mca_proc_state_dump, r2, p0, 0x0) - ;; + br ia64_os_mca_proc_state_dump;; + ia64_os_mca_done_dump: // Setup new stack frame for OS_MCA handling - movl r2=ia64_mca_bspstore // local bspstore area location in r2 - movl r3=ia64_mca_stackframe // save stack frame to memory in r3 + movl r2=ia64_mca_bspstore;; // local bspstore area location in r2 + DATA_VA_TO_PA(r2);; + movl r3=ia64_mca_stackframe;; // save stack frame to memory in r3 + DATA_VA_TO_PA(r3);; rse_switch_context(r6,r3,r2);; // RSC management in this new context movl r12=ia64_mca_stack;; + mov r2=8*1024;; // stack size must be same as c array + add r12=r2,r12;; // stack base @ bottom of array + DATA_VA_TO_PA(r12);; // Enter virtual mode from physical mode VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4) @@ -127,7 +116,7 @@ // call our handler movl r2=ia64_mca_ucmc_handler;; mov b6=r2;; - br.call.sptk.few b0=b6 + br.call.sptk.many b0=b6;; .ret0: // Revert back to physical mode before going back to SAL PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4) @@ -135,9 +124,9 @@ #if defined(MCA_TEST) // Pretend that we are in interrupt context - mov r2=psr - dep r2=0, r2, PSR_IC, 2; - mov psr.l = r2 + mov r2=psr;; + dep r2=0, r2, PSR_IC, 2;; + mov psr.l = r2;; #endif /* #if defined(MCA_TEST) */ // restore the original stack frame here @@ -152,15 +141,14 @@ mov r8=gp ;; begin_os_mca_restore: - BRANCH(ia64_os_mca_proc_state_restore, r2, p0, 0x0) - ;; + br ia64_os_mca_proc_state_restore;; ia64_os_mca_done_restore: ;; // branch back to SALE_CHECK OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2) ld8 r3=[r2];; - mov b0=r3 // SAL_CHECK return address + mov b0=r3;; // SAL_CHECK return address br b0 ;; ia64_os_mca_dispatch_end: @@ -178,8 +166,10 @@ //-- ia64_os_mca_proc_state_dump: -// Get and save GR0-31 from Proc. Min. State Save Area to SAL PSI +// Save bank 1 GRs 16-31 which will be used by c-language code when we switch +// to virtual addressing mode. movl r2=ia64_mca_proc_state_dump;; // Os state dump area + DATA_VA_TO_PA(r2) // convert to to physical address // save ar.NaT mov r5=ar.unat // ar.unat @@ -250,16 +240,16 @@ // if PSR.ic=0, reading interruption registers causes an illegal operation fault mov r3=psr;; tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test -(p6) st8 [r2]=r0,9*8+160 // increment by 168 byte inc. +(p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc. begin_skip_intr_regs: - BRANCH(SkipIntrRegs, r9, p6, 0x0) - ;; +(p6) br SkipIntrRegs;; + add r4=8,r2 // duplicate r2 in r4 add r6=2*8,r2 // duplicate r2 in r6 mov r3=cr16 // cr.ipsr mov r5=cr17 // cr.isr - mov r7=r0;; // cr.ida => cr18 + mov r7=r0;; // cr.ida => cr18 (reserved) st8 [r2]=r3,3*8 st8 [r4]=r5,3*8 st8 [r6]=r7,3*8;; @@ -394,8 +384,7 @@ br.cloop.sptk.few cStRR ;; end_os_mca_dump: - BRANCH(ia64_os_mca_done_dump, r2, p0, -0x10) - ;; + br ia64_os_mca_done_dump;; //EndStub////////////////////////////////////////////////////////////////////// @@ -484,11 +473,10 @@ // if PSR.ic=1, reading interruption registers causes an illegal operation fault mov r3=psr;; tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test -(p6) st8 [r2]=r0,9*8+160 // increment by 160 byte inc. +(p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc. begin_rskip_intr_regs: - BRANCH(rSkipIntrRegs, r9, p6, 0x0) - ;; +(p6) br rSkipIntrRegs;; add r4=8,r2 // duplicate r2 in r4 add r6=2*8,r2;; // duplicate r2 in r4 @@ -498,7 +486,7 @@ ld8 r7=[r6],3*8;; mov cr16=r3 // cr.ipsr mov cr17=r5 // cr.isr is read only -// mov cr18=r7;; // cr.ida +// mov cr18=r7;; // cr.ida (reserved - don't restore) ld8 r3=[r2],3*8 ld8 r5=[r4],3*8 @@ -629,8 +617,8 @@ mov ar.lc=r5 ;; end_os_mca_restore: - BRANCH(ia64_os_mca_done_restore, r2, p0, -0x20) - ;; + br ia64_os_mca_done_restore;; + //EndStub////////////////////////////////////////////////////////////////////// // ok, the issue here is that we need to save state information so @@ -660,12 +648,7 @@ // 6. GR12 = Return address to location within SAL_INIT procedure - .text - .align 16 -.global ia64_monarch_init_handler -.proc ia64_monarch_init_handler -ia64_monarch_init_handler: - +GLOBAL_ENTRY(ia64_monarch_init_handler) #if defined(CONFIG_SMP) && defined(SAL_MPINIT_WORKAROUND) // // work around SAL bug that sends all processors to monarch entry @@ -741,13 +724,12 @@ adds out0=16,sp // out0 = pointer to pt_regs ;; - br.call.sptk.few rp=ia64_init_handler + br.call.sptk.many rp=ia64_init_handler .ret1: return_from_init: br.sptk return_from_init - - .endp +END(ia64_monarch_init_handler) // // SAL to OS entry point for INIT on the slave processor @@ -755,14 +737,6 @@ // as a part of ia64_mca_init. // - .text - .align 16 -.global ia64_slave_init_handler -.proc ia64_slave_init_handler -ia64_slave_init_handler: - - -slave_init_spin_me: - br.sptk slave_init_spin_me - ;; - .endp +GLOBAL_ENTRY(ia64_slave_init_handler) +1: br.sptk 1b +END(ia64_slave_init_handler) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/pal.S linux/arch/ia64/kernel/pal.S --- v2.4.14/linux/arch/ia64/kernel/pal.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/pal.S Fri Nov 9 14:26:17 2001 @@ -4,8 +4,9 @@ * * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> - * Copyright (C) 1999-2000 David Mosberger <davidm@hpl.hp.com> - * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 1999-2001 Hewlett-Packard Co + * David Mosberger <davidm@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> * * 05/22/2000 eranian Added support for stacked register calls * 05/24/2000 eranian Added support for physical mode static calls @@ -31,7 +32,7 @@ movl r2=pal_entry_point ;; st8 [r2]=in0 - br.ret.sptk.few rp + br.ret.sptk.many rp END(ia64_pal_handler_init) /* @@ -41,7 +42,7 @@ */ GLOBAL_ENTRY(ia64_pal_default_handler) mov r8=-1 - br.cond.sptk.few rp + br.cond.sptk.many rp END(ia64_pal_default_handler) /* @@ -79,13 +80,13 @@ ;; (p6) srlz.i mov rp = r8 - br.cond.sptk.few b7 + br.cond.sptk.many b7 1: mov psr.l = loc3 mov ar.pfs = loc1 mov rp = loc0 ;; srlz.d // seralize restoration of psr.l - br.ret.sptk.few b0 + br.ret.sptk.many b0 END(ia64_pal_call_static) /* @@ -120,7 +121,7 @@ mov rp = loc0 ;; srlz.d // serialize restoration of psr.l - br.ret.sptk.few b0 + br.ret.sptk.many b0 END(ia64_pal_call_stacked) /* @@ -173,13 +174,13 @@ or loc3=loc3,r17 // add in psr the bits to set ;; andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.few rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode .ret1: mov rp = r8 // install return address (physical) - br.cond.sptk.few b7 + br.cond.sptk.many b7 1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr - br.call.sptk.few rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode // return to virtual mode .ret2: mov psr.l = loc3 // restore init PSR @@ -188,7 +189,7 @@ ;; mov ar.rsc=loc4 // restore RSE configuration srlz.d // seralize restoration of psr.l - br.ret.sptk.few b0 + br.ret.sptk.many b0 END(ia64_pal_call_phys_static) /* @@ -227,13 +228,13 @@ mov b7 = loc2 // install target to branch reg ;; andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.few rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode .ret6: br.call.sptk.many rp=b7 // now make the call .ret7: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr - br.call.sptk.few rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode // return to virtual mode .ret8: mov psr.l = loc3 // restore init PSR mov ar.pfs = loc1 @@ -241,6 +242,6 @@ ;; mov ar.rsc=loc4 // restore RSE configuration srlz.d // seralize restoration of psr.l - br.ret.sptk.few b0 + br.ret.sptk.many b0 END(ia64_pal_call_phys_stacked) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/palinfo.c linux/arch/ia64/kernel/palinfo.c --- v2.4.14/linux/arch/ia64/kernel/palinfo.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/palinfo.c Fri Nov 9 14:26:17 2001 @@ -6,12 +6,13 @@ * Intel IA-64 Architecture Software Developer's Manual v1.0. * * - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 2000-2001 Hewlett-Packard Co + * Stephane Eranian <eranian@hpl.hp.com> * * 05/26/2000 S.Eranian initial release * 08/21/2000 S.Eranian updated to July 2000 PAL specs * 02/05/2001 S.Eranian fixed module support + * 10/23/2001 S.Eranian updated pal_perf_mon_info bug fixes */ #include <linux/config.h> #include <linux/types.h> @@ -32,8 +33,9 @@ MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>"); MODULE_DESCRIPTION("/proc interface to IA-64 PAL"); +MODULE_LICENSE("GPL"); -#define PALINFO_VERSION "0.4" +#define PALINFO_VERSION "0.5" #ifdef CONFIG_SMP #define cpu_is_online(i) (cpu_online_map & (1UL << i)) @@ -606,15 +608,6 @@ if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0; -#ifdef IA64_PAL_PERF_MON_INFO_BUG - /* - * This bug has been fixed in PAL 2.2.9 and higher - */ - pm_buffer[5]=0x3; - pm_info.pal_perf_mon_info_s.cycles = 0x12; - pm_info.pal_perf_mon_info_s.retired = 0x08; -#endif - p += sprintf(p, "PMC/PMD pairs : %d\n" \ "Counter width : %d bits\n" \ "Cycle event number : %d\n" \ @@ -636,6 +629,14 @@ p = bitregister_process(p, pm_buffer+8, 256); p += sprintf(p, "\nRetired bundles count capable : "); + +#ifdef CONFIG_ITANIUM + /* + * PAL_PERF_MON_INFO reports that only PMC4 can be used to count CPU_CYCLES + * which is wrong, both PMC4 and PMD5 support it. + */ + if (pm_buffer[12] == 0x10) pm_buffer[12]=0x30; +#endif p = bitregister_process(p, pm_buffer+12, 256); diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/pci.c linux/arch/ia64/kernel/pci.c --- v2.4.14/linux/arch/ia64/kernel/pci.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/pci.c Fri Nov 9 14:26:17 2001 @@ -38,6 +38,10 @@ #define DBG(x...) #endif +#ifdef CONFIG_IA64_MCA +extern void ia64_mca_check_errors( void ); +#endif + /* * This interrupt-safe spinlock protects all accesses to PCI * configuration space. @@ -122,6 +126,10 @@ # define PCI_BUSES_TO_SCAN 255 int i; +#ifdef CONFIG_IA64_MCA + ia64_mca_check_errors(); /* For post-failure MCA error logging */ +#endif + platform_pci_fixup(0); /* phase 0 initialization (before PCI bus has been scanned) */ printk("PCI: Probing PCI hardware\n"); @@ -194,4 +202,40 @@ pcibios_setup (char *str) { return NULL; +} + +int +pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + /* + * I/O space cannot be accessed via normal processor loads and stores on this + * platform. + */ + if (mmap_state == pci_mmap_io) + /* + * XXX we could relax this for I/O spaces for which ACPI indicates that + * the space is 1-to-1 mapped. But at the moment, we don't support + * multiple PCI address spaces and the legacy I/O space is not 1-to-1 + * mapped, so this is moot. + */ + return -EINVAL; + + /* + * Leave vm_pgoff as-is, the PCI space address is the physical address on this + * platform. + */ + vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO); + + if (write_combine) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (remap_page_range(vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; } diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/perfmon.c linux/arch/ia64/kernel/perfmon.c --- v2.4.14/linux/arch/ia64/kernel/perfmon.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/perfmon.c Fri Nov 9 14:26:17 2001 @@ -38,7 +38,7 @@ #ifdef CONFIG_PERFMON -#define PFM_VERSION "0.2" +#define PFM_VERSION "0.3" #define PFM_SMPL_HDR_VERSION 1 #define PMU_FIRST_COUNTER 4 /* first generic counter */ @@ -52,6 +52,7 @@ #define PFM_DISABLE 0xa6 /* freeze only */ #define PFM_RESTART 0xcf #define PFM_CREATE_CONTEXT 0xa7 +#define PFM_DESTROY_CONTEXT 0xa8 /* * Those 2 are just meant for debugging. I considered using sysctl() for * that but it is a little bit too pervasive. This solution is at least @@ -60,6 +61,8 @@ #define PFM_DEBUG_ON 0xe0 #define PFM_DEBUG_OFF 0xe1 +#define PFM_DEBUG_BASE PFM_DEBUG_ON + /* * perfmon API flags @@ -68,7 +71,8 @@ #define PFM_FL_INHERIT_ONCE 0x01 /* clone pfm_context only once across fork() */ #define PFM_FL_INHERIT_ALL 0x02 /* always clone pfm_context across fork() */ #define PFM_FL_SMPL_OVFL_NOBLOCK 0x04 /* do not block on sampling buffer overflow */ -#define PFM_FL_SYSTEMWIDE 0x08 /* create a systemwide context */ +#define PFM_FL_SYSTEM_WIDE 0x08 /* create a system wide context */ +#define PFM_FL_EXCL_INTR 0x10 /* exclude interrupt from system wide monitoring */ /* * PMC API flags @@ -87,7 +91,7 @@ #endif #define PMC_IS_IMPL(i) (i < pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1<< (i&~(64-1)))) -#define PMD_IS_IMPL(i) (i < pmu_conf.num_pmds && pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1)))) +#define PMD_IS_IMPL(i) (i < pmu_conf.num_pmds && pmu_conf.impl_regs[4+(i>>6)] & (1<< (i&~(64-1)))) #define PMD_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) #define PMC_IS_COUNTER(i) (i>=PMU_FIRST_COUNTER && i < (PMU_FIRST_COUNTER+pmu_conf.max_counters)) @@ -197,7 +201,8 @@ unsigned int noblock:1; /* block/don't block on overflow with notification */ unsigned int system:1; /* do system wide monitoring */ unsigned int frozen:1; /* pmu must be kept frozen on ctxsw in */ - unsigned int reserved:27; + unsigned int exclintr:1;/* exlcude interrupts from system wide monitoring */ + unsigned int reserved:26; } pfm_context_flags_t; typedef struct pfm_context { @@ -207,26 +212,33 @@ unsigned long ctx_iear_counter; /* which PMD holds I-EAR */ unsigned long ctx_btb_counter; /* which PMD holds BTB */ - pid_t ctx_notify_pid; /* who to notify on overflow */ - int ctx_notify_sig; /* XXX: SIGPROF or other */ - pfm_context_flags_t ctx_flags; /* block/noblock */ - pid_t ctx_creator; /* pid of creator (debug) */ - unsigned long ctx_ovfl_regs; /* which registers just overflowed (notification) */ - unsigned long ctx_smpl_regs; /* which registers to record on overflow */ + spinlock_t ctx_notify_lock; + pfm_context_flags_t ctx_flags; /* block/noblock */ + int ctx_notify_sig; /* XXX: SIGPROF or other */ + struct task_struct *ctx_notify_task; /* who to notify on overflow */ + struct task_struct *ctx_creator; /* pid of creator (debug) */ + + unsigned long ctx_ovfl_regs; /* which registers just overflowed (notification) */ + unsigned long ctx_smpl_regs; /* which registers to record on overflow */ + + struct semaphore ctx_restart_sem; /* use for blocking notification mode */ - struct semaphore ctx_restart_sem; /* use for blocking notification mode */ + unsigned long ctx_used_pmds[4]; /* bitmask of used PMD (speedup ctxsw) */ + unsigned long ctx_used_pmcs[4]; /* bitmask of used PMC (speedup ctxsw) */ pfm_counter_t ctx_pmds[IA64_NUM_PMD_COUNTERS]; /* XXX: size should be dynamic */ + } pfm_context_t; +#define CTX_USED_PMD(ctx,n) (ctx)->ctx_used_pmds[(n)>>6] |= 1<< ((n) % 64) +#define CTX_USED_PMC(ctx,n) (ctx)->ctx_used_pmcs[(n)>>6] |= 1<< ((n) % 64) + #define ctx_fl_inherit ctx_flags.inherit #define ctx_fl_noblock ctx_flags.noblock #define ctx_fl_system ctx_flags.system #define ctx_fl_frozen ctx_flags.frozen +#define ctx_fl_exclintr ctx_flags.exclintr -#define CTX_IS_DEAR(c,n) ((c)->ctx_dear_counter == (n)) -#define CTX_IS_IEAR(c,n) ((c)->ctx_iear_counter == (n)) -#define CTX_IS_BTB(c,n) ((c)->ctx_btb_counter == (n)) #define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_noblock == 1) #define CTX_INHERIT_MODE(c) ((c)->ctx_fl_inherit) #define CTX_HAS_SMPL(c) ((c)->ctx_smpl_buf != NULL) @@ -234,17 +246,15 @@ static pmu_config_t pmu_conf; /* for debug only */ -static unsigned long pfm_debug=0; /* 0= nodebug, >0= debug output on */ +static int pfm_debug=0; /* 0= nodebug, >0= debug output on */ + #define DBprintk(a) \ do { \ - if (pfm_debug >0) { printk(__FUNCTION__" "); printk a; } \ + if (pfm_debug >0) { printk(__FUNCTION__" %d: ", __LINE__); printk a; } \ } while (0); -static void perfmon_softint(unsigned long ignored); static void ia64_reset_pmu(void); -DECLARE_TASKLET(pfm_tasklet, perfmon_softint, 0); - /* * structure used to pass information between the interrupt handler * and the tasklet. @@ -256,26 +266,42 @@ unsigned long bitvect; /* which counters have overflowed */ } notification_info_t; -#define notification_is_invalid(i) (i->to_pid < 2) -/* will need to be cache line padded */ -static notification_info_t notify_info[NR_CPUS]; +typedef struct { + unsigned long pfs_proc_sessions; + unsigned long pfs_sys_session; /* can only be 0/1 */ + unsigned long pfs_dfl_dcr; /* XXX: hack */ + unsigned int pfs_pp; +} pfm_session_t; -/* - * We force cache line alignment to avoid false sharing - * given that we have one entry per CPU. - */ -static struct { +struct { struct task_struct *owner; } ____cacheline_aligned pmu_owners[NR_CPUS]; -/* helper macros */ + + +/* + * helper macros + */ #define SET_PMU_OWNER(t) do { pmu_owners[smp_processor_id()].owner = (t); } while(0); #define PMU_OWNER() pmu_owners[smp_processor_id()].owner +#ifdef CONFIG_SMP +#define PFM_CAN_DO_LAZY() (smp_num_cpus==1 && pfs_info.pfs_sys_session==0) +#else +#define PFM_CAN_DO_LAZY() (pfs_info.pfs_sys_session==0) +#endif + +static void pfm_lazy_save_regs (struct task_struct *ta); + /* for debug only */ static struct proc_dir_entry *perfmon_dir; /* + * XXX: hack to indicate that a system wide monitoring session is active + */ +static pfm_session_t pfs_info; + +/* * finds the number of PM(C|D) registers given * the bitvector returned by PAL */ @@ -339,8 +365,7 @@ static inline unsigned long kvirt_to_pa(unsigned long adr) { - __u64 pa; - __asm__ __volatile__ ("tpa %0 = %1" : "=r"(pa) : "r"(adr) : "memory"); + __u64 pa = ia64_tpa(adr); DBprintk(("kv2pa(%lx-->%lx)\n", adr, pa)); return pa; } @@ -568,25 +593,44 @@ static int pfx_is_sane(pfreq_context_t *pfx) { + int ctx_flags; + /* valid signal */ - if (pfx->notify_sig < 1 || pfx->notify_sig >= _NSIG) return 0; + //if (pfx->notify_sig < 1 || pfx->notify_sig >= _NSIG) return -EINVAL; + if (pfx->notify_sig !=0 && pfx->notify_sig != SIGPROF) return -EINVAL; /* cannot send to process 1, 0 means do not notify */ - if (pfx->notify_pid < 0 || pfx->notify_pid == 1) return 0; + if (pfx->notify_pid < 0 || pfx->notify_pid == 1) return -EINVAL; + + ctx_flags = pfx->flags; + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { +#ifdef CONFIG_SMP + if (smp_num_cpus > 1) { + printk("perfmon: system wide monitoring on SMP not yet supported\n"); + return -EINVAL; + } +#endif + if ((ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) == 0) { + printk("perfmon: system wide monitoring cannot use blocking notification mode\n"); + return -EINVAL; + } + } /* probably more to add here */ - return 1; + return 0; } static int -pfm_context_create(struct task_struct *task, int flags, perfmon_req_t *req) +pfm_context_create(int flags, perfmon_req_t *req) { pfm_context_t *ctx; + struct task_struct *task = NULL; perfmon_req_t tmp; void *uaddr = NULL; - int ret = -EFAULT; + int ret; int ctx_flags; + pid_t pid; /* to go away */ if (flags) { @@ -595,48 +639,156 @@ if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; + ret = pfx_is_sane(&tmp.pfr_ctx); + if (ret < 0) return ret; + ctx_flags = tmp.pfr_ctx.flags; - /* not yet supported */ - if (ctx_flags & PFM_FL_SYSTEMWIDE) return -EINVAL; + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { + /* + * XXX: This is not AT ALL SMP safe + */ + if (pfs_info.pfs_proc_sessions > 0) return -EBUSY; + if (pfs_info.pfs_sys_session > 0) return -EBUSY; + + pfs_info.pfs_sys_session = 1; - if (!pfx_is_sane(&tmp.pfr_ctx)) return -EINVAL; + } else if (pfs_info.pfs_sys_session >0) { + /* no per-process monitoring while there is a system wide session */ + return -EBUSY; + } else + pfs_info.pfs_proc_sessions++; ctx = pfm_context_alloc(); - if (!ctx) return -ENOMEM; + if (!ctx) goto error; + + /* record the creator (debug only) */ + ctx->ctx_creator = current; + + pid = tmp.pfr_ctx.notify_pid; + + spin_lock_init(&ctx->ctx_notify_lock); + + if (pid == current->pid) { + ctx->ctx_notify_task = task = current; + current->thread.pfm_context = ctx; + + atomic_set(¤t->thread.pfm_notifiers_check, 1); + + } else if (pid!=0) { + read_lock(&tasklist_lock); + + task = find_task_by_pid(pid); + if (task) { + /* + * record who to notify + */ + ctx->ctx_notify_task = task; + + /* + * make visible + * must be done inside critical section + * + * if the initialization does not go through it is still + * okay because child will do the scan for nothing which + * won't hurt. + */ + current->thread.pfm_context = ctx; + + /* + * will cause task to check on exit for monitored + * processes that would notify it. see release_thread() + * Note: the scan MUST be done in release thread, once the + * task has been detached from the tasklist otherwise you are + * exposed to race conditions. + */ + atomic_add(1, &task->thread.pfm_notifiers_check); + } + read_unlock(&tasklist_lock); + } - /* record who the creator is (for debug) */ - ctx->ctx_creator = task->pid; + /* + * notification process does not exist + */ + if (pid != 0 && task == NULL) { + ret = -EINVAL; + goto buffer_error; + } - ctx->ctx_notify_pid = tmp.pfr_ctx.notify_pid; ctx->ctx_notify_sig = SIGPROF; /* siginfo imposes a fixed signal */ if (tmp.pfr_ctx.smpl_entries) { DBprintk((" sampling entries=%ld\n",tmp.pfr_ctx.smpl_entries)); - if ((ret=pfm_smpl_buffer_alloc(ctx, tmp.pfr_ctx.smpl_regs, tmp.pfr_ctx.smpl_entries, &uaddr)) ) goto buffer_error; + + ret = pfm_smpl_buffer_alloc(ctx, tmp.pfr_ctx.smpl_regs, + tmp.pfr_ctx.smpl_entries, &uaddr); + if (ret<0) goto buffer_error; + tmp.pfr_ctx.smpl_vaddr = uaddr; } /* initialization of context's flags */ - ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK; - ctx->ctx_fl_noblock = (ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) ? 1 : 0; - ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEMWIDE) ? 1: 0; - ctx->ctx_fl_frozen = 0; + ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK; + ctx->ctx_fl_noblock = (ctx_flags & PFM_FL_SMPL_OVFL_NOBLOCK) ? 1 : 0; + ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; + ctx->ctx_fl_exclintr = (ctx_flags & PFM_FL_EXCL_INTR) ? 1: 0; + ctx->ctx_fl_frozen = 0; + + /* + * Keep track of the pmds we want to sample + * XXX: may be we don't need to save/restore the DEAR/IEAR pmds + * but we do need the BTB for sure. This is because of a hardware + * buffer of 1 only for non-BTB pmds. + */ + ctx->ctx_used_pmds[0] = tmp.pfr_ctx.smpl_regs; + ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */ sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */ - if (copy_to_user(req, &tmp, sizeof(tmp))) goto buffer_error; - DBprintk((" context=%p, pid=%d notify_sig %d notify_pid=%d\n",(void *)ctx, task->pid, ctx->ctx_notify_sig, ctx->ctx_notify_pid)); - DBprintk((" context=%p, pid=%d flags=0x%x inherit=%d noblock=%d system=%d\n",(void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, ctx->ctx_fl_noblock, ctx->ctx_fl_system)); + if (copy_to_user(req, &tmp, sizeof(tmp))) { + ret = -EFAULT; + goto buffer_error; + } + + DBprintk((" context=%p, pid=%d notify_sig %d notify_task=%p\n",(void *)ctx, current->pid, ctx->ctx_notify_sig, ctx->ctx_notify_task)); + DBprintk((" context=%p, pid=%d flags=0x%x inherit=%d noblock=%d system=%d\n",(void *)ctx, current->pid, ctx_flags, ctx->ctx_fl_inherit, ctx->ctx_fl_noblock, ctx->ctx_fl_system)); + + /* + * when no notification is required, we can make this visible at the last moment + */ + if (pid == 0) current->thread.pfm_context = ctx; + + /* + * by default, we always include interrupts for system wide + * DCR.pp is set by default to zero by kernel in cpu_init() + */ + if (ctx->ctx_fl_system) { + if (ctx->ctx_fl_exclintr == 0) { + unsigned long dcr = ia64_get_dcr(); + + ia64_set_dcr(dcr|IA64_DCR_PP); + /* + * keep track of the kernel default value + */ + pfs_info.pfs_dfl_dcr = dcr; - /* link with task */ - task->thread.pfm_context = ctx; + DBprintk((" dcr.pp is set\n")); + } + } return 0; buffer_error: - vfree(ctx); - + pfm_context_free(ctx); +error: + /* + * undo session reservation + */ + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { + pfs_info.pfs_sys_session = 0; + } else { + pfs_info.pfs_proc_sessions--; + } return ret; } @@ -656,8 +808,20 @@ /* upper part is ignored on rval */ ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval); + + /* + * we must reset BTB index (clears pmd16.full to make + * sure we do not report the same branches twice. + * The non-blocking case in handled in update_counters() + */ + if (cnum == ctx->ctx_btb_counter) { + DBprintk(("reseting PMD16\n")); + ia64_set_pmd(16, 0); + } } } + /* just in case ! */ + ctx->ctx_ovfl_regs = 0; } static int @@ -695,20 +859,23 @@ } else if (PMC_IS_BTB(&tmp.pfr_reg.reg_value)) { ctx->ctx_btb_counter = cnum; } - +#if 0 if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY) ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY; +#endif } - + /* keep track of what we use */ + CTX_USED_PMC(ctx, cnum); ia64_set_pmc(cnum, tmp.pfr_reg.reg_value); - DBprintk((" setting PMC[%ld]=0x%lx flags=0x%x\n", cnum, tmp.pfr_reg.reg_value, ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags)); + + DBprintk((" setting PMC[%ld]=0x%lx flags=0x%x used_pmcs=0%lx\n", cnum, tmp.pfr_reg.reg_value, ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags, ctx->ctx_used_pmcs[0])); } /* * we have to set this here event hough we haven't necessarily started monitoring * because we may be context switched out */ - th->flags |= IA64_THREAD_PM_VALID; + if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; return 0; } @@ -741,25 +908,32 @@ ctx->ctx_pmds[k].val = tmp.pfr_reg.reg_value & ~pmu_conf.perf_ovfl_val; ctx->ctx_pmds[k].smpl_rval = tmp.pfr_reg.reg_smpl_reset; ctx->ctx_pmds[k].ovfl_rval = tmp.pfr_reg.reg_ovfl_reset; + + if (tmp.pfr_reg.reg_flags & PFM_REGFL_OVFL_NOTIFY) + ctx->ctx_pmds[cnum - PMU_FIRST_COUNTER].flags |= PFM_REGFL_OVFL_NOTIFY; } + /* keep track of what we use */ + CTX_USED_PMD(ctx, cnum); /* writes to unimplemented part is ignored, so this is safe */ ia64_set_pmd(cnum, tmp.pfr_reg.reg_value); /* to go away */ ia64_srlz_d(); - DBprintk((" setting PMD[%ld]: pmd.val=0x%lx pmd.ovfl_rval=0x%lx pmd.smpl_rval=0x%lx pmd=%lx\n", + DBprintk((" setting PMD[%ld]: ovfl_notify=%d pmd.val=0x%lx pmd.ovfl_rval=0x%lx pmd.smpl_rval=0x%lx pmd=%lx used_pmds=0%lx\n", cnum, + PMD_OVFL_NOTIFY(ctx, cnum - PMU_FIRST_COUNTER), ctx->ctx_pmds[k].val, ctx->ctx_pmds[k].ovfl_rval, ctx->ctx_pmds[k].smpl_rval, - ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val)); + ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val, + ctx->ctx_used_pmds[0])); } /* * we have to set this here event hough we haven't necessarily started monitoring * because we may be context switched out */ - th->flags |= IA64_THREAD_PM_VALID; + if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; return 0; } @@ -783,6 +957,8 @@ /* XXX: ctx locking may be required here */ for (i = 0; i < count; i++, req++) { + unsigned long reg_val = ~0, ctx_val = ~0; + if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; if (!PMD_IS_IMPL(tmp.pfr_reg.reg_num)) return -EINVAL; @@ -791,23 +967,25 @@ if (ta == current){ val = ia64_get_pmd(tmp.pfr_reg.reg_num); } else { - val = th->pmd[tmp.pfr_reg.reg_num]; + val = reg_val = th->pmd[tmp.pfr_reg.reg_num]; } val &= pmu_conf.perf_ovfl_val; /* * lower part of .val may not be zero, so we must be an addition because of * residual count (see update_counters). */ - val += ctx->ctx_pmds[tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER].val; + val += ctx_val = ctx->ctx_pmds[tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER].val; } else { /* for now */ if (ta != current) return -EINVAL; + ia64_srlz_d(); val = ia64_get_pmd(tmp.pfr_reg.reg_num); } tmp.pfr_reg.reg_value = val; - DBprintk((" reading PMD[%ld]=0x%lx\n", tmp.pfr_reg.reg_num, val)); + DBprintk((" reading PMD[%ld]=0x%lx reg=0x%lx ctx_val=0x%lx pmc=0x%lx\n", + tmp.pfr_reg.reg_num, val, reg_val, ctx_val, ia64_get_pmc(tmp.pfr_reg.reg_num))); if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; } @@ -822,7 +1000,7 @@ void *sem = &ctx->ctx_restart_sem; if (task == current) { - DBprintk((" restartig self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen)); + DBprintk((" restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen)); pfm_reset_regs(ctx); @@ -871,6 +1049,23 @@ return 0; } +/* + * system-wide mode: propagate activation/desactivation throughout the tasklist + * + * XXX: does not work for SMP, of course + */ +static void +pfm_process_tasklist(int cmd) +{ + struct task_struct *p; + struct pt_regs *regs; + + for_each_task(p) { + regs = (struct pt_regs *)((unsigned long)p + IA64_STK_OFFSET); + regs--; + ia64_psr(regs)->pp = cmd; + } +} static int do_perfmonctl (struct task_struct *task, int cmd, int flags, perfmon_req_t *req, int count, struct pt_regs *regs) @@ -881,19 +1076,26 @@ memset(&tmp, 0, sizeof(tmp)); + if (ctx == NULL && cmd != PFM_CREATE_CONTEXT && cmd < PFM_DEBUG_BASE) { + DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid)); + return -EINVAL; + } + switch (cmd) { case PFM_CREATE_CONTEXT: /* a context has already been defined */ if (ctx) return -EBUSY; - /* may be a temporary limitation */ + /* + * cannot directly create a context in another process + */ if (task != current) return -EINVAL; if (req == NULL || count != 1) return -EINVAL; if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - return pfm_context_create(task, flags, req); + return pfm_context_create(flags, req); case PFM_WRITE_PMCS: /* we don't quite support this right now */ @@ -901,10 +1103,6 @@ if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - if (!ctx) { - DBprintk((" PFM_WRITE_PMCS: no context for task %d\n", task->pid)); - return -EINVAL; - } return pfm_write_pmcs(task, req, count); case PFM_WRITE_PMDS: @@ -913,45 +1111,41 @@ if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - if (!ctx) { - DBprintk((" PFM_WRITE_PMDS: no context for task %d\n", task->pid)); - return -EINVAL; - } return pfm_write_pmds(task, req, count); case PFM_START: /* we don't quite support this right now */ if (task != current) return -EINVAL; - if (!ctx) { - DBprintk((" PFM_START: no context for task %d\n", task->pid)); - return -EINVAL; - } + if (PMU_OWNER() && PMU_OWNER() != current && PFM_CAN_DO_LAZY()) pfm_lazy_save_regs(PMU_OWNER()); SET_PMU_OWNER(current); /* will start monitoring right after rfi */ ia64_psr(regs)->up = 1; + ia64_psr(regs)->pp = 1; + + if (ctx->ctx_fl_system) { + pfm_process_tasklist(1); + pfs_info.pfs_pp = 1; + } /* * mark the state as valid. * this will trigger save/restore at context switch */ - th->flags |= IA64_THREAD_PM_VALID; + if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; ia64_set_pmc(0, 0); ia64_srlz_d(); - break; + break; case PFM_ENABLE: /* we don't quite support this right now */ if (task != current) return -EINVAL; - if (!ctx) { - DBprintk((" PFM_ENABLE: no context for task %d\n", task->pid)); - return -EINVAL; - } + if (PMU_OWNER() && PMU_OWNER() != current && PFM_CAN_DO_LAZY()) pfm_lazy_save_regs(PMU_OWNER()); /* reset all registers to stable quiet state */ ia64_reset_pmu(); @@ -969,7 +1163,7 @@ * mark the state as valid. * this will trigger save/restore at context switch */ - th->flags |= IA64_THREAD_PM_VALID; + if (ctx->ctx_fl_system==0) th->flags |= IA64_THREAD_PM_VALID; /* simply unfreeze */ ia64_set_pmc(0, 0); @@ -983,54 +1177,41 @@ /* simply freeze */ ia64_set_pmc(0, 1); ia64_srlz_d(); + /* + * XXX: cannot really toggle IA64_THREAD_PM_VALID + * but context is still considered valid, so any + * read request would return something valid. Same + * thing when this task terminates (pfm_flush_regs()). + */ break; case PFM_READ_PMDS: if (!access_ok(VERIFY_READ, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; if (!access_ok(VERIFY_WRITE, req, sizeof(struct perfmon_req_t)*count)) return -EFAULT; - if (!ctx) { - DBprintk((" PFM_READ_PMDS: no context for task %d\n", task->pid)); - return -EINVAL; - } return pfm_read_pmds(task, req, count); case PFM_STOP: /* we don't quite support this right now */ if (task != current) return -EINVAL; - ia64_set_pmc(0, 1); - ia64_srlz_d(); - + /* simply stop monitors, not PMU */ ia64_psr(regs)->up = 0; + ia64_psr(regs)->pp = 0; - th->flags &= ~IA64_THREAD_PM_VALID; - - SET_PMU_OWNER(NULL); - - /* we probably will need some more cleanup here */ - break; - - case PFM_DEBUG_ON: - printk(" debugging on\n"); - pfm_debug = 1; - break; + if (ctx->ctx_fl_system) { + pfm_process_tasklist(0); + pfs_info.pfs_pp = 0; + } - case PFM_DEBUG_OFF: - printk(" debugging off\n"); - pfm_debug = 0; break; case PFM_RESTART: /* temporary, will most likely end up as a PFM_ENABLE */ - if ((th->flags & IA64_THREAD_PM_VALID) == 0) { + if ((th->flags & IA64_THREAD_PM_VALID) == 0 && ctx->ctx_fl_system==0) { printk(" PFM_RESTART not monitoring\n"); return -EINVAL; } - if (!ctx) { - printk(" PFM_RESTART no ctx for %d\n", task->pid); - return -EINVAL; - } if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_fl_frozen==0) { printk("task %d without pmu_frozen set\n", task->pid); return -EINVAL; @@ -1038,6 +1219,37 @@ return pfm_do_restart(task); /* we only look at first entry */ + case PFM_DESTROY_CONTEXT: + /* we don't quite support this right now */ + if (task != current) return -EINVAL; + + /* first stop monitors */ + ia64_psr(regs)->up = 0; + ia64_psr(regs)->pp = 0; + + /* then freeze PMU */ + ia64_set_pmc(0, 1); + ia64_srlz_d(); + + /* don't save/restore on context switch */ + if (ctx->ctx_fl_system ==0) task->thread.flags &= ~IA64_THREAD_PM_VALID; + + SET_PMU_OWNER(NULL); + + /* now free context and related state */ + pfm_context_exit(task); + break; + + case PFM_DEBUG_ON: + printk("perfmon debugging on\n"); + pfm_debug = 1; + break; + + case PFM_DEBUG_OFF: + printk("perfmon debugging off\n"); + pfm_debug = 0; + break; + default: DBprintk((" UNknown command 0x%x\n", cmd)); return -EINVAL; @@ -1074,11 +1286,8 @@ /* XXX: pid interface is going away in favor of pfm context */ if (pid != current->pid) { read_lock(&tasklist_lock); - { - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - } + + child = find_task_by_pid(pid); if (!child) goto abort_call; @@ -1101,93 +1310,44 @@ return ret; } - -/* - * This function is invoked on the exit path of the kernel. Therefore it must make sure - * it does does modify the caller's input registers (in0-in7) in case of entry by system call - * which can be restarted. That's why it's declared as a system call and all 8 possible args - * are declared even though not used. - */ #if __GNUC__ >= 3 void asmlinkage -pfm_overflow_notify(void) +pfm_block_on_overflow(void) #else void asmlinkage -pfm_overflow_notify(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7) +pfm_block_on_overflow(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7) #endif { - struct task_struct *task; struct thread_struct *th = ¤t->thread; pfm_context_t *ctx = current->thread.pfm_context; - struct siginfo si; int ret; /* - * do some sanity checks first - */ - if (!ctx) { - printk("perfmon: process %d has no PFM context\n", current->pid); - return; - } - if (ctx->ctx_notify_pid < 2) { - printk("perfmon: process %d invalid notify_pid=%d\n", current->pid, ctx->ctx_notify_pid); - return; - } - - DBprintk((" current=%d ctx=%p bv=0%lx\n", current->pid, (void *)ctx, ctx->ctx_ovfl_regs)); - /* * NO matter what notify_pid is, * we clear overflow, won't notify again */ - th->pfm_pend_notify = 0; + th->pfm_must_block = 0; /* - * When measuring in kernel mode and non-blocking fashion, it is possible to - * get an overflow while executing this code. Therefore the state of pend_notify - * and ovfl_regs can be altered. The important point is not to loose any notification. - * It is fine to get called for nothing. To make sure we do collect as much state as - * possible, update_counters() always uses |= to add bit to the ovfl_regs field. - * - * In certain cases, it is possible to come here, with ovfl_regs == 0; - * - * XXX: pend_notify and ovfl_regs could be merged maybe ! + * do some sanity checks first */ - if (ctx->ctx_ovfl_regs == 0) { - printk("perfmon: spurious overflow notification from pid %d\n", current->pid); + if (!ctx) { + printk("perfmon: process %d has no PFM context\n", current->pid); return; } - read_lock(&tasklist_lock); - - task = find_task_by_pid(ctx->ctx_notify_pid); - - if (task) { - si.si_signo = ctx->ctx_notify_sig; - si.si_errno = 0; - si.si_code = PROF_OVFL; /* goes to user */ - si.si_addr = NULL; - si.si_pid = current->pid; /* who is sending */ - si.si_pfm_ovfl = ctx->ctx_ovfl_regs; - - DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task)); - - /* must be done with tasklist_lock locked */ - ret = send_sig_info(ctx->ctx_notify_sig, &si, task); - if (ret != 0) { - DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", ctx->ctx_notify_pid, ret)); - task = NULL; /* will cause return */ - } - } else { - printk("perfmon: notify_pid %d not found\n", ctx->ctx_notify_pid); + if (ctx->ctx_notify_task == 0) { + printk("perfmon: process %d has no task to notify\n", current->pid); + return; } - read_unlock(&tasklist_lock); + DBprintk((" current=%d task=%d\n", current->pid, ctx->ctx_notify_task->pid)); - /* now that we have released the lock handle error condition */ - if (!task || CTX_OVFL_NOBLOCK(ctx)) { - /* we clear all pending overflow bits in noblock mode */ - ctx->ctx_ovfl_regs = 0; + /* should not happen */ + if (CTX_OVFL_NOBLOCK(ctx)) { + printk("perfmon: process %d non-blocking ctx should not be here\n", current->pid); return; } + DBprintk((" CPU%d %d before sleep\n", smp_processor_id(), current->pid)); /* @@ -1211,9 +1371,6 @@ pfm_reset_regs(ctx); - /* now we can clear this mask */ - ctx->ctx_ovfl_regs = 0; - /* * Unlock sampling buffer and reset index atomically * XXX: not really needed when blocking @@ -1232,84 +1389,14 @@ } } -static void -perfmon_softint(unsigned long ignored) -{ - notification_info_t *info; - int my_cpu = smp_processor_id(); - struct task_struct *task; - struct siginfo si; - - info = notify_info+my_cpu; - - DBprintk((" CPU%d current=%d to_pid=%d from_pid=%d bv=0x%lx\n", \ - smp_processor_id(), current->pid, info->to_pid, info->from_pid, info->bitvect)); - - /* assumption check */ - if (info->from_pid == info->to_pid) { - DBprintk((" Tasklet assumption error: from=%d tor=%d\n", info->from_pid, info->to_pid)); - return; - } - - if (notification_is_invalid(info)) { - DBprintk((" invalid notification information\n")); - return; - } - - /* sanity check */ - if (info->to_pid == 1) { - DBprintk((" cannot notify init\n")); - return; - } - /* - * XXX: needs way more checks here to make sure we send to a task we have control over - */ - read_lock(&tasklist_lock); - - task = find_task_by_pid(info->to_pid); - - DBprintk((" after find %p\n", (void *)task)); - - if (task) { - int ret; - - si.si_signo = SIGPROF; - si.si_errno = 0; - si.si_code = PROF_OVFL; /* goes to user */ - si.si_addr = NULL; - si.si_pid = info->from_pid; /* who is sending */ - si.si_pfm_ovfl = info->bitvect; - - DBprintk((" SIGPROF to %d @ %p\n", task->pid, (void *)task)); - - /* must be done with tasklist_lock locked */ - ret = send_sig_info(SIGPROF, &si, task); - if (ret != 0) - DBprintk((" send_sig_info(process %d, SIGPROF)=%d\n", info->to_pid, ret)); - - /* invalidate notification */ - info->to_pid = info->from_pid = 0; - info->bitvect = 0; - } - - read_unlock(&tasklist_lock); - - DBprintk((" after unlock %p\n", (void *)task)); - - if (!task) { - printk("perfmon: CPU%d cannot find process %d\n", smp_processor_id(), info->to_pid); - } -} - /* * main overflow processing routine. * it can be called from the interrupt path or explicitely during the context switch code * Return: - * 0 : do not unfreeze the PMU - * 1 : PMU can be unfrozen + * new value of pmc[0]. if 0x0 then unfreeze, else keep frozen */ -static unsigned long -update_counters (struct task_struct *ta, u64 pmc0, struct pt_regs *regs) +unsigned long +update_counters (struct task_struct *task, u64 pmc0, struct pt_regs *regs) { unsigned long mask, i, cnum; struct thread_struct *th; @@ -1317,7 +1404,9 @@ unsigned long bv = 0; int my_cpu = smp_processor_id(); int ret = 1, buffer_is_full = 0; - int ovfl_is_smpl, can_notify, need_reset_pmd16=0; + int ovfl_has_long_recovery, can_notify, need_reset_pmd16=0; + struct siginfo si; + /* * It is never safe to access the task for which the overflow interrupt is destinated * using the current variable as the interrupt may occur in the middle of a context switch @@ -1331,23 +1420,23 @@ * valid one, i.e. the one that caused the interrupt. */ - if (ta == NULL) { + if (task == NULL) { DBprintk((" owners[%d]=NULL\n", my_cpu)); return 0x1; } - th = &ta->thread; + th = &task->thread; ctx = th->pfm_context; /* * XXX: debug test * Don't think this could happen given upfront tests */ - if ((th->flags & IA64_THREAD_PM_VALID) == 0) { - printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", ta->pid); + if ((th->flags & IA64_THREAD_PM_VALID) == 0 && ctx->ctx_fl_system == 0) { + printk("perfmon: Spurious overflow interrupt: process %d not using perfmon\n", task->pid); return 0x1; } if (!ctx) { - printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", ta->pid); + printk("perfmon: Spurious overflow interrupt: process %d has no PFM context\n", task->pid); return 0; } @@ -1355,16 +1444,21 @@ * sanity test. Should never happen */ if ((pmc0 & 0x1 )== 0) { - printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", ta->pid, pmc0); + printk("perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", task->pid, pmc0); return 0x0; } mask = pmc0 >> PMU_FIRST_COUNTER; - DBprintk(("pmc0=0x%lx pid=%d\n", pmc0, ta->pid)); - - DBprintk(("ctx is in %s mode\n", CTX_OVFL_NOBLOCK(ctx) ? "NO-BLOCK" : "BLOCK")); + DBprintk(("pmc0=0x%lx pid=%d owner=%d iip=0x%lx, ctx is in %s mode used_pmds=0x%lx used_pmcs=0x%lx\n", + pmc0, task->pid, PMU_OWNER()->pid, regs->cr_iip, + CTX_OVFL_NOBLOCK(ctx) ? "NO-BLOCK" : "BLOCK", + ctx->ctx_used_pmds[0], + ctx->ctx_used_pmcs[0])); + /* + * XXX: need to record sample only when an EAR/BTB has overflowed + */ if (CTX_HAS_SMPL(ctx)) { pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf; unsigned long *e, m, idx=0; @@ -1372,11 +1466,15 @@ int j; idx = ia64_fetch_and_add(1, &psb->psb_index); - DBprintk((" trying to record index=%ld entries=%ld\n", idx, psb->psb_entries)); + DBprintk((" recording index=%ld entries=%ld\n", idx, psb->psb_entries)); /* * XXX: there is a small chance that we could run out on index before resetting * but index is unsigned long, so it will take some time..... + * We use > instead of == because fetch_and_add() is off by one (see below) + * + * This case can happen in non-blocking mode or with multiple processes. + * For non-blocking, we need to reload and continue. */ if (idx > psb->psb_entries) { buffer_is_full = 1; @@ -1388,7 +1486,7 @@ h = (perfmon_smpl_entry_t *)(((char *)psb->psb_addr) + idx*(psb->psb_entry_size)); - h->pid = ta->pid; + h->pid = task->pid; h->cpu = my_cpu; h->rate = 0; h->ip = regs ? regs->cr_iip : 0x0; /* where did the fault happened */ @@ -1398,6 +1496,7 @@ h->stamp = perfmon_get_stamp(); e = (unsigned long *)(h+1); + /* * selectively store PMDs in increasing index number */ @@ -1406,35 +1505,66 @@ if (PMD_IS_COUNTER(j)) *e = ctx->ctx_pmds[j-PMU_FIRST_COUNTER].val + (ia64_get_pmd(j) & pmu_conf.perf_ovfl_val); - else + else { *e = ia64_get_pmd(j); /* slow */ + } DBprintk((" e=%p pmd%d =0x%lx\n", (void *)e, j, *e)); e++; } } - /* make the new entry visible to user, needs to be atomic */ + /* + * make the new entry visible to user, needs to be atomic + */ ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count); DBprintk((" index=%ld entries=%ld hdr_count=%ld\n", idx, psb->psb_entries, psb->psb_hdr->hdr_count)); - - /* sampling buffer full ? */ + /* + * sampling buffer full ? + */ if (idx == (psb->psb_entries-1)) { - bv = mask; + /* + * will cause notification, cannot be 0 + */ + bv = mask << PMU_FIRST_COUNTER; + buffer_is_full = 1; DBprintk((" sampling buffer full must notify bv=0x%lx\n", bv)); - if (!CTX_OVFL_NOBLOCK(ctx)) goto buffer_full; + /* + * we do not reload here, when context is blocking + */ + if (!CTX_OVFL_NOBLOCK(ctx)) goto no_reload; + /* * here, we have a full buffer but we are in non-blocking mode - * so we need to reloads overflowed PMDs with sampling reset values - * and restart + * so we need to reload overflowed PMDs with sampling reset values + * and restart right away. */ } + /* FALL THROUGH */ } reload_pmds: - ovfl_is_smpl = CTX_OVFL_NOBLOCK(ctx) && buffer_is_full; - can_notify = CTX_HAS_SMPL(ctx) == 0 && ctx->ctx_notify_pid; + + /* + * in the case of a non-blocking context, we reload + * with the ovfl_rval when no user notification is taking place (short recovery) + * otherwise when the buffer is full which requires user interaction) then we use + * smpl_rval which is the long_recovery path (disturbance introduce by user execution). + * + * XXX: implies that when buffer is full then there is always notification. + */ + ovfl_has_long_recovery = CTX_OVFL_NOBLOCK(ctx) && buffer_is_full; + + /* + * XXX: CTX_HAS_SMPL() should really be something like CTX_HAS_SMPL() and is activated,i.e., + * one of the PMC is configured for EAR/BTB. + * + * When sampling, we can only notify when the sampling buffer is full. + */ + can_notify = CTX_HAS_SMPL(ctx) == 0 && ctx->ctx_notify_task; + + DBprintk((" ovfl_has_long_recovery=%d can_notify=%d\n", ovfl_has_long_recovery, can_notify)); for (i = 0, cnum = PMU_FIRST_COUNTER; mask ; cnum++, i++, mask >>= 1) { @@ -1456,7 +1586,7 @@ DBprintk((" pmod[%ld].val=0x%lx pmd=0x%lx\n", i, ctx->ctx_pmds[i].val, ia64_get_pmd(cnum)&pmu_conf.perf_ovfl_val)); if (can_notify && PMD_OVFL_NOTIFY(ctx, i)) { - DBprintk((" CPU%d should notify process %d with signal %d\n", my_cpu, ctx->ctx_notify_pid, ctx->ctx_notify_sig)); + DBprintk((" CPU%d should notify task %p with signal %d\n", my_cpu, ctx->ctx_notify_task, ctx->ctx_notify_sig)); bv |= 1 << i; } else { DBprintk((" CPU%d PMD[%ld] overflow, no notification\n", my_cpu, cnum)); @@ -1467,93 +1597,150 @@ */ /* writes to upper part are ignored, so this is safe */ - if (ovfl_is_smpl) { - DBprintk((" CPU%d PMD[%ld] reloaded with smpl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); + if (ovfl_has_long_recovery) { + DBprintk((" CPU%d PMD[%ld] reload with smpl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); ia64_set_pmd(cnum, ctx->ctx_pmds[i].smpl_rval); } else { - DBprintk((" CPU%d PMD[%ld] reloaded with ovfl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); + DBprintk((" CPU%d PMD[%ld] reload with ovfl_val=%lx\n", my_cpu, cnum,ctx->ctx_pmds[i].smpl_rval)); ia64_set_pmd(cnum, ctx->ctx_pmds[i].ovfl_rval); } } if (cnum == ctx->ctx_btb_counter) need_reset_pmd16=1; } /* - * In case of BTB, overflow - * we need to reset the BTB index. + * In case of BTB overflow we need to reset the BTB index. */ if (need_reset_pmd16) { DBprintk(("reset PMD16\n")); ia64_set_pmd(16, 0); } -buffer_full: - /* see pfm_overflow_notify() on details for why we use |= here */ - ctx->ctx_ovfl_regs |= bv; - /* nobody to notify, return and unfreeze */ +no_reload: + + /* + * some counters overflowed, but they did not require + * user notification, so after having reloaded them above + * we simply restart + */ if (!bv) return 0x0; + ctx->ctx_ovfl_regs = bv; /* keep track of what to reset when unblocking */ + /* + * Now we know that: + * - we have some counters which overflowed (contains in bv) + * - someone has asked to be notified on overflow. + */ + + + /* + * If the notification task is still present, then notify_task is non + * null. It is clean by that task if it ever exits before we do. + */ - if (ctx->ctx_notify_pid == ta->pid) { - struct siginfo si; + if (ctx->ctx_notify_task) { si.si_errno = 0; si.si_addr = NULL; - si.si_pid = ta->pid; /* who is sending */ - + si.si_pid = task->pid; /* who is sending */ si.si_signo = ctx->ctx_notify_sig; /* is SIGPROF */ si.si_code = PROF_OVFL; /* goes to user */ si.si_pfm_ovfl = bv; + /* - * in this case, we don't stop the task, we let it go on. It will - * necessarily go to the signal handler (if any) when it goes back to - * user mode. + * when the target of the signal is not ourself, we have to be more + * careful. The notify_task may being cleared by the target task itself + * in release_thread(). We must ensure mutual exclusion here such that + * the signal is delivered (even to a dying task) safely. */ - DBprintk((" sending %d notification to self %d\n", si.si_signo, ta->pid)); - - /* this call is safe in an interrupt handler */ - ret = send_sig_info(ctx->ctx_notify_sig, &si, ta); - if (ret != 0) - printk(" send_sig_info(process %d, SIGPROF)=%d\n", ta->pid, ret); - /* - * no matter if we block or not, we keep PMU frozen and do not unfreeze on ctxsw - */ - ctx->ctx_fl_frozen = 1; + if (ctx->ctx_notify_task != current) { + /* + * grab the notification lock for this task + */ + spin_lock(&ctx->ctx_notify_lock); - } else { -#if 0 /* - * The tasklet is guaranteed to be scheduled for this CPU only + * now notify_task cannot be modified until we're done + * if NULL, they it got modified while we were in the handler */ - notify_info[my_cpu].to_pid = ctx->notify_pid; - notify_info[my_cpu].from_pid = ta->pid; /* for debug only */ - notify_info[my_cpu].bitvect = bv; - /* tasklet is inserted and active */ - tasklet_schedule(&pfm_tasklet); -#endif + if (ctx->ctx_notify_task == NULL) { + spin_unlock(&ctx->ctx_notify_lock); + goto lost_notify; + } /* - * stored the vector of overflowed registers for use in notification - * mark that a notification/blocking is pending (arm the trap) + * required by send_sig_info() to make sure the target + * task does not disappear on us. */ - th->pfm_pend_notify = 1; + read_lock(&tasklist_lock); + } + /* + * in this case, we don't stop the task, we let it go on. It will + * necessarily go to the signal handler (if any) when it goes back to + * user mode. + */ + DBprintk((" %d sending %d notification to %d\n", task->pid, si.si_signo, ctx->ctx_notify_task->pid)); + + + /* + * this call is safe in an interrupt handler, so does read_lock() on tasklist_lock + */ + ret = send_sig_info(ctx->ctx_notify_sig, &si, ctx->ctx_notify_task); + if (ret != 0) printk(" send_sig_info(process %d, SIGPROF)=%d\n", ctx->ctx_notify_task->pid, ret); + /* + * now undo the protections in order + */ + if (ctx->ctx_notify_task != current) { + read_unlock(&tasklist_lock); + spin_unlock(&ctx->ctx_notify_lock); + } /* - * if we do block, then keep PMU frozen until restart + * if we block set the pfm_must_block bit + * when in block mode, we can effectively block only when the notified + * task is not self, otherwise we would deadlock. + * in this configuration, the notification is sent, the task will not + * block on the way back to user mode, but the PMU will be kept frozen + * until PFM_RESTART. + * Note that here there is still a race condition with notify_task + * possibly being nullified behind our back, but this is fine because + * it can only be changed to NULL which by construction, can only be + * done when notify_task != current. So if it was already different + * before, changing it to NULL will still maintain this invariant. + * Of course, when it is equal to current it cannot change at this point. */ - if (!CTX_OVFL_NOBLOCK(ctx)) ctx->ctx_fl_frozen = 1; + if (!CTX_OVFL_NOBLOCK(ctx) && ctx->ctx_notify_task != current) { + th->pfm_must_block = 1; /* will cause blocking */ + } + } else { +lost_notify: + DBprintk((" notification task has disappeared !\n")); + /* + * for a non-blocking context, we make sure we do not fall into the pfm_overflow_notify() + * trap. Also in the case of a blocking context with lost notify process, then we do not + * want to block either (even though it is interruptible). In this case, the PMU will be kept + * frozen and the process will run to completion without monitoring enabled. + * + * Of course, we cannot loose notify process when self-monitoring. + */ + th->pfm_must_block = 0; - DBprintk((" process %d notify ovfl_regs=0x%lx\n", ta->pid, bv)); } /* - * keep PMU frozen (and overflowed bits cleared) when we have to stop, - * otherwise return a resume 'value' for PMC[0] - * - * XXX: maybe that's enough to get rid of ctx_fl_frozen ? + * if we block, we keep the PMU frozen. If non-blocking we restart. + * in the case of non-blocking were the notify process is lost, we also + * restart. */ - DBprintk((" will return pmc0=0x%x\n",ctx->ctx_fl_frozen ? 0x1 : 0x0)); + if (!CTX_OVFL_NOBLOCK(ctx)) + ctx->ctx_fl_frozen = 1; + else + ctx->ctx_fl_frozen = 0; + + DBprintk((" reload pmc0=0x%x must_block=%ld\n", + ctx->ctx_fl_frozen ? 0x1 : 0x0, th->pfm_must_block)); + return ctx->ctx_fl_frozen ? 0x1 : 0x0; } @@ -1595,10 +1782,17 @@ u64 pmc0 = ia64_get_pmc(0); int i; - p += sprintf(p, "PMC[0]=%lx\nPerfmon debug: %s\n", pmc0, pfm_debug ? "On" : "Off"); + p += sprintf(p, "CPU%d.pmc[0]=%lx\nPerfmon debug: %s\n", smp_processor_id(), pmc0, pfm_debug ? "On" : "Off"); + p += sprintf(p, "proc_sessions=%lu sys_sessions=%lu\n", + pfs_info.pfs_proc_sessions, + pfs_info.pfs_sys_session); + for(i=0; i < NR_CPUS; i++) { - if (cpu_is_online(i)) - p += sprintf(p, "CPU%d.PMU %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: 0); + if (cpu_is_online(i)) { + p += sprintf(p, "CPU%d.pmu_owner: %-6d\n", + i, + pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1); + } } return p - page; } @@ -1648,8 +1842,8 @@ } pmu_conf.perf_ovfl_val = (1L << pm_info.pal_perf_mon_info_s.width) - 1; pmu_conf.max_counters = pm_info.pal_perf_mon_info_s.generic; - pmu_conf.num_pmds = find_num_pm_regs(pmu_conf.impl_regs); - pmu_conf.num_pmcs = find_num_pm_regs(&pmu_conf.impl_regs[4]); + pmu_conf.num_pmcs = find_num_pm_regs(pmu_conf.impl_regs); + pmu_conf.num_pmds = find_num_pm_regs(&pmu_conf.impl_regs[4]); printk("perfmon: %d bits counters (max value 0x%lx)\n", pm_info.pal_perf_mon_info_s.width, pmu_conf.perf_ovfl_val); printk("perfmon: %ld PMC/PMD pairs, %ld PMCs, %ld PMDs\n", pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds); @@ -1681,21 +1875,19 @@ ia64_srlz_d(); } -/* - * XXX: for system wide this function MUST never be called - */ void pfm_save_regs (struct task_struct *ta) { struct task_struct *owner; + pfm_context_t *ctx; struct thread_struct *t; u64 pmc0, psr; + unsigned long mask; int i; - if (ta == NULL) { - panic(__FUNCTION__" task is NULL\n"); - } - t = &ta->thread; + t = &ta->thread; + ctx = ta->thread.pfm_context; + /* * We must make sure that we don't loose any potential overflow * interrupt while saving PMU context. In this code, external @@ -1715,7 +1907,7 @@ * in kernel. * By now, we could still have an overflow interrupt in-flight. */ - __asm__ __volatile__ ("rum psr.up;;"::: "memory"); + __asm__ __volatile__ ("rsm psr.up|psr.pp;;"::: "memory"); /* * Mark the PMU as not owned @@ -1744,7 +1936,6 @@ * next process does not start with monitoring on if not requested */ ia64_set_pmc(0, 1); - ia64_srlz_d(); /* * Check for overflow bits and proceed manually if needed @@ -1755,94 +1946,111 @@ * next time the task exits from the kernel. */ if (pmc0 & ~0x1) { - if (owner != ta) printk(__FUNCTION__" owner=%p task=%p\n", (void *)owner, (void *)ta); - printk(__FUNCTION__" Warning: pmc[0]=0x%lx explicit call\n", pmc0); - - pmc0 = update_counters(owner, pmc0, NULL); + update_counters(owner, pmc0, NULL); /* we will save the updated version of pmc0 */ } - /* * restore PSR for context switch to save */ __asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory"); + /* + * we do not save registers if we can do lazy + */ + if (PFM_CAN_DO_LAZY()) { + SET_PMU_OWNER(owner); + return; + } /* * XXX needs further optimization. * Also must take holes into account */ - for (i=0; i< pmu_conf.num_pmds; i++) { - t->pmd[i] = ia64_get_pmd(i); + mask = ctx->ctx_used_pmds[0]; + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i); } /* skip PMC[0], we handle it separately */ - for (i=1; i< pmu_conf.num_pmcs; i++) { - t->pmc[i] = ia64_get_pmc(i); + mask = ctx->ctx_used_pmcs[0]>>1; + for (i=1; mask; i++, mask>>=1) { + if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i); } - /* * Throughout this code we could have gotten an overflow interrupt. It is transformed * into a spurious interrupt as soon as we give up pmu ownership. */ } -void -pfm_load_regs (struct task_struct *ta) +static void +pfm_lazy_save_regs (struct task_struct *ta) { - struct thread_struct *t = &ta->thread; - pfm_context_t *ctx = ta->thread.pfm_context; + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long mask; int i; + DBprintk((" on [%d] by [%d]\n", ta->pid, current->pid)); + + t = &ta->thread; + ctx = ta->thread.pfm_context; /* * XXX needs further optimization. * Also must take holes into account */ - for (i=0; i< pmu_conf.num_pmds; i++) { - ia64_set_pmd(i, t->pmd[i]); + mask = ctx->ctx_used_pmds[0]; + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i); } - - /* skip PMC[0] to avoid side effects */ - for (i=1; i< pmu_conf.num_pmcs; i++) { - ia64_set_pmc(i, t->pmc[i]); + + /* skip PMC[0], we handle it separately */ + mask = ctx->ctx_used_pmcs[0]>>1; + for (i=1; mask; i++, mask>>=1) { + if (mask & 0x1) t->pmc[i] = ia64_get_pmc(i); } + SET_PMU_OWNER(NULL); +} + +void +pfm_load_regs (struct task_struct *ta) +{ + struct thread_struct *t = &ta->thread; + pfm_context_t *ctx = ta->thread.pfm_context; + struct task_struct *owner; + unsigned long mask; + int i; + + owner = PMU_OWNER(); + if (owner == ta) goto skip_restore; + if (owner) pfm_lazy_save_regs(owner); - /* - * we first restore ownership of the PMU to the 'soon to be current' - * context. This way, if, as soon as we unfreeze the PMU at the end - * of this function, we get an interrupt, we attribute it to the correct - * task - */ SET_PMU_OWNER(ta); -#if 0 - /* - * check if we had pending overflow before context switching out - * If so, we invoke the handler manually, i.e. simulate interrupt. - * - * XXX: given that we do not use the tasklet anymore to stop, we can - * move this back to the pfm_save_regs() routine. - */ - if (t->pmc[0] & ~0x1) { - /* freeze set in pfm_save_regs() */ - DBprintk((" pmc[0]=0x%lx manual interrupt\n",t->pmc[0])); - update_counters(ta, t->pmc[0], NULL); + mask = ctx->ctx_used_pmds[0]; + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) ia64_set_pmd(i, t->pmd[i]); } -#endif + /* skip PMC[0] to avoid side effects */ + mask = ctx->ctx_used_pmcs[0]>>1; + for (i=1; mask; i++, mask>>=1) { + if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]); + } +skip_restore: /* * unfreeze only when possible */ if (ctx->ctx_fl_frozen == 0) { ia64_set_pmc(0, 0); ia64_srlz_d(); + /* place where we potentially (kernel level) start monitoring again */ } } /* * This function is called when a thread exits (from exit_thread()). - * This is a simplified pfm_save_regs() that simply flushes hthe current + * This is a simplified pfm_save_regs() that simply flushes the current * register state into the save area taking into account any pending * overflow. This time no notification is sent because the taks is dying * anyway. The inline processing of overflows avoids loosing some counts. @@ -1933,12 +2141,20 @@ /* collect latest results */ ctx->ctx_pmds[i].val += ia64_get_pmd(j) & pmu_conf.perf_ovfl_val; + /* + * now everything is in ctx_pmds[] and we need + * to clear the saved context from save_regs() such that + * pfm_read_pmds() gets the correct value + */ + ta->thread.pmd[j] = 0; + /* take care of overflow inline */ if (mask & 0x1) { ctx->ctx_pmds[i].val += 1 + pmu_conf.perf_ovfl_val; DBprintk((" PMD[%d] overflowed pmd=0x%lx pmds.val=0x%lx\n", j, ia64_get_pmd(j), ctx->ctx_pmds[i].val)); } + mask >>=1; } } @@ -1977,7 +2193,7 @@ /* clears all PMD registers */ for(i=0;i< pmu_conf.num_pmds; i++) { - if (PMD_IS_IMPL(i)) ia64_set_pmd(i,0); + if (PMD_IS_IMPL(i)) ia64_set_pmd(i,0); } ia64_srlz_d(); } @@ -1986,7 +2202,7 @@ * task is the newly created task */ int -pfm_inherit(struct task_struct *task) +pfm_inherit(struct task_struct *task, struct pt_regs *regs) { pfm_context_t *ctx = current->thread.pfm_context; pfm_context_t *nctx; @@ -1994,12 +2210,22 @@ int i, cnum; /* + * bypass completely for system wide + */ + if (pfs_info.pfs_sys_session) { + DBprintk((" enabling psr.pp for %d\n", task->pid)); + ia64_psr(regs)->pp = pfs_info.pfs_pp; + return 0; + } + + /* * takes care of easiest case first */ if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) { DBprintk((" removing PFM context for %d\n", task->pid)); task->thread.pfm_context = NULL; - task->thread.pfm_pend_notify = 0; + task->thread.pfm_must_block = 0; + atomic_set(&task->thread.pfm_notifiers_check, 0); /* copy_thread() clears IA64_THREAD_PM_VALID */ return 0; } @@ -2009,9 +2235,11 @@ /* copy content */ *nctx = *ctx; - if (ctx->ctx_fl_inherit == PFM_FL_INHERIT_ONCE) { + if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_ONCE) { nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE; + atomic_set(&task->thread.pfm_notifiers_check, 0); DBprintk((" downgrading to INHERIT_NONE for %d\n", task->pid)); + pfs_info.pfs_proc_sessions++; } /* initialize counters in new context */ @@ -2033,7 +2261,7 @@ sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */ /* clear pending notification */ - th->pfm_pend_notify = 0; + th->pfm_must_block = 0; /* link with new task */ th->pfm_context = nctx; @@ -2052,7 +2280,10 @@ return 0; } -/* called from exit_thread() */ +/* + * called from release_thread(), at this point this task is not in the + * tasklist anymore + */ void pfm_context_exit(struct task_struct *task) { @@ -2068,16 +2299,126 @@ pfm_smpl_buffer_desc_t *psb = ctx->ctx_smpl_buf; /* if only user left, then remove */ - DBprintk((" pid %d: task %d sampling psb->refcnt=%d\n", current->pid, task->pid, psb->psb_refcnt.counter)); + DBprintk((" [%d] [%d] psb->refcnt=%d\n", current->pid, task->pid, psb->psb_refcnt.counter)); if (atomic_dec_and_test(&psb->psb_refcnt) ) { rvfree(psb->psb_hdr, psb->psb_size); vfree(psb); - DBprintk((" pid %d: cleaning task %d sampling buffer\n", current->pid, task->pid )); + DBprintk((" [%d] cleaning [%d] sampling buffer\n", current->pid, task->pid )); + } + } + DBprintk((" [%d] cleaning [%d] pfm_context @%p\n", current->pid, task->pid, (void *)ctx)); + + /* + * To avoid getting the notified task scan the entire process list + * when it exits because it would have pfm_notifiers_check set, we + * decrease it by 1 to inform the task, that one less task is going + * to send it notification. each new notifer increases this field by + * 1 in pfm_context_create(). Of course, there is race condition between + * decreasing the value and the notified task exiting. The danger comes + * from the fact that we have a direct pointer to its task structure + * thereby bypassing the tasklist. We must make sure that if we have + * notify_task!= NULL, the target task is still somewhat present. It may + * already be detached from the tasklist but that's okay. Note that it is + * okay if we 'miss the deadline' and the task scans the list for nothing, + * it will affect performance but not correctness. The correctness is ensured + * by using the notify_lock whic prevents the notify_task from changing on us. + * Once holdhing this lock, if we see notify_task!= NULL, then it will stay like + * that until we release the lock. If it is NULL already then we came too late. + */ + spin_lock(&ctx->ctx_notify_lock); + + if (ctx->ctx_notify_task) { + DBprintk((" [%d] [%d] atomic_sub on [%d] notifiers=%u\n", current->pid, task->pid, + ctx->ctx_notify_task->pid, + atomic_read(&ctx->ctx_notify_task->thread.pfm_notifiers_check))); + + atomic_sub(1, &ctx->ctx_notify_task->thread.pfm_notifiers_check); + } + + spin_unlock(&ctx->ctx_notify_lock); + + if (ctx->ctx_fl_system) { + /* + * if included interrupts (true by default), then reset + * to get default value + */ + if (ctx->ctx_fl_exclintr == 0) { + /* + * reload kernel default DCR value + */ + ia64_set_dcr(pfs_info.pfs_dfl_dcr); + DBprintk((" restored dcr to 0x%lx\n", pfs_info.pfs_dfl_dcr)); } + /* + * free system wide session slot + */ + pfs_info.pfs_sys_session = 0; + } else { + pfs_info.pfs_proc_sessions--; } - DBprintk((" pid %d: task %d pfm_context is freed @%p\n", current->pid, task->pid, (void *)ctx)); + pfm_context_free(ctx); + /* + * clean pfm state in thread structure, + */ + task->thread.pfm_context = NULL; + task->thread.pfm_must_block = 0; + /* pfm_notifiers is cleaned in pfm_cleanup_notifiers() */ + +} + +void +pfm_cleanup_notifiers(struct task_struct *task) +{ + struct task_struct *p; + pfm_context_t *ctx; + + DBprintk((" [%d] called\n", task->pid)); + + read_lock(&tasklist_lock); + + for_each_task(p) { + /* + * It is safe to do the 2-step test here, because thread.ctx + * is cleaned up only in release_thread() and at that point + * the task has been detached from the tasklist which is an + * operation which uses the write_lock() on the tasklist_lock + * so it cannot run concurrently to this loop. So we have the + * guarantee that if we find p and it has a perfmon ctx then + * it is going to stay like this for the entire execution of this + * loop. + */ + ctx = p->thread.pfm_context; + + DBprintk((" [%d] scanning task [%d] ctx=%p\n", task->pid, p->pid, ctx)); + + if (ctx && ctx->ctx_notify_task == task) { + DBprintk((" trying for notifier %d in %d\n", task->pid, p->pid)); + /* + * the spinlock is required to take care of a race condition + * with the send_sig_info() call. We must make sure that + * either the send_sig_info() completes using a valid task, + * or the notify_task is cleared before the send_sig_info() + * can pick up a stale value. Note that by the time this + * function is executed the 'task' is already detached from the + * tasklist. The problem is that the notifiers have a direct + * pointer to it. It is okay to send a signal to a task in this + * stage, it simply will have no effect. But it is better than sending + * to a completely destroyed task or worse to a new task using the same + * task_struct address. + */ + spin_lock(&ctx->ctx_notify_lock); + + ctx->ctx_notify_task = NULL; + + spin_unlock(&ctx->ctx_notify_lock); + + DBprintk((" done for notifier %d in %d\n", task->pid, p->pid)); + } + } + read_unlock(&tasklist_lock); + } #else /* !CONFIG_PERFMON */ diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c --- v2.4.14/linux/arch/ia64/kernel/process.c Tue Oct 9 17:06:51 2001 +++ linux/arch/ia64/kernel/process.c Fri Nov 9 14:26:17 2001 @@ -63,7 +63,8 @@ { unsigned long ip = regs->cr_iip + ia64_psr(regs)->ri; - printk("\npsr : %016lx ifs : %016lx ip : [<%016lx>] %s\n", + printk("\nPid: %d, comm: %20s\n", current->pid, current->comm); + printk("psr : %016lx ifs : %016lx ip : [<%016lx>] %s\n", regs->cr_ipsr, regs->cr_ifs, ip, print_tainted()); printk("unat: %016lx pfs : %016lx rsc : %016lx\n", regs->ar_unat, regs->ar_pfs, regs->ar_rsc); @@ -201,7 +202,7 @@ { unsigned long rbs, child_rbs, rbs_size, stack_offset, stack_top, stack_used; struct switch_stack *child_stack, *stack; - extern char ia64_ret_from_clone; + extern char ia64_ret_from_clone, ia32_ret_from_clone; struct pt_regs *child_ptregs; int retval = 0; @@ -250,7 +251,10 @@ child_ptregs->r12 = (unsigned long) (child_ptregs + 1); /* kernel sp */ child_ptregs->r13 = (unsigned long) p; /* set `current' pointer */ } - child_stack->b0 = (unsigned long) &ia64_ret_from_clone; + if (IS_IA32_PROCESS(regs)) + child_stack->b0 = (unsigned long) &ia32_ret_from_clone; + else + child_stack->b0 = (unsigned long) &ia64_ret_from_clone; child_stack->ar_bspstore = child_rbs + rbs_size; /* copy parts of thread_struct: */ @@ -285,9 +289,8 @@ ia32_save_state(p); #endif #ifdef CONFIG_PERFMON - p->thread.pfm_pend_notify = 0; if (p->thread.pfm_context) - retval = pfm_inherit(p); + retval = pfm_inherit(p, child_ptregs); #endif return retval; } @@ -441,11 +444,24 @@ } #ifdef CONFIG_PERFMON +/* + * By the time we get here, the task is detached from the tasklist. This is important + * because it means that no other tasks can ever find it as a notifiied task, therfore + * there is no race condition between this code and let's say a pfm_context_create(). + * Conversely, the pfm_cleanup_notifiers() cannot try to access a task's pfm context if + * this other task is in the middle of its own pfm_context_exit() because it would alreayd + * be out of the task list. Note that this case is very unlikely between a direct child + * and its parents (if it is the notified process) because of the way the exit is notified + * via SIGCHLD. + */ void release_thread (struct task_struct *task) { if (task->thread.pfm_context) pfm_context_exit(task); + + if (atomic_read(&task->thread.pfm_notifiers_check) > 0) + pfm_cleanup_notifiers(task); } #endif @@ -516,6 +532,29 @@ } void +cpu_halt (void) +{ + pal_power_mgmt_info_u_t power_info[8]; + unsigned long min_power; + int i, min_power_state; + + if (ia64_pal_halt_info(power_info) != 0) + return; + + min_power_state = 0; + min_power = power_info[0].pal_power_mgmt_info_s.power_consumption; + for (i = 1; i < 8; ++i) + if (power_info[i].pal_power_mgmt_info_s.im + && power_info[i].pal_power_mgmt_info_s.power_consumption < min_power) { + min_power = power_info[i].pal_power_mgmt_info_s.power_consumption; + min_power_state = i; + } + + while (1) + ia64_pal_halt(min_power_state); +} + +void machine_restart (char *restart_cmd) { (*efi.reset_system)(EFI_RESET_WARM, 0, 0, 0); @@ -524,6 +563,7 @@ void machine_halt (void) { + cpu_halt(); } void @@ -531,4 +571,5 @@ { if (pm_power_off) pm_power_off(); + machine_halt(); } diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c --- v2.4.14/linux/arch/ia64/kernel/ptrace.c Sun Sep 23 11:40:55 2001 +++ linux/arch/ia64/kernel/ptrace.c Fri Nov 9 14:26:17 2001 @@ -2,7 +2,7 @@ * Kernel support for the ptrace() and syscall tracing interfaces. * * Copyright (C) 1999-2001 Hewlett-Packard Co - * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> * * Derived from the x86 and Alpha versions. Most of the code in here * could actually be factored into a common set of routines. @@ -794,11 +794,14 @@ * * Make sure the single step bit is not set. */ -void ptrace_disable(struct task_struct *child) +void +ptrace_disable (struct task_struct *child) { + struct ia64_psr *child_psr = ia64_psr(ia64_task_regs(child)); + /* make sure the single step/take-branch tra bits are not set: */ - ia64_psr(pt)->ss = 0; - ia64_psr(pt)->tb = 0; + child_psr->ss = 0; + child_psr->tb = 0; /* Turn off flag indicating that the KRBS is sync'd with child's VM: */ child->thread.flags &= ~IA64_THREAD_KRBS_SYNCED; @@ -809,7 +812,7 @@ long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *pt, *regs = (struct pt_regs *) &stack; - unsigned long flags, urbs_end; + unsigned long urbs_end; struct task_struct *child; struct switch_stack *sw; long ret; @@ -855,6 +858,19 @@ if (child->p_pptr != current) goto out_tsk; + if (request != PTRACE_KILL) { + if (child->state != TASK_STOPPED) + goto out_tsk; + +#ifdef CONFIG_SMP + while (child->has_cpu) { + if (child->state != TASK_STOPPED) + goto out_tsk; + barrier(); + } +#endif + } + pt = ia64_task_regs(child); sw = (struct switch_stack *) (child->thread.ksp + 16); @@ -925,7 +941,7 @@ child->ptrace &= ~PT_TRACESYS; child->exit_code = data; - /* make sure the single step/take-branch tra bits are not set: */ + /* make sure the single step/taken-branch trap bits are not set: */ ia64_psr(pt)->ss = 0; ia64_psr(pt)->tb = 0; diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/sal.c linux/arch/ia64/kernel/sal.c --- v2.4.14/linux/arch/ia64/kernel/sal.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/sal.c Fri Nov 9 14:26:17 2001 @@ -1,8 +1,8 @@ /* * System Abstraction Layer (SAL) interface routines. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> */ @@ -18,8 +18,6 @@ #include <asm/sal.h> #include <asm/pal.h> -#define SAL_DEBUG - spinlock_t sal_lock = SPIN_LOCK_UNLOCKED; static struct { @@ -122,10 +120,8 @@ switch (*p) { case SAL_DESC_ENTRY_POINT: ep = (struct ia64_sal_desc_entry_point *) p; -#ifdef SAL_DEBUG - printk("sal[%d] - entry: pal_proc=0x%lx, sal_proc=0x%lx\n", - i, ep->pal_proc, ep->sal_proc); -#endif + printk("SAL: entry: pal_proc=0x%lx, sal_proc=0x%lx\n", + ep->pal_proc, ep->sal_proc); ia64_pal_handler_init(__va(ep->pal_proc)); ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp)); break; @@ -138,17 +134,12 @@ #ifdef CONFIG_SMP { struct ia64_sal_desc_ap_wakeup *ap = (void *) p; -# ifdef SAL_DEBUG - printk("sal[%d] - wakeup type %x, 0x%lx\n", - i, ap->mechanism, ap->vector); -# endif + switch (ap->mechanism) { case IA64_SAL_AP_EXTERNAL_INT: ap_wakeup_vector = ap->vector; -# ifdef SAL_DEBUG printk("SAL: AP wakeup using external interrupt " "vector 0x%lx\n", ap_wakeup_vector); -# endif break; default: @@ -163,21 +154,13 @@ struct ia64_sal_desc_platform_feature *pf = (void *) p; printk("SAL: Platform features "); -#ifdef CONFIG_IA64_HAVE_IRQREDIR - /* - * Early versions of SAL say we don't have - * IRQ redirection, even though we do... - */ - pf->feature_mask |= (1 << 1); -#endif - if (pf->feature_mask & (1 << 0)) printk("BusLock "); if (pf->feature_mask & (1 << 1)) { printk("IRQ_Redirection "); #ifdef CONFIG_SMP - if (no_int_routing) + if (no_int_routing) smp_int_redirect &= ~SMP_IRQ_REDIRECTION; else smp_int_redirect |= SMP_IRQ_REDIRECTION; diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/setup.c linux/arch/ia64/kernel/setup.c --- v2.4.14/linux/arch/ia64/kernel/setup.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/setup.c Fri Nov 9 14:26:17 2001 @@ -534,10 +534,13 @@ /* * Initialize default control register to defer all speculative faults. The * kernel MUST NOT depend on a particular setting of these bits (in other words, - * the kernel must have recovery code for all speculative accesses). + * the kernel must have recovery code for all speculative accesses). Turn on + * dcr.lc as per recommendation by the architecture team. Most IA-32 apps + * shouldn't be affected by this (moral: keep your ia32 locks aligned and you'll + * be fine). */ ia64_set_dcr( IA64_DCR_DM | IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR - | IA64_DCR_DA | IA64_DCR_DD); + | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC); #ifndef CONFIG_SMP ia64_set_fpu_owner(0); #endif diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/sigframe.h linux/arch/ia64/kernel/sigframe.h --- v2.4.14/linux/arch/ia64/kernel/sigframe.h Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/sigframe.h Fri Nov 9 14:26:17 2001 @@ -1,3 +1,9 @@ +struct sigscratch { + unsigned long scratch_unat; /* ar.unat for the general registers saved in pt */ + unsigned long pad; + struct pt_regs pt; +}; + struct sigframe { /* * Place signal handler args where user-level unwinder can find them easily. @@ -7,10 +13,11 @@ unsigned long arg0; /* signum */ unsigned long arg1; /* siginfo pointer */ unsigned long arg2; /* sigcontext pointer */ + /* + * End of architected state. + */ - unsigned long rbs_base; /* base of new register backing store (or NULL) */ void *handler; /* pointer to the plabel of the signal handler */ - struct siginfo info; struct sigcontext sc; }; diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c --- v2.4.14/linux/arch/ia64/kernel/signal.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/signal.c Fri Nov 9 14:26:17 2001 @@ -2,7 +2,7 @@ * Architecture-specific signal handling support. * * Copyright (C) 1999-2001 Hewlett-Packard Co - * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> * * Derived from i386 and Alpha versions. */ @@ -39,12 +39,6 @@ # define GET_SIGSET(k,u) __get_user((k)->sig[0], &(u)->sig[0]) #endif -struct sigscratch { - unsigned long scratch_unat; /* ar.unat for the general registers saved in pt */ - unsigned long pad; - struct pt_regs pt; -}; - extern long ia64_do_signal (sigset_t *, struct sigscratch *, long); /* forward decl */ long @@ -55,6 +49,10 @@ /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) return -EINVAL; + + if (!access_ok(VERIFY_READ, uset, sigsetsize)) + return -EFAULT; + if (GET_SIGSET(&set, uset)) return -EFAULT; @@ -73,15 +71,9 @@ * pre-set the correct error code here to ensure that the right values * get saved in sigcontext by ia64_do_signal. */ -#ifdef CONFIG_IA32_SUPPORT - if (IS_IA32_PROCESS(&scr->pt)) { - scr->pt.r8 = -EINTR; - } else -#endif - { - scr->pt.r8 = EINTR; - scr->pt.r10 = -1; - } + scr->pt.r8 = EINTR; + scr->pt.r10 = -1; + while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); @@ -139,10 +131,9 @@ struct ia64_psr *psr = ia64_psr(&scr->pt); __copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16); - if (!psr->dfh) { - psr->mfh = 0; + psr->mfh = 0; /* drop signal handler's fph contents... */ + if (!psr->dfh) __ia64_load_fpu(current->thread.fph); - } } return err; } @@ -380,7 +371,8 @@ err = __put_user(sig, &frame->arg0); err |= __put_user(&frame->info, &frame->arg1); err |= __put_user(&frame->sc, &frame->arg2); - err |= __put_user(new_rbs, &frame->rbs_base); + err |= __put_user(new_rbs, &frame->sc.sc_rbs_base); + err |= __put_user(0, &frame->sc.sc_loadrs); /* initialize to zero */ err |= __put_user(ka->sa.sa_handler, &frame->handler); err |= copy_siginfo_to_user(&frame->info, info); @@ -460,6 +452,7 @@ long ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall) { + struct signal_struct *sig; struct k_sigaction *ka; siginfo_t info; long restart = in_syscall; @@ -571,8 +564,8 @@ case SIGSTOP: current->state = TASK_STOPPED; current->exit_code = signr; - if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags - & SA_NOCLDSTOP)) + sig = current->p_pptr->sig; + if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c --- v2.4.14/linux/arch/ia64/kernel/smp.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/smp.c Fri Nov 9 14:26:17 2001 @@ -48,6 +48,7 @@ #include <asm/sal.h> #include <asm/system.h> #include <asm/unistd.h> +#include <asm/mca.h> /* The 'big kernel lock' */ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; @@ -70,20 +71,18 @@ #define IPI_CALL_FUNC 0 #define IPI_CPU_STOP 1 -#ifndef CONFIG_ITANIUM_PTCG -# define IPI_FLUSH_TLB 2 -#endif /*!CONFIG_ITANIUM_PTCG */ static void stop_this_cpu (void) { + extern void cpu_halt (void); /* * Remove this CPU: */ clear_bit(smp_processor_id(), &cpu_online_map); max_xtp(); __cli(); - for (;;); + cpu_halt(); } void @@ -136,49 +135,6 @@ stop_this_cpu(); break; -#ifndef CONFIG_ITANIUM_PTCG - case IPI_FLUSH_TLB: - { - extern unsigned long flush_start, flush_end, flush_nbits, flush_rid; - extern atomic_t flush_cpu_count; - unsigned long saved_rid = ia64_get_rr(flush_start); - unsigned long end = flush_end; - unsigned long start = flush_start; - unsigned long nbits = flush_nbits; - - /* - * Current CPU may be running with different RID so we need to - * reload the RID of flushed address. Purging the translation - * also needs ALAT invalidation; we do not need "invala" here - * since it is done in ia64_leave_kernel. - */ - ia64_srlz_d(); - if (saved_rid != flush_rid) { - ia64_set_rr(flush_start, flush_rid); - ia64_srlz_d(); - } - - do { - /* - * Purge local TLB entries. - */ - __asm__ __volatile__ ("ptc.l %0,%1" :: - "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - - ia64_insn_group_barrier(); - ia64_srlz_i(); /* srlz.i implies srlz.d */ - - if (saved_rid != flush_rid) { - ia64_set_rr(flush_start, saved_rid); - ia64_srlz_d(); - } - atomic_dec(&flush_cpu_count); - break; - } -#endif /* !CONFIG_ITANIUM_PTCG */ - default: printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); break; @@ -228,30 +184,6 @@ platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); } -#ifndef CONFIG_ITANIUM_PTCG - -void -smp_send_flush_tlb (void) -{ - send_IPI_allbutself(IPI_FLUSH_TLB); -} - -void -smp_resend_flush_tlb (void) -{ - int i; - - /* - * Really need a null IPI but since this rarely should happen & since this code - * will go away, lets not add one. - */ - for (i = 0; i < smp_num_cpus; ++i) - if (i != smp_processor_id()) - smp_send_reschedule(i); -} - -#endif /* !CONFIG_ITANIUM_PTCG */ - void smp_flush_tlb_all (void) { @@ -277,10 +209,6 @@ { struct call_data_struct data; int cpus = 1; -#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) - unsigned long timeout; -#endif if (cpuid == smp_processor_id()) { printk(__FUNCTION__" trying to call self\n"); @@ -295,26 +223,15 @@ atomic_set(&data.finished, 0); spin_lock_bh(&call_lock); - call_data = &data; - -#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) - resend: - send_IPI_single(cpuid, IPI_CALL_FUNC); - /* Wait for response */ - timeout = jiffies + HZ; - while ((atomic_read(&data.started) != cpus) && time_before(jiffies, timeout)) - barrier(); - if (atomic_read(&data.started) != cpus) - goto resend; -#else + call_data = &data; + mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ send_IPI_single(cpuid, IPI_CALL_FUNC); /* Wait for response */ while (atomic_read(&data.started) != cpus) barrier(); -#endif + if (wait) while (atomic_read(&data.finished) != cpus) barrier(); @@ -348,10 +265,6 @@ { struct call_data_struct data; int cpus = smp_num_cpus-1; -#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) - unsigned long timeout; -#endif if (!cpus) return 0; @@ -364,27 +277,14 @@ atomic_set(&data.finished, 0); spin_lock_bh(&call_lock); - call_data = &data; - -#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) - resend: - /* Send a message to all other CPUs and wait for them to respond */ - send_IPI_allbutself(IPI_CALL_FUNC); - /* Wait for response */ - timeout = jiffies + HZ; - while ((atomic_read(&data.started) != cpus) && time_before(jiffies, timeout)) - barrier(); - if (atomic_read(&data.started) != cpus) - goto resend; -#else + call_data = &data; + mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ send_IPI_allbutself(IPI_CALL_FUNC); /* Wait for response */ while (atomic_read(&data.started) != cpus) barrier(); -#endif if (wait) while (atomic_read(&data.finished) != cpus) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/smpboot.c linux/arch/ia64/kernel/smpboot.c --- v2.4.14/linux/arch/ia64/kernel/smpboot.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/smpboot.c Fri Nov 9 14:26:17 2001 @@ -33,6 +33,7 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/machvec.h> +#include <asm/mca.h> #include <asm/page.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> @@ -42,6 +43,8 @@ #include <asm/system.h> #include <asm/unistd.h> +#define SMP_DEBUG 0 + #if SMP_DEBUG #define Dprintk(x...) printk(x) #else @@ -310,7 +313,7 @@ } -void __init +static void __init smp_callin (void) { int cpuid, phys_id; @@ -324,8 +327,7 @@ phys_id = hard_smp_processor_id(); if (test_and_set_bit(cpuid, &cpu_online_map)) { - printk("huh, phys CPU#0x%x, CPU#0x%x already present??\n", - phys_id, cpuid); + printk("huh, phys CPU#0x%x, CPU#0x%x already present??\n", phys_id, cpuid); BUG(); } @@ -341,6 +343,12 @@ * Get our bogomips. */ ia64_init_itm(); + +#ifdef CONFIG_IA64_MCA + ia64_mca_cmc_vector_setup(); /* Setup vector on AP & enable */ + ia64_mca_check_errors(); /* For post-failure MCA error logging */ +#endif + #ifdef CONFIG_PERFMON perfmon_init_percpu(); #endif @@ -364,14 +372,15 @@ { extern int cpu_idle (void); + Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id()); efi_map_pal_code(); cpu_init(); smp_callin(); - Dprintk("CPU %d is set to go. \n", smp_processor_id()); + Dprintk("CPU %d is set to go.\n", smp_processor_id()); while (!atomic_read(&smp_commenced)) ; - Dprintk("CPU %d is starting idle. \n", smp_processor_id()); + Dprintk("CPU %d is starting idle.\n", smp_processor_id()); return cpu_idle(); } @@ -415,7 +424,7 @@ unhash_process(idle); init_tasks[cpu] = idle; - Dprintk("Sending Wakeup Vector to AP 0x%x/0x%x.\n", cpu, sapicid); + Dprintk("Sending wakeup vector %u to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid); platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); @@ -424,7 +433,6 @@ */ Dprintk("Waiting on callin_map ..."); for (timeout = 0; timeout < 100000; timeout++) { - Dprintk("."); if (test_bit(cpu, &cpu_callin_map)) break; /* It has booted */ udelay(100); diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c --- v2.4.14/linux/arch/ia64/kernel/sys_ia64.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/sys_ia64.c Fri Nov 9 14:26:17 2001 @@ -19,24 +19,29 @@ #include <asm/shmparam.h> #include <asm/uaccess.h> -#define COLOR_ALIGN(addr) (((addr) + SHMLBA - 1) & ~(SHMLBA - 1)) - unsigned long arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { - struct vm_area_struct * vmm; long map_shared = (flags & MAP_SHARED); + unsigned long align_mask = PAGE_SIZE - 1; + struct vm_area_struct * vmm; if (len > RGN_MAP_LIMIT) return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - if (map_shared) - addr = COLOR_ALIGN(addr); - else - addr = PAGE_ALIGN(addr); + if (map_shared && (TASK_SIZE > 0xfffffffful)) + /* + * For 64-bit tasks, align shared segments to 1MB to avoid potential + * performance penalty due to virtual aliasing (see ASDM). For 32-bit + * tasks, we prefer to avoid exhausting the address space too quickly by + * limiting alignment to a single page. + */ + align_mask = SHMLBA - 1; + + addr = (addr + align_mask) & ~align_mask; for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { /* At this point: (!vmm || addr < vmm->vm_end). */ @@ -46,9 +51,7 @@ return -ENOMEM; if (!vmm || addr + len <= vmm->vm_start) return addr; - addr = vmm->vm_end; - if (map_shared) - addr = COLOR_ALIGN(addr); + addr = (vmm->vm_end + align_mask) & ~align_mask; } } @@ -184,8 +187,10 @@ if (!file) return -EBADF; - if (!file->f_op || !file->f_op->mmap) - return -ENODEV; + if (!file->f_op || !file->f_op->mmap) { + addr = -ENODEV; + goto out; + } } /* @@ -194,22 +199,26 @@ */ len = PAGE_ALIGN(len); if (len == 0) - return addr; + goto out; /* don't permit mappings into unmapped space or the virtual page table of a region: */ roff = rgn_offset(addr); - if ((len | roff | (roff + len)) >= RGN_MAP_LIMIT) - return -EINVAL; + if ((len | roff | (roff + len)) >= RGN_MAP_LIMIT) { + addr = -EINVAL; + goto out; + } /* don't permit mappings that would cross a region boundary: */ - if (rgn_index(addr) != rgn_index(addr + len)) - return -EINVAL; + if (rgn_index(addr) != rgn_index(addr + len)) { + addr = -EINVAL; + goto out; + } down_write(¤t->mm->mmap_sem); addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up_write(¤t->mm->mmap_sem); - if (file) +out: if (file) fput(file); return addr; } diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c --- v2.4.14/linux/arch/ia64/kernel/time.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/time.c Fri Nov 9 14:26:17 2001 @@ -145,6 +145,9 @@ tv->tv_usec = usec; } +/* XXX there should be a cleaner way for declaring an alias... */ +asm (".global get_fast_time; get_fast_time = do_gettimeofday"); + static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c --- v2.4.14/linux/arch/ia64/kernel/traps.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/traps.c Fri Nov 9 14:26:17 2001 @@ -1,20 +1,19 @@ /* * Architecture-specific trap handling. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> * * 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE */ /* - * The fpu_fault() handler needs to be able to access and update all - * floating point registers. Those saved in pt_regs can be accessed - * through that structure, but those not saved, will be accessed - * directly. To make this work, we need to ensure that the compiler - * does not end up using a preserved floating point register on its - * own. The following achieves this by declaring preserved registers - * that are not marked as "fixed" as global register variables. + * fp_emulate() needs to be able to access and update all floating point registers. Those + * saved in pt_regs can be accessed through that structure, but those not saved, will be + * accessed directly. To make this work, we need to ensure that the compiler does not end + * up using a preserved floating point register on its own. The following achieves this + * by declaring preserved registers that are not marked as "fixed" as global register + * variables. */ register double f2 asm ("f2"); register double f3 asm ("f3"); register double f4 asm ("f4"); register double f5 asm ("f5"); @@ -33,13 +32,17 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/sched.h> +#include <linux/vt_kern.h> /* For unblank_screen() */ +#include <asm/hardirq.h> #include <asm/ia32.h> #include <asm/processor.h> #include <asm/uaccess.h> #include <asm/fpswa.h> +extern spinlock_t timerlist_lock; + static fpswa_interface_t *fpswa_interface; void __init @@ -51,30 +54,74 @@ fpswa_interface = __va(ia64_boot_param->fpswa); } +/* + * Unlock any spinlocks which will prevent us from getting the message out (timerlist_lock + * is acquired through the console unblank code) + */ void -die_if_kernel (char *str, struct pt_regs *regs, long err) +bust_spinlocks (int yes) { - if (user_mode(regs)) { -#if 0 - /* XXX for debugging only */ - printk ("!!die_if_kernel: %s(%d): %s %ld\n", - current->comm, current->pid, str, err); - show_regs(regs); + spin_lock_init(&timerlist_lock); + if (yes) { + oops_in_progress = 1; +#ifdef CONFIG_SMP + global_irq_lock = 0; /* Many serial drivers do __global_cli() */ #endif - return; + } else { + int loglevel_save = console_loglevel; +#ifdef CONFIG_VT + unblank_screen(); +#endif + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() without + * oops_in_progress set so that printk will give klogd a poke. Hold onto + * your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; } +} - printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err); - - show_regs(regs); +void +die (const char *str, struct pt_regs *regs, long err) +{ + static struct { + spinlock_t lock; + int lock_owner; + int lock_owner_depth; + } die = { + lock: SPIN_LOCK_UNLOCKED, + lock_owner: -1, + lock_owner_depth: 0 + }; - if (current->thread.flags & IA64_KERNEL_DEATH) { - printk("die_if_kernel recursion detected.\n"); - sti(); - while (1); + if (die.lock_owner != smp_processor_id()) { + console_verbose(); + spin_lock_irq(&die.lock); + die.lock_owner = smp_processor_id(); + die.lock_owner_depth = 0; + bust_spinlocks(1); } - current->thread.flags |= IA64_KERNEL_DEATH; - do_exit(SIGSEGV); + + if (++die.lock_owner_depth < 3) { + printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err); + show_regs(regs); + } else + printk(KERN_ERR "Recursive die() failure, output suppressed\n"); + + bust_spinlocks(0); + die.lock_owner = -1; + spin_unlock_irq(&die.lock); + do_exit(SIGSEGV); +} + +void +die_if_kernel (char *str, struct pt_regs *regs, long err) +{ + if (!user_mode(regs)) + die(str, regs, err); } void @@ -169,14 +216,12 @@ } /* - * disabled_fph_fault() is called when a user-level process attempts - * to access one of the registers f32..f127 when it doesn't own the - * fp-high register partition. When this happens, we save the current - * fph partition in the task_struct of the fpu-owner (if necessary) - * and then load the fp-high partition of the current task (if - * necessary). Note that the kernel has access to fph by the time we - * get here, as the IVT's "Diabled FP-Register" handler takes care of - * clearing psr.dfh. + * disabled_fph_fault() is called when a user-level process attempts to access f32..f127 + * and it doesn't own the fp-high register partition. When this happens, we save the + * current fph partition in the task_struct of the fpu-owner (if necessary) and then load + * the fp-high partition of the current task (if necessary). Note that the kernel has + * access to fph by the time we get here, as the IVT's "Disabled FP-Register" handler takes + * care of clearing psr.dfh. */ static inline void disabled_fph_fault (struct pt_regs *regs) @@ -277,7 +322,7 @@ if (jiffies - last_time > 5*HZ) fpu_swa_count = 0; - if (++fpu_swa_count < 5) { + if ((++fpu_swa_count < 5) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { last_time = jiffies; printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx\n", current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri); @@ -478,12 +523,12 @@ case 32: /* fp fault */ case 33: /* fp trap */ result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr); - if (result < 0) { + if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; siginfo.si_code = FPE_FLTINV; siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); - force_sig(SIGFPE, current); + force_sig_info(SIGFPE, &siginfo, current); } return; @@ -510,6 +555,10 @@ break; case 46: +#ifdef CONFIG_IA32_SUPPORT + if (ia32_intercept(regs, isr) == 0) + return; +#endif printk("Unexpected IA-32 intercept trap (Trap 46)\n"); printk(" iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n", regs->cr_iip, ifa, isr, iim); diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/unaligned.c linux/arch/ia64/kernel/unaligned.c --- v2.4.14/linux/arch/ia64/kernel/unaligned.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/unaligned.c Fri Nov 9 14:26:17 2001 @@ -5,6 +5,8 @@ * Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> * + * 2001/10/11 Fix unaligned access to rotating registers in s/w pipelined loops. + * 2001/08/13 Correct size of extended floats (float_fsz) from 16 to 10 bytes. * 2001/01/17 Add support emulation of unaligned kernel accesses. */ #include <linux/kernel.h> @@ -282,9 +284,19 @@ unsigned long rnats, nat_mask; unsigned long on_kbs; long sof = (regs->cr_ifs) & 0x7f; + long sor = 8 * ((regs->cr_ifs >> 14) & 0xf); + long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; + long ridx; + + if ((r1 - 32) > sor) + ridx = -sof + (r1 - 32); + else if ((r1 - 32) < (sor - rrb_gr)) + ridx = -sof + (r1 - 32) + rrb_gr; + else + ridx = -sof + (r1 - 32) - (sor - rrb_gr); - DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n", - r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f); + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx); if ((r1 - 32) >= sof) { /* this should never happen, as the "rsvd register fault" has higher priority */ @@ -293,7 +305,7 @@ } on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); - addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32)); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx); if (addr >= kbs) { /* the register is on the kernel backing store: easy... */ rnat_addr = ia64_rse_rnat_addr(addr); @@ -318,12 +330,12 @@ return; } - bspstore = (unsigned long *) regs->ar_bspstore; + bspstore = (unsigned long *)regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); bsp = ia64_rse_skip_regs(ubs_end, -sof); - addr = ia64_rse_skip_regs(bsp, r1 - 32); + addr = ia64_rse_skip_regs(bsp, ridx + sof); - DPRINT("ubs_end=%p bsp=%p addr=%px\n", (void *) ubs_end, (void *) bsp, (void *) addr); + DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr); ia64_poke(current, sw, (unsigned long) ubs_end, (unsigned long) addr, val); @@ -353,9 +365,19 @@ unsigned long rnats, nat_mask; unsigned long on_kbs; long sof = (regs->cr_ifs) & 0x7f; + long sor = 8 * ((regs->cr_ifs >> 14) & 0xf); + long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; + long ridx; + + if ((r1 - 32) > sor) + ridx = -sof + (r1 - 32); + else if ((r1 - 32) < (sor - rrb_gr)) + ridx = -sof + (r1 - 32) + rrb_gr; + else + ridx = -sof + (r1 - 32) - (sor - rrb_gr); - DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld\n", - r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f); + DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n", + r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx); if ((r1 - 32) >= sof) { /* this should never happen, as the "rsvd register fault" has higher priority */ @@ -364,7 +386,7 @@ } on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore); - addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + (r1 - 32)); + addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx); if (addr >= kbs) { /* the register is on the kernel backing store: easy... */ *val = *addr; @@ -390,7 +412,7 @@ bspstore = (unsigned long *)regs->ar_bspstore; ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); bsp = ia64_rse_skip_regs(ubs_end, -sof); - addr = ia64_rse_skip_regs(bsp, r1 - 32); + addr = ia64_rse_skip_regs(bsp, ridx + sof); DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr); @@ -908,7 +930,7 @@ * floating point operations sizes in bytes */ static const unsigned char float_fsz[4]={ - 16, /* extended precision (e) */ + 10, /* extended precision (e) */ 8, /* integer (8) */ 4, /* single precision (s) */ 8 /* double precision (d) */ @@ -978,11 +1000,11 @@ unsigned long len = float_fsz[ld.x6_sz]; /* - * fr0 & fr1 don't need to be checked because Illegal Instruction - * faults have higher priority than unaligned faults. + * fr0 & fr1 don't need to be checked because Illegal Instruction faults have + * higher priority than unaligned faults. * - * r0 cannot be found as the base as it would never generate an - * unaligned reference. + * r0 cannot be found as the base as it would never generate an unaligned + * reference. */ /* @@ -996,8 +1018,10 @@ * invalidate the ALAT entry and execute updates, if any. */ if (ld.x6_op != 0x2) { - /* this assumes little-endian byte-order: */ - + /* + * This assumes little-endian byte-order. Note that there is no "ldfpe" + * instruction: + */ if (copy_from_user(&fpr_init[0], (void *) ifa, len) || copy_from_user(&fpr_init[1], (void *) (ifa + len), len)) return -1; @@ -1337,7 +1361,7 @@ /* * IMPORTANT: - * Notice that the swictch statement DOES not cover all possible instructions + * Notice that the switch statement DOES not cover all possible instructions * that DO generate unaligned references. This is made on purpose because for some * instructions it DOES NOT make sense to try and emulate the access. Sometimes it * is WRONG to try and emulate. Here is a list of instruction we don't emulate i.e., diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/unwind.c linux/arch/ia64/kernel/unwind.c --- v2.4.14/linux/arch/ia64/kernel/unwind.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/kernel/unwind.c Fri Nov 9 14:26:17 2001 @@ -504,7 +504,7 @@ return 0; } -inline int +int unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write) { unsigned long *addr; diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/clear_page.S linux/arch/ia64/lib/clear_page.S --- v2.4.14/linux/arch/ia64/lib/clear_page.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/lib/clear_page.S Fri Nov 9 14:26:17 2001 @@ -47,5 +47,5 @@ br.cloop.dptk.few 1b ;; mov ar.lc = r2 // restore lc - br.ret.sptk.few rp + br.ret.sptk.many rp END(clear_page) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/clear_user.S linux/arch/ia64/lib/clear_user.S --- v2.4.14/linux/arch/ia64/lib/clear_user.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/lib/clear_user.S Fri Nov 9 14:26:17 2001 @@ -8,7 +8,7 @@ * r8: number of bytes that didn't get cleared due to a fault * * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> */ #include <asm/asmmacro.h> @@ -62,11 +62,11 @@ ;; // avoid WAW on CFM adds tmp=-1,len // br.ctop is repeat/until mov ret0=len // return value is length at this point -(p6) br.ret.spnt.few rp +(p6) br.ret.spnt.many rp ;; cmp.lt p6,p0=16,len // if len > 16 then long memset mov ar.lc=tmp // initialize lc for small count -(p6) br.cond.dptk.few long_do_clear +(p6) br.cond.dptk .long_do_clear ;; // WAR on ar.lc // // worst case 16 iterations, avg 8 iterations @@ -79,7 +79,7 @@ 1: EX( .Lexit1, st1 [buf]=r0,1 ) adds len=-1,len // countdown length using len - br.cloop.dptk.few 1b + br.cloop.dptk 1b ;; // avoid RAW on ar.lc // // .Lexit4: comes from byte by byte loop @@ -87,7 +87,7 @@ .Lexit1: mov ret0=len // faster than using ar.lc mov ar.lc=saved_lc - br.ret.sptk.few rp // end of short clear_user + br.ret.sptk.many rp // end of short clear_user // @@ -98,7 +98,7 @@ // instead of ret0 is due to the fact that the exception code // changes the values of r8. // -long_do_clear: +.long_do_clear: tbit.nz p6,p0=buf,0 // odd alignment (for long_do_clear) ;; EX( .Lexit3, (p6) st1 [buf]=r0,1 ) // 1-byte aligned @@ -119,7 +119,7 @@ ;; cmp.eq p6,p0=r0,cnt adds tmp=-1,cnt -(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left +(p6) br.cond.dpnt .dotail // we have less than 16 bytes left ;; adds buf2=8,buf // setup second base pointer mov ar.lc=tmp @@ -148,7 +148,7 @@ ;; // needed to get len correct when error st8 [buf2]=r0,16 adds len=-16,len - br.cloop.dptk.few 2b + br.cloop.dptk 2b ;; mov ar.lc=saved_lc // @@ -178,7 +178,7 @@ ;; EX( .Lexit2, (p7) st1 [buf]=r0 ) // only 1 byte left mov ret0=r0 // success - br.ret.dptk.few rp // end of most likely path + br.ret.sptk.many rp // end of most likely path // // Outlined error handling code @@ -205,5 +205,5 @@ .Lexit3: mov ret0=len mov ar.lc=saved_lc - br.ret.dptk.few rp + br.ret.sptk.many rp END(__do_clear_user) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/copy_page.S linux/arch/ia64/lib/copy_page.S --- v2.4.14/linux/arch/ia64/lib/copy_page.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/lib/copy_page.S Fri Nov 9 14:26:17 2001 @@ -90,5 +90,5 @@ mov pr=saved_pr,0xffffffffffff0000 // restore predicates mov ar.pfs=saved_pfs mov ar.lc=saved_lc - br.ret.sptk.few rp + br.ret.sptk.many rp END(copy_page) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S --- v2.4.14/linux/arch/ia64/lib/copy_user.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/lib/copy_user.S Fri Nov 9 14:26:17 2001 @@ -19,8 +19,8 @@ * ret0 0 in case of success. The number of bytes NOT copied in * case of error. * - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 2000-2001 Hewlett-Packard Co + * Stephane Eranian <eranian@hpl.hp.com> * * Fixme: * - handle the case where we have more than 16 bytes and the alignment @@ -85,7 +85,7 @@ cmp.eq p8,p0=r0,len // check for zero length .save ar.lc, saved_lc mov saved_lc=ar.lc // preserve ar.lc (slow) -(p8) br.ret.spnt.few rp // empty mempcy() +(p8) br.ret.spnt.many rp // empty mempcy() ;; add enddst=dst,len // first byte after end of source add endsrc=src,len // first byte after end of destination @@ -103,26 +103,26 @@ cmp.lt p10,p7=COPY_BREAK,len // if len > COPY_BREAK then long copy xor tmp=src,dst // same alignment test prepare -(p10) br.cond.dptk.few long_copy_user +(p10) br.cond.dptk .long_copy_user ;; // RAW pr.rot/p16 ? // // Now we do the byte by byte loop with software pipeline // // p7 is necessarily false by now 1: - EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) - EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) + EX(.failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) + EX(.failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 1b ;; mov ar.lc=saved_lc mov pr=saved_pr,0xffffffffffff0000 mov ar.pfs=saved_pfs // restore ar.ec - br.ret.sptk.few rp // end of short memcpy + br.ret.sptk.many rp // end of short memcpy // // Not 8-byte aligned // -diff_align_copy_user: +.diff_align_copy_user: // At this point we know we have more than 16 bytes to copy // and also that src and dest do _not_ have the same alignment. and src2=0x7,src1 // src offset @@ -153,7 +153,7 @@ // We know src1 is not 8-byte aligned in this case. // cmp.eq p14,p15=r0,dst2 -(p15) br.cond.spnt.few 1f +(p15) br.cond.spnt 1f ;; sub t1=8,src2 mov t2=src2 @@ -163,7 +163,7 @@ ;; sub lshift=64,rshift ;; - br.cond.spnt.few word_copy_user + br.cond.spnt .word_copy_user ;; 1: cmp.leu p14,p15=src2,dst2 @@ -192,15 +192,15 @@ mov ar.lc=cnt ;; 2: - EX(failure_in_pipe2,(p16) ld1 val1[0]=[src1],1) - EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) + EX(.failure_in_pipe2,(p16) ld1 val1[0]=[src1],1) + EX(.failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 2b ;; clrrrb ;; -word_copy_user: +.word_copy_user: cmp.gtu p9,p0=16,len1 -(p9) br.cond.spnt.few 4f // if (16 > len1) skip 8-byte copy +(p9) br.cond.spnt 4f // if (16 > len1) skip 8-byte copy ;; shr.u cnt=len1,3 // number of 64-bit words ;; @@ -232,24 +232,24 @@ #define EPI_1 p[PIPE_DEPTH-2] #define SWITCH(pred, shift) cmp.eq pred,p0=shift,rshift #define CASE(pred, shift) \ - (pred) br.cond.spnt.few copy_user_bit##shift + (pred) br.cond.spnt .copy_user_bit##shift #define BODY(rshift) \ -copy_user_bit##rshift: \ +.copy_user_bit##rshift: \ 1: \ - EX(failure_out,(EPI) st8 [dst1]=tmp,8); \ + EX(.failure_out,(EPI) st8 [dst1]=tmp,8); \ (EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift; \ EX(3f,(p16) ld8 val1[0]=[src1],8); \ - br.ctop.dptk.few 1b; \ + br.ctop.dptk 1b; \ ;; \ - br.cond.sptk.few .diff_align_do_tail; \ + br.cond.sptk.many .diff_align_do_tail; \ 2: \ (EPI) st8 [dst1]=tmp,8; \ (EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift; \ 3: \ (p16) mov val1[0]=r0; \ - br.ctop.dptk.few 2b; \ + br.ctop.dptk 2b; \ ;; \ - br.cond.sptk.few failure_in2 + br.cond.sptk.many .failure_in2 // // Since the instruction 'shrp' requires a fixed 128-bit value @@ -301,25 +301,25 @@ mov ar.lc=len1 ;; 5: - EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) - EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) + EX(.failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) + EX(.failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) br.ctop.dptk.few 5b ;; mov ar.lc=saved_lc mov pr=saved_pr,0xffffffffffff0000 mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp // // Beginning of long mempcy (i.e. > 16 bytes) // -long_copy_user: +.long_copy_user: tbit.nz p6,p7=src1,0 // odd alignement and tmp=7,tmp ;; cmp.eq p10,p8=r0,tmp mov len1=len // copy because of rotation -(p8) br.cond.dpnt.few diff_align_copy_user +(p8) br.cond.dpnt .diff_align_copy_user ;; // At this point we know we have more than 16 bytes to copy // and also that both src and dest have the same alignment @@ -327,11 +327,11 @@ // forward slowly until we reach 16byte alignment: no need to // worry about reaching the end of buffer. // - EX(failure_in1,(p6) ld1 val1[0]=[src1],1) // 1-byte aligned + EX(.failure_in1,(p6) ld1 val1[0]=[src1],1) // 1-byte aligned (p6) adds len1=-1,len1;; tbit.nz p7,p0=src1,1 ;; - EX(failure_in1,(p7) ld2 val1[1]=[src1],2) // 2-byte aligned + EX(.failure_in1,(p7) ld2 val1[1]=[src1],2) // 2-byte aligned (p7) adds len1=-2,len1;; tbit.nz p8,p0=src1,2 ;; @@ -339,28 +339,28 @@ // Stop bit not required after ld4 because if we fail on ld4 // we have never executed the ld1, therefore st1 is not executed. // - EX(failure_in1,(p8) ld4 val2[0]=[src1],4) // 4-byte aligned + EX(.failure_in1,(p8) ld4 val2[0]=[src1],4) // 4-byte aligned ;; - EX(failure_out,(p6) st1 [dst1]=val1[0],1) + EX(.failure_out,(p6) st1 [dst1]=val1[0],1) tbit.nz p9,p0=src1,3 ;; // // Stop bit not required after ld8 because if we fail on ld8 // we have never executed the ld2, therefore st2 is not executed. // - EX(failure_in1,(p9) ld8 val2[1]=[src1],8) // 8-byte aligned - EX(failure_out,(p7) st2 [dst1]=val1[1],2) + EX(.failure_in1,(p9) ld8 val2[1]=[src1],8) // 8-byte aligned + EX(.failure_out,(p7) st2 [dst1]=val1[1],2) (p8) adds len1=-4,len1 ;; - EX(failure_out, (p8) st4 [dst1]=val2[0],4) + EX(.failure_out, (p8) st4 [dst1]=val2[0],4) (p9) adds len1=-8,len1;; shr.u cnt=len1,4 // number of 128-bit (2x64bit) words ;; - EX(failure_out, (p9) st8 [dst1]=val2[1],8) + EX(.failure_out, (p9) st8 [dst1]=val2[1],8) tbit.nz p6,p0=len1,3 cmp.eq p7,p0=r0,cnt adds tmp=-1,cnt // br.ctop is repeat/until -(p7) br.cond.dpnt.few .dotail // we have less than 16 bytes left +(p7) br.cond.dpnt .dotail // we have less than 16 bytes left ;; adds src2=8,src1 adds dst2=8,dst1 @@ -370,12 +370,12 @@ // 16bytes/iteration // 2: - EX(failure_in3,(p16) ld8 val1[0]=[src1],16) + EX(.failure_in3,(p16) ld8 val1[0]=[src1],16) (p16) ld8 val2[0]=[src2],16 - EX(failure_out, (EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16) + EX(.failure_out, (EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16) (EPI) st8 [dst2]=val2[PIPE_DEPTH-1],16 - br.ctop.dptk.few 2b + br.ctop.dptk 2b ;; // RAW on src1 when fall through from loop // // Tail correction based on len only @@ -384,29 +384,28 @@ // is 16 byte aligned AND we have less than 16 bytes to copy. // .dotail: - EX(failure_in1,(p6) ld8 val1[0]=[src1],8) // at least 8 bytes + EX(.failure_in1,(p6) ld8 val1[0]=[src1],8) // at least 8 bytes tbit.nz p7,p0=len1,2 ;; - EX(failure_in1,(p7) ld4 val1[1]=[src1],4) // at least 4 bytes + EX(.failure_in1,(p7) ld4 val1[1]=[src1],4) // at least 4 bytes tbit.nz p8,p0=len1,1 ;; - EX(failure_in1,(p8) ld2 val2[0]=[src1],2) // at least 2 bytes + EX(.failure_in1,(p8) ld2 val2[0]=[src1],2) // at least 2 bytes tbit.nz p9,p0=len1,0 ;; - EX(failure_out, (p6) st8 [dst1]=val1[0],8) + EX(.failure_out, (p6) st8 [dst1]=val1[0],8) ;; - EX(failure_in1,(p9) ld1 val2[1]=[src1]) // only 1 byte left + EX(.failure_in1,(p9) ld1 val2[1]=[src1]) // only 1 byte left mov ar.lc=saved_lc ;; - EX(failure_out,(p7) st4 [dst1]=val1[1],4) + EX(.failure_out,(p7) st4 [dst1]=val1[1],4) mov pr=saved_pr,0xffffffffffff0000 ;; - EX(failure_out, (p8) st2 [dst1]=val2[0],2) + EX(.failure_out, (p8) st2 [dst1]=val2[0],2) mov ar.pfs=saved_pfs ;; - EX(failure_out, (p9) st1 [dst1]=val2[1]) - br.ret.dptk.few rp - + EX(.failure_out, (p9) st1 [dst1]=val2[1]) + br.ret.sptk.many rp // @@ -433,32 +432,32 @@ // pipeline going. We can't really do this inline because // p16 is always reset to 1 when lc > 0. // -failure_in_pipe1: +.failure_in_pipe1: sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied 1: (p16) mov val1[0]=r0 (EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1 - br.ctop.dptk.few 1b + br.ctop.dptk 1b ;; mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp // // This is the case where the byte by byte copy fails on the load // when we copy the head. We need to finish the pipeline and copy // zeros for the rest of the destination. Since this happens // at the top we still need to fill the body and tail. -failure_in_pipe2: +.failure_in_pipe2: sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied 2: (p16) mov val1[0]=r0 (EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1 - br.ctop.dptk.few 2b + br.ctop.dptk 2b ;; sub len=enddst,dst1,1 // precompute len - br.cond.dptk.few failure_in1bis + br.cond.dptk.many .failure_in1bis ;; // @@ -533,9 +532,7 @@ // This means that we are in a situation similar the a fault in the // head part. That's nice! // -failure_in1: -// sub ret0=enddst,dst1 // number of bytes to zero, i.e. not copied -// sub len=enddst,dst1,1 +.failure_in1: sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied sub len=endsrc,src1,1 // @@ -546,18 +543,17 @@ // calling side. // ;; -failure_in1bis: // from (failure_in3) +.failure_in1bis: // from (.failure_in3) mov ar.lc=len // Continue with a stupid byte store. ;; 5: st1 [dst1]=r0,1 - br.cloop.dptk.few 5b + br.cloop.dptk 5b ;; -skip_loop: mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp // // Here we simply restart the loop but instead @@ -569,7 +565,7 @@ // we MUST use src1/endsrc here and not dst1/enddst because // of the pipeline effect. // -failure_in3: +.failure_in3: sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied ;; 2: @@ -577,36 +573,36 @@ (p16) mov val2[0]=r0 (EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16 (EPI) st8 [dst2]=val2[PIPE_DEPTH-1],16 - br.ctop.dptk.few 2b + br.ctop.dptk 2b ;; cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? sub len=enddst,dst1,1 // precompute len -(p6) br.cond.dptk.few failure_in1bis +(p6) br.cond.dptk .failure_in1bis ;; mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp -failure_in2: +.failure_in2: sub ret0=endsrc,src1 cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? sub len=enddst,dst1,1 // precompute len -(p6) br.cond.dptk.few failure_in1bis +(p6) br.cond.dptk .failure_in1bis ;; mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp // // handling of failures on stores: that's the easy part // -failure_out: +.failure_out: sub ret0=enddst,dst1 mov pr=saved_pr,0xffffffffffff0000 mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.dptk.few rp + br.ret.sptk.many rp END(__copy_user) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/do_csum.S linux/arch/ia64/lib/do_csum.S --- v2.4.14/linux/arch/ia64/lib/do_csum.S Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/lib/do_csum.S Fri Nov 9 14:26:17 2001 @@ -16,7 +16,6 @@ * back-to-back 8-byte words per loop. Clean up the initialization * for the loop. Support the cases where load latency = 1 or 2. * Set CONFIG_IA64_LOAD_LATENCY to 1 or 2 (default). - * */ #include <asm/asmmacro.h> @@ -130,7 +129,7 @@ ;; // avoid WAW on CFM mov tmp3=0x7 // a temporary mask/value add tmp1=buf,len // last byte's address -(p6) br.ret.spnt.few rp // return if true (hope we can avoid that) +(p6) br.ret.spnt.many rp // return if true (hope we can avoid that) and firstoff=7,buf // how many bytes off for first1 element tbit.nz p15,p0=buf,0 // is buf an odd address ? @@ -181,9 +180,9 @@ cmp.ltu p6,p0=result1[0],word1[0] // check the carry ;; (p6) adds result1[0]=1,result1[0] -(p8) br.cond.dptk.few do_csum_exit // if (within an 8-byte word) +(p8) br.cond.dptk .do_csum_exit // if (within an 8-byte word) ;; -(p11) br.cond.dptk.few do_csum16 // if (count is even) +(p11) br.cond.dptk .do_csum16 // if (count is even) ;; // Here count is odd. ld8 word1[1]=[first1],8 // load an 8-byte word @@ -196,14 +195,14 @@ ;; (p6) adds result1[0]=1,result1[0] ;; -(p9) br.cond.sptk.few do_csum_exit // if (count == 1) exit +(p9) br.cond.sptk .do_csum_exit // if (count == 1) exit // Fall through to caluculate the checksum, feeding result1[0] as // the initial value in result1[0]. ;; // // Calculate the checksum loading two 8-byte words per loop. // -do_csum16: +.do_csum16: mov saved_lc=ar.lc shr.u count=count,1 // we do 16 bytes per loop ;; @@ -225,7 +224,7 @@ ;; add first2=8,first1 ;; -(p9) br.cond.sptk.few do_csum_exit +(p9) br.cond.sptk .do_csum_exit ;; nop.m 0 nop.i 0 @@ -241,7 +240,7 @@ 2: (p16) ld8 word1[0]=[first1],16 (p16) ld8 word2[0]=[first2],16 - br.ctop.sptk.few 1b + br.ctop.sptk 1b ;; // Since len is a 32-bit value, carry cannot be larger than // a 64-bit value. @@ -263,7 +262,7 @@ ;; (p6) adds result1[0]=1,result1[0] ;; -do_csum_exit: +.do_csum_exit: movl tmp3=0xffffffff ;; // XXX Fixme @@ -299,7 +298,7 @@ ;; mov ar.lc=saved_lc (p15) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes - br.ret.sptk.few rp + br.ret.sptk.many rp // I (Jun Nakajima) wrote an equivalent code (see below), but it was // not much better than the original. So keep the original there so that @@ -331,6 +330,6 @@ //(p15) mux1 ret0=ret0,@rev // reverse word // ;; //(p15) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes -// br.ret.sptk.few rp +// br.ret.sptk.many rp END(do_csum) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/idiv32.S linux/arch/ia64/lib/idiv32.S --- v2.4.14/linux/arch/ia64/lib/idiv32.S Mon Oct 9 17:54:56 2000 +++ linux/arch/ia64/lib/idiv32.S Fri Nov 9 14:26:17 2001 @@ -79,5 +79,5 @@ ;; #endif getf.sig r8 = f6 // transfer result to result register - br.ret.sptk rp + br.ret.sptk.many rp END(NAME) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/idiv64.S linux/arch/ia64/lib/idiv64.S --- v2.4.14/linux/arch/ia64/lib/idiv64.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/idiv64.S Fri Nov 9 14:26:17 2001 @@ -89,5 +89,5 @@ #endif getf.sig r8 = f17 // transfer result to result register ldf.fill f17 = [sp] - br.ret.sptk rp + br.ret.sptk.many rp END(NAME) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/memcpy.S linux/arch/ia64/lib/memcpy.S --- v2.4.14/linux/arch/ia64/lib/memcpy.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/memcpy.S Fri Nov 9 14:26:17 2001 @@ -9,20 +9,14 @@ * Output: * no return value * - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> - * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 2000-2001 Hewlett-Packard Co + * Stephane Eranian <eranian@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> #include <asm/asmmacro.h> -#if defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) -# define BRP(args...) nop.b 0 -#else -# define BRP(args...) brp.loop.imp args -#endif - GLOBAL_ENTRY(bcopy) .regstk 3,0,0,0 mov r8=in0 @@ -103,8 +97,8 @@ cmp.ne p6,p0=t0,r0 mov src=in1 // copy because of rotation -(p7) br.cond.spnt.few memcpy_short -(p6) br.cond.spnt.few memcpy_long +(p7) br.cond.spnt.few .memcpy_short +(p6) br.cond.spnt.few .memcpy_long ;; nop.m 0 ;; @@ -119,7 +113,7 @@ 1: { .mib (p[0]) ld8 val[0]=[src],8 nop.i 0 - BRP(1b, 2f) + brp.loop.imp 1b, 2f } 2: { .mfb (p[N-1])st8 [dst]=val[N-1],8 @@ -139,14 +133,14 @@ * issues, we want to avoid read-modify-write of entire words. */ .align 32 -memcpy_short: +.memcpy_short: adds cnt=-1,in2 // br.ctop is repeat/until mov ar.ec=MEM_LAT - BRP(1f, 2f) + brp.loop.imp 1f, 2f ;; mov ar.lc=cnt ;; - nop.m 0 + nop.m 0 ;; nop.m 0 nop.i 0 @@ -163,7 +157,7 @@ 1: { .mib (p[0]) ld1 val[0]=[src],1 nop.i 0 - BRP(1b, 2f) + brp.loop.imp 1b, 2f } ;; 2: { .mfb (p[MEM_LAT-1])st1 [dst]=val[MEM_LAT-1],1 @@ -202,7 +196,7 @@ #define LOG_LOOP_SIZE 6 -memcpy_long: +.memcpy_long: alloc t3=ar.pfs,3,Nrot,0,Nrot // resize register frame and t0=-8,src // t0 = src & ~7 and t2=7,src // t2 = src & 7 @@ -247,7 +241,7 @@ mov t4=ip } ;; and src2=-8,src // align source pointer - adds t4=memcpy_loops-1b,t4 + adds t4=.memcpy_loops-1b,t4 mov ar.ec=N and t0=7,src // t0 = src & 7 @@ -266,7 +260,7 @@ mov pr=cnt,0x38 // set (p5,p4,p3) to # of bytes last-word bytes to copy mov ar.lc=t2 ;; - nop.m 0 + nop.m 0 ;; nop.m 0 nop.i 0 @@ -278,7 +272,7 @@ br.sptk.few b6 ;; -memcpy_tail: +.memcpy_tail: // At this point, (p5,p4,p3) are set to the number of bytes left to copy (which is // less than 8) and t0 contains the last few bytes of the src buffer: (p5) st4 [dst]=t0,4 @@ -300,7 +294,7 @@ 1: { .mib \ (p[0]) ld8 val[0]=[src2],8; \ (p[MEM_LAT+3]) shrp w[0]=val[MEM_LAT+3],val[MEM_LAT+4-index],shift; \ - BRP(1b, 2f) \ + brp.loop.imp 1b, 2f \ }; \ 2: { .mfb \ (p[MEM_LAT+4]) st8 [dst]=w[1],8; \ @@ -311,8 +305,8 @@ ld8 val[N-1]=[src_end]; /* load last word (may be same as val[N]) */ \ ;; \ shrp t0=val[N-1],val[N-index],shift; \ - br memcpy_tail -memcpy_loops: + br .memcpy_tail +.memcpy_loops: COPY(0, 1) /* no point special casing this---it doesn't go any faster without shrp */ COPY(8, 0) COPY(16, 0) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/memset.S linux/arch/ia64/lib/memset.S --- v2.4.14/linux/arch/ia64/lib/memset.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/memset.S Fri Nov 9 14:26:17 2001 @@ -43,11 +43,11 @@ adds tmp=-1,len // br.ctop is repeat/until tbit.nz p6,p0=buf,0 // odd alignment -(p8) br.ret.spnt.few rp +(p8) br.ret.spnt.many rp cmp.lt p7,p0=16,len // if len > 16 then long memset mux1 val=val,@brcst // prepare value -(p7) br.cond.dptk.few long_memset +(p7) br.cond.dptk .long_memset ;; mov ar.lc=tmp // initialize lc for small count ;; // avoid RAW and WAW on ar.lc @@ -57,11 +57,11 @@ ;; // avoid RAW on ar.lc mov ar.lc=saved_lc mov ar.pfs=saved_pfs - br.ret.sptk.few rp // end of short memset + br.ret.sptk.many rp // end of short memset // at this point we know we have more than 16 bytes to copy // so we focus on alignment -long_memset: +.long_memset: (p6) st1 [buf]=val,1 // 1-byte aligned (p6) adds len=-1,len;; // sync because buf is modified tbit.nz p6,p0=buf,1 @@ -80,7 +80,7 @@ ;; cmp.eq p6,p0=r0,cnt adds tmp=-1,cnt -(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left +(p6) br.cond.dpnt .dotail // we have less than 16 bytes left ;; adds buf2=8,buf // setup second base pointer mov ar.lc=tmp @@ -104,5 +104,5 @@ mov ar.lc=saved_lc ;; (p6) st1 [buf]=val // only 1 byte left - br.ret.dptk.few rp + br.ret.sptk.many rp END(memset) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/strlen.S linux/arch/ia64/lib/strlen.S --- v2.4.14/linux/arch/ia64/lib/strlen.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/strlen.S Fri Nov 9 14:26:17 2001 @@ -11,7 +11,7 @@ * does not count the \0 * * Copyright (C) 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> * * 09/24/99 S.Eranian add speculation recovery code */ @@ -116,7 +116,7 @@ ld8.s w[0]=[src],8 // speculatively load next to next cmp.eq.and p6,p0=8,val1 // p6 = p6 and val1==8 cmp.eq.and p6,p0=8,val2 // p6 = p6 and mask==8 -(p6) br.wtop.dptk.few 1b // loop until p6 == 0 +(p6) br.wtop.dptk 1b // loop until p6 == 0 ;; // // We must return try the recovery code iff @@ -127,14 +127,14 @@ // cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) tnat.nz p6,p7=val1 // test NaT on val1 -(p6) br.cond.spnt.few recover// jump to recovery if val1 is NaT +(p6) br.cond.spnt .recover // jump to recovery if val1 is NaT ;; // // if we come here p7 is true, i.e., initialized for // cmp // cmp.eq.and p7,p0=8,val1// val1==8? tnat.nz.and p7,p0=val2 // test NaT if val2 -(p7) br.cond.spnt.few recover// jump to recovery if val2 is NaT +(p7) br.cond.spnt .recover // jump to recovery if val2 is NaT ;; (p8) mov val1=val2 // the other test got us out of the loop (p8) adds src=-16,src // correct position when 3 ahead @@ -146,7 +146,7 @@ ;; sub ret0=ret0,tmp // adjust mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp // end of normal execution + br.ret.sptk.many rp // end of normal execution // // Outlined recovery code when speculation failed @@ -165,7 +165,7 @@ // - today we restart from the beginning of the string instead // of trying to continue where we left off. // -recover: +.recover: ld8 val=[base],8 // will fail if unrecoverable fault ;; or val=val,mask // remask first bytes @@ -180,7 +180,7 @@ czx1.r val1=val // search 0 byte from right ;; cmp.eq p6,p0=8,val1 // val1==8 ? -(p6) br.wtop.dptk.few 2b // loop until p6 == 0 +(p6) br.wtop.dptk 2b // loop until p6 == 0 ;; // (avoid WAW on p63) sub ret0=base,orig // distance from base sub tmp=8,val1 @@ -188,5 +188,5 @@ ;; sub ret0=ret0,tmp // length=now - back -1 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp // end of successful recovery code + br.ret.sptk.many rp // end of successful recovery code END(strlen) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/strlen_user.S linux/arch/ia64/lib/strlen_user.S --- v2.4.14/linux/arch/ia64/lib/strlen_user.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/strlen_user.S Fri Nov 9 14:26:17 2001 @@ -8,8 +8,8 @@ * ret0 0 in case of fault, strlen(buffer)+1 otherwise * * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> * * 01/19/99 S.Eranian heavily enhanced version (see details below) * 09/24/99 S.Eranian added speculation recovery code @@ -108,7 +108,7 @@ mov ar.ec=r0 // clear epilogue counter (saved in ar.pfs) ;; add base=-16,src // keep track of aligned base - chk.s v[1], recover // if already NaT, then directly skip to recover + chk.s v[1], .recover // if already NaT, then directly skip to recover or v[1]=v[1],mask // now we have a safe initial byte pattern ;; 1: @@ -130,14 +130,14 @@ // cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) tnat.nz p6,p7=val1 // test NaT on val1 -(p6) br.cond.spnt.few recover// jump to recovery if val1 is NaT +(p6) br.cond.spnt .recover // jump to recovery if val1 is NaT ;; // // if we come here p7 is true, i.e., initialized for // cmp // cmp.eq.and p7,p0=8,val1// val1==8? tnat.nz.and p7,p0=val2 // test NaT if val2 -(p7) br.cond.spnt.few recover// jump to recovery if val2 is NaT +(p7) br.cond.spnt .recover // jump to recovery if val2 is NaT ;; (p8) mov val1=val2 // val2 contains the value (p8) adds src=-16,src // correct position when 3 ahead @@ -149,7 +149,7 @@ ;; sub ret0=ret0,tmp // length=now - back -1 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp // end of normal execution + br.ret.sptk.many rp // end of normal execution // // Outlined recovery code when speculation failed @@ -162,7 +162,7 @@ // - today we restart from the beginning of the string instead // of trying to continue where we left off. // -recover: +.recover: EX(.Lexit1, ld8 val=[base],8) // load the initial bytes ;; or val=val,mask // remask first bytes @@ -185,7 +185,7 @@ ;; sub ret0=ret0,tmp // length=now - back -1 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp // end of successful recovery code + br.ret.sptk.many rp // end of successful recovery code // // We failed even on the normal load (called from exception handler) @@ -194,5 +194,5 @@ mov ret0=0 mov pr=saved_pr,0xffffffffffff0000 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp + br.ret.sptk.many rp END(__strlen_user) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/strncpy_from_user.S linux/arch/ia64/lib/strncpy_from_user.S --- v2.4.14/linux/arch/ia64/lib/strncpy_from_user.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/strncpy_from_user.S Fri Nov 9 14:26:17 2001 @@ -40,5 +40,5 @@ (p6) mov r8=in2 // buffer filled up---return buffer length (p7) sub r8=in1,r9,1 // return string length (excluding NUL character) [.Lexit:] - br.ret.sptk.few rp + br.ret.sptk.many rp END(__strncpy_from_user) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/strnlen_user.S linux/arch/ia64/lib/strnlen_user.S --- v2.4.14/linux/arch/ia64/lib/strnlen_user.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/strnlen_user.S Fri Nov 9 14:26:17 2001 @@ -33,7 +33,7 @@ add r9=1,r9 ;; cmp.eq p6,p0=r8,r0 -(p6) br.dpnt.few .Lexit +(p6) br.cond.dpnt .Lexit br.cloop.dptk.few .Loop1 add r9=1,in1 // NUL not found---return N+1 @@ -41,5 +41,5 @@ .Lexit: mov r8=r9 mov ar.lc=r16 // restore ar.lc - br.ret.sptk.few rp + br.ret.sptk.many rp END(__strnlen_user) diff -u --recursive --new-file v2.4.14/linux/arch/ia64/lib/swiotlb.c linux/arch/ia64/lib/swiotlb.c --- v2.4.14/linux/arch/ia64/lib/swiotlb.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/lib/swiotlb.c Fri Nov 9 14:26:17 2001 @@ -398,7 +398,7 @@ BUG(); for (i = 0; i < nelems; i++, sg++) { - sg->orig_address = sg->address; + sg->page = sg->address; if ((virt_to_phys(sg->address) & ~hwdev->dma_mask) != 0) { sg->address = map_single(hwdev, sg->address, sg->length, direction); } @@ -419,9 +419,9 @@ BUG(); for (i = 0; i < nelems; i++, sg++) - if (sg->orig_address != sg->address) { + if (sg->page != sg->address) { unmap_single(hwdev, sg->address, sg->length, direction); - sg->address = sg->orig_address; + sg->address = sg->page; } else if (direction == PCI_DMA_FROMDEVICE) mark_clean(sg->address, sg->length); } @@ -442,7 +442,7 @@ BUG(); for (i = 0; i < nelems; i++, sg++) - if (sg->orig_address != sg->address) + if (sg->page != sg->address) sync_single(hwdev, sg->address, sg->length, direction); } diff -u --recursive --new-file v2.4.14/linux/arch/ia64/mm/fault.c linux/arch/ia64/mm/fault.c --- v2.4.14/linux/arch/ia64/mm/fault.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/mm/fault.c Fri Nov 9 14:26:17 2001 @@ -1,8 +1,8 @@ /* * MMU fault handling support. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/sched.h> #include <linux/kernel.h> @@ -16,7 +16,7 @@ #include <asm/uaccess.h> #include <asm/hardirq.h> -extern void die_if_kernel (char *, struct pt_regs *, long); +extern void die (char *, struct pt_regs *, long); /* * This routine is analogous to expand_stack() but instead grows the @@ -46,16 +46,15 @@ void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) { + int signal = SIGSEGV, code = SEGV_MAPERR; + struct vm_area_struct *vma, *prev_vma; struct mm_struct *mm = current->mm; struct exception_fixup fix; - struct vm_area_struct *vma, *prev_vma; struct siginfo si; - int signal = SIGSEGV; unsigned long mask; /* - * If we're in an interrupt or have no user - * context, we must not take the fault.. + * If we're in an interrupt or have no user context, we must not take the fault.. */ if (in_interrupt() || !mm) goto no_context; @@ -71,6 +70,8 @@ goto check_expansion; good_area: + code = SEGV_ACCERR; + /* OK, we've got a good vm_area for this memory area. Check the access permissions: */ # define VM_READ_BIT 0 @@ -89,12 +90,13 @@ if ((vma->vm_flags & mask) != mask) goto bad_area; + survive: /* * If for any reason at all we couldn't handle the fault, make * sure we exit gracefully rather than endlessly redo the * fault. */ - switch (handle_mm_fault(mm, vma, address, mask) != 0) { + switch (handle_mm_fault(mm, vma, address, mask)) { case 1: ++current->min_flt; break; @@ -147,7 +149,7 @@ if (user_mode(regs)) { si.si_signo = signal; si.si_errno = 0; - si.si_code = SI_KERNEL; + si.si_code = code; si.si_addr = (void *) address; force_sig_info(signal, &si, current); return; @@ -174,17 +176,29 @@ } /* - * Oops. The kernel tried to access some bad page. We'll have - * to terminate things with extreme prejudice. + * Oops. The kernel tried to access some bad page. We'll have to terminate things + * with extreme prejudice. */ - printk(KERN_ALERT "Unable to handle kernel paging request at " - "virtual address %016lx\n", address); - die_if_kernel("Oops", regs, isr); + bust_spinlocks(1); + + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging request at " + "virtual address %016lx\n", address); + die("Oops", regs, isr); + bust_spinlocks(0); do_exit(SIGKILL); return; out_of_memory: up_read(&mm->mmap_sem); + if (current->pid == 1) { + current->policy |= SCHED_YIELD; + schedule(); + down_read(&mm->mmap_sem); + goto survive; + } printk("VM: killing process %s\n", current->comm); if (user_mode(regs)) do_exit(SIGKILL); diff -u --recursive --new-file v2.4.14/linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c --- v2.4.14/linux/arch/ia64/mm/init.c Sun Sep 23 11:40:55 2001 +++ linux/arch/ia64/mm/init.c Fri Nov 9 14:26:17 2001 @@ -167,13 +167,40 @@ } void -show_mem (void) +show_mem(void) { int i, total = 0, reserved = 0; int shared = 0, cached = 0; printk("Mem-info:\n"); show_free_areas(); + +#ifdef CONFIG_DISCONTIGMEM + { + pg_data_t *pgdat = pgdat_list; + + printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + do { + printk("Node ID: %d\n", pgdat->node_id); + for(i = 0; i < pgdat->node_size; i++) { + if (PageReserved(pgdat->node_mem_map+i)) + reserved++; + else if (PageSwapCache(pgdat->node_mem_map+i)) + cached++; + else if (page_count(pgdat->node_mem_map + i)) + shared += page_count(pgdat->node_mem_map + i) - 1; + } + printk("\t%d pages of RAM\n", pgdat->node_size); + printk("\t%d reserved pages\n", reserved); + printk("\t%d pages shared\n", shared); + printk("\t%d pages swap cached\n", cached); + pgdat = pgdat->node_next; + } while (pgdat); + printk("Total of %ld pages in page table cache\n", pgtable_cache_size); + show_buffers(); + printk("%d free buffer pages\n", nr_free_buffer_pages()); + } +#else /* !CONFIG_DISCONTIGMEM */ printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); i = max_mapnr; while (i-- > 0) { @@ -191,6 +218,7 @@ printk("%d pages swap cached\n", cached); printk("%ld pages in page table cache\n", pgtable_cache_size); show_buffers(); +#endif /* !CONFIG_DISCONTIGMEM */ } /* @@ -248,7 +276,7 @@ ia64_clear_ic(flags); rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET); - ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (KERNEL_PG_SHIFT << 2)); + ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (IA64_GRANULE_SHIFT << 2)); rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START); ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1); diff -u --recursive --new-file v2.4.14/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c --- v2.4.14/linux/arch/ia64/mm/tlb.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/mm/tlb.c Fri Nov 9 14:26:17 2001 @@ -2,7 +2,7 @@ * TLB support routines. * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> * * 08/02/00 A. Mallick <asit.k.mallick@intel.com> * Modified RID allocation for SMP @@ -41,89 +41,6 @@ }; /* - * Seralize usage of ptc.g - */ -spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; /* see <asm/pgtable.h> */ - -#if defined(CONFIG_SMP) && !defined(CONFIG_ITANIUM_PTCG) - -#include <linux/irq.h> - -unsigned long flush_end, flush_start, flush_nbits, flush_rid; -atomic_t flush_cpu_count; - -/* - * flush_tlb_no_ptcg is called with ptcg_lock locked - */ -static inline void -flush_tlb_no_ptcg (unsigned long start, unsigned long end, unsigned long nbits) -{ - extern void smp_send_flush_tlb (void); - unsigned long saved_tpr = 0; - unsigned long flags; - - /* - * Some times this is called with interrupts disabled and causes - * dead-lock; to avoid this we enable interrupt and raise the TPR - * to enable ONLY IPI. - */ - __save_flags(flags); - if (!(flags & IA64_PSR_I)) { - saved_tpr = ia64_get_tpr(); - ia64_srlz_d(); - ia64_set_tpr(IA64_IPI_VECTOR - 16); - ia64_srlz_d(); - local_irq_enable(); - } - - spin_lock(&ptcg_lock); - flush_rid = ia64_get_rr(start); - ia64_srlz_d(); - flush_start = start; - flush_end = end; - flush_nbits = nbits; - atomic_set(&flush_cpu_count, smp_num_cpus - 1); - smp_send_flush_tlb(); - /* - * Purge local TLB entries. ALAT invalidation is done in ia64_leave_kernel. - */ - do { - asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - - ia64_srlz_i(); /* srlz.i implies srlz.d */ - - /* - * Wait for other CPUs to finish purging entries. - */ -#if defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) - { - extern void smp_resend_flush_tlb (void); - unsigned long start = ia64_get_itc(); - - while (atomic_read(&flush_cpu_count) > 0) { - if ((ia64_get_itc() - start) > 400000UL) { - smp_resend_flush_tlb(); - start = ia64_get_itc(); - } - } - } -#else - while (atomic_read(&flush_cpu_count)) { - /* Nothing */ - } -#endif - if (!(flags & IA64_PSR_I)) { - local_irq_disable(); - ia64_set_tpr(saved_tpr); - ia64_srlz_d(); - } -} - -#endif /* CONFIG_SMP && !CONFIG_ITANIUM_PTCG */ - -/* * Acquire the ia64_ctx.lock before calling this function! */ void @@ -162,6 +79,26 @@ flush_tlb_all(); } +static inline void +ia64_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) +{ + static spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; + + /* HW requires global serialization of ptc.ga. */ + spin_lock(&ptcg_lock); + { + do { + /* + * Flush ALAT entries also. + */ + asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) + : "memory"); + start += (1UL << nbits); + } while (start < end); + } + spin_unlock(&ptcg_lock); +} + void __flush_tlb_all (void) { @@ -222,23 +159,15 @@ } start &= ~((1UL << nbits) - 1); -#if defined(CONFIG_SMP) && !defined(CONFIG_ITANIUM_PTCG) - flush_tlb_no_ptcg(start, end, nbits); -#else - spin_lock(&ptcg_lock); - do { # ifdef CONFIG_SMP - /* - * Flush ALAT entries also. - */ - asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) : "memory"); + platform_global_tlb_purge(start, end, nbits); # else + do { asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); -# endif start += (1UL << nbits); } while (start < end); -#endif /* CONFIG_SMP && !defined(CONFIG_ITANIUM_PTCG) */ - spin_unlock(&ptcg_lock); +# endif + ia64_insn_group_barrier(); ia64_srlz_i(); /* srlz.i implies srlz.d */ ia64_insn_group_barrier(); diff -u --recursive --new-file v2.4.14/linux/arch/ia64/sn/sn1/llsc4.c linux/arch/ia64/sn/sn1/llsc4.c --- v2.4.14/linux/arch/ia64/sn/sn1/llsc4.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/sn/sn1/llsc4.c Fri Nov 9 14:26:17 2001 @@ -35,16 +35,6 @@ static int inttest=0; #endif -#ifdef IA64_SEMFIX_INSN -#undef IA64_SEMFIX_INSN -#endif -#ifdef IA64_SEMFIX -#undef IA64_SEMFIX -#endif -# define IA64_SEMFIX_INSN -# define IA64_SEMFIX "" - - /* * Test parameter table for AUTOTEST */ @@ -192,7 +182,6 @@ printk (" llscfail \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off"); printk (" llscselt \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off"); printk (" llscblkadr \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off"); - printk (" SEMFIX: %s\n", IA64_SEMFIX); printk ("\n"); } __setup("autotest", autotest_enable); diff -u --recursive --new-file v2.4.14/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c --- v2.4.14/linux/arch/ia64/tools/print_offsets.c Sun Aug 12 13:27:58 2001 +++ linux/arch/ia64/tools/print_offsets.c Fri Nov 9 14:26:17 2001 @@ -57,11 +57,8 @@ { "IA64_TASK_PROCESSOR_OFFSET", offsetof (struct task_struct, processor) }, { "IA64_TASK_THREAD_OFFSET", offsetof (struct task_struct, thread) }, { "IA64_TASK_THREAD_KSP_OFFSET", offsetof (struct task_struct, thread.ksp) }, -#ifdef CONFIG_IA32_SUPPORT - { "IA64_TASK_THREAD_SIGMASK_OFFSET",offsetof (struct task_struct, thread.un.sigmask) }, -#endif #ifdef CONFIG_PERFMON - { "IA64_TASK_PFM_NOTIFY_OFFSET", offsetof(struct task_struct, thread.pfm_pend_notify) }, + { "IA64_TASK_PFM_MUST_BLOCK_OFFSET",offsetof(struct task_struct, thread.pfm_must_block) }, #endif { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, { "IA64_TASK_MM_OFFSET", offsetof (struct task_struct, mm) }, @@ -165,17 +162,18 @@ { "IA64_SIGCONTEXT_FR6_OFFSET", offsetof (struct sigcontext, sc_fr[6]) }, { "IA64_SIGCONTEXT_PR_OFFSET", offsetof (struct sigcontext, sc_pr) }, { "IA64_SIGCONTEXT_R12_OFFSET", offsetof (struct sigcontext, sc_gr[12]) }, + { "IA64_SIGCONTEXT_RBS_BASE_OFFSET",offsetof (struct sigcontext, sc_rbs_base) }, + { "IA64_SIGCONTEXT_LOADRS_OFFSET", offsetof (struct sigcontext, sc_loadrs) }, { "IA64_SIGFRAME_ARG0_OFFSET", offsetof (struct sigframe, arg0) }, { "IA64_SIGFRAME_ARG1_OFFSET", offsetof (struct sigframe, arg1) }, { "IA64_SIGFRAME_ARG2_OFFSET", offsetof (struct sigframe, arg2) }, - { "IA64_SIGFRAME_RBS_BASE_OFFSET", offsetof (struct sigframe, rbs_base) }, { "IA64_SIGFRAME_HANDLER_OFFSET", offsetof (struct sigframe, handler) }, { "IA64_SIGFRAME_SIGCONTEXT_OFFSET", offsetof (struct sigframe, sc) }, { "IA64_CLONE_VFORK", CLONE_VFORK }, { "IA64_CLONE_VM", CLONE_VM }, { "IA64_CPU_IRQ_COUNT_OFFSET", offsetof (struct cpuinfo_ia64, irq_stat.f.irq_count) }, { "IA64_CPU_BH_COUNT_OFFSET", offsetof (struct cpuinfo_ia64, irq_stat.f.bh_count) }, - { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET", offsetof (struct cpuinfo_ia64, phys_stacked_size_p8) }, + { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET",offsetof (struct cpuinfo_ia64, phys_stacked_size_p8)}, }; static const char *tabs = "\t\t\t\t\t\t\t\t\t\t"; diff -u --recursive --new-file v2.4.14/linux/arch/s390/config.in linux/arch/s390/config.in --- v2.4.14/linux/arch/s390/config.in Sun Aug 12 13:27:58 2001 +++ linux/arch/s390/config.in Fri Nov 9 13:58:02 2001 @@ -9,6 +9,7 @@ define_bool CONFIG_UID16 y define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n +define_bool CONFIG_GENERIC_BUST_SPINLOCK n mainmenu_name "Linux Kernel Configuration" define_bool CONFIG_ARCH_S390 y diff -u --recursive --new-file v2.4.14/linux/arch/s390/defconfig linux/arch/s390/defconfig --- v2.4.14/linux/arch/s390/defconfig Sun Aug 12 13:27:58 2001 +++ linux/arch/s390/defconfig Fri Nov 9 13:58:02 2001 @@ -7,6 +7,7 @@ CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_GENERIC_BUST_SPINLOCK=n CONFIG_ARCH_S390=y # @@ -72,6 +73,7 @@ CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m CONFIG_MD_RAID5=m +# CONFIG_MD_MULTIPATH is not set CONFIG_BLK_DEV_LVM=m # @@ -183,19 +185,25 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_CMS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set +# CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -218,6 +226,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set @@ -235,6 +244,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -247,6 +258,7 @@ CONFIG_IBM_PARTITION=y # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set diff -u --recursive --new-file v2.4.14/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S --- v2.4.14/linux/arch/s390/kernel/entry.S Tue Oct 23 22:48:49 2001 +++ linux/arch/s390/kernel/entry.S Fri Nov 9 13:58:02 2001 @@ -256,9 +256,17 @@ # sysc_tracesys: l %r1,BASED(.Ltrace) - l %r2,BASED(.Lc_ENOSYS) - st %r2,SP_R2(%r15) # give sysc_trace an -ENOSYS retval + l %r7,BASED(.Lc_ENOSYS) + st %r7,SP_R2(%r15) # give sysc_trace an -ENOSYS retval basr %r14,%r1 + l %r2,SP_R2(%r15) + cr %r2,%r7 # compare with saved -ENOSYS + be BASED(sysc_tracesys_dn1) + # strace wants to change the syscall + sll %r2,24 + srl %r2,22 + l %r8,sys_call_table-entry_base(2,%r13) # get address of system call +sysc_tracesys_dn1: lm %r3,%r6,SP_R3(%r15) l %r2,SP_ORIG_R2(%r15) basr %r14,%r8 # call sys_xxx @@ -689,10 +697,7 @@ l %r5,SP_PSW+4(15) # load psw addr sr %r5,%r7 # substract ilc from psw st %r5,SP_PSW+4(15) # store corrected psw addr -pgm_per:cl %r3,BASED(.Lc20) # pseudo page fault ? - be BASED(pgm_go) # if yes then don't reenable interrupts - stosm 24(%r15),0x03 # reenable interrupts -pgm_go: basr %r14,%r1 # branch to interrupt-handler +pgm_per:basr %r14,%r1 # branch to interrupt-handler pgm_dn: n %r8,BASED(.Lc128) # check for per excepton be BASED(pgm_return) la %r2,SP_PTREGS(15) # address of register-save area diff -u --recursive --new-file v2.4.14/linux/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S --- v2.4.14/linux/arch/s390/kernel/head.S Tue Oct 23 22:48:49 2001 +++ linux/arch/s390/kernel/head.S Fri Nov 9 13:58:02 2001 @@ -338,12 +338,12 @@ # reset files in VM reader # stidp __LC_CPUID # store cpuid - lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on P/390 ? - be start # no -> skip reset + tm __LC_CPUID,0xff # running VM ? + bno .Lnoreset la %r2,.Lreset lhi %r3,26 .long 0x83230008 +.Lnoreset: #endif # diff -u --recursive --new-file v2.4.14/linux/arch/s390/kernel/init_task.c linux/arch/s390/kernel/init_task.c --- v2.4.14/linux/arch/s390/kernel/init_task.c Sun Sep 23 11:40:56 2001 +++ linux/arch/s390/kernel/init_task.c Fri Nov 9 13:58:02 2001 @@ -12,6 +12,7 @@ #include <asm/uaccess.h> #include <asm/pgtable.h> +static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; diff -u --recursive --new-file v2.4.14/linux/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c --- v2.4.14/linux/arch/s390/kernel/s390_ksyms.c Tue Oct 23 22:48:49 2001 +++ linux/arch/s390/kernel/s390_ksyms.c Fri Nov 9 13:58:02 2001 @@ -59,4 +59,3 @@ EXPORT_SYMBOL_NOVERS(do_call_softirq); - diff -u --recursive --new-file v2.4.14/linux/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c --- v2.4.14/linux/arch/s390/kernel/traps.c Tue Oct 23 22:48:50 2001 +++ linux/arch/s390/kernel/traps.c Fri Nov 9 13:58:02 2001 @@ -94,8 +94,16 @@ static void inline do_trap(long interruption_code, int signr, char *str, struct pt_regs *regs, siginfo_t *info) { + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (regs->psw.mask & PSW_PROBLEM_STATE) { struct task_struct *tsk = current; + tsk->thread.trap_no = interruption_code; if (info) force_sig_info(signr, info, tsk); @@ -160,20 +168,27 @@ __u8 opcode[6]; __u16 *location; int signal = 0; - int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); - if(problem_state) + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + + if (regs->psw.mask & PSW_PROBLEM_STATE) get_user(*((__u16 *) opcode), location); else *((__u16 *)opcode)=*((__u16 *)location); - if(*((__u16 *)opcode)==S390_BREAKPOINT_U16) + if (*((__u16 *)opcode)==S390_BREAKPOINT_U16) { if(do_debugger_trap(regs,SIGTRAP)) signal = SIGILL; } #ifdef CONFIG_MATHEMU - else if (problem_state) + else if (regs->psw.mask & PSW_PROBLEM_STATE) { if (opcode[0] == 0xb3) { get_user(*((__u16 *) (opcode+2)), location+1); @@ -216,8 +231,16 @@ __u16 *location = NULL; int signal = 0; + location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (regs->psw.mask & PSW_PROBLEM_STATE) { - location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ @@ -267,6 +290,14 @@ int signal = 0; location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (MACHINE_HAS_IEEE) __asm__ volatile ("stfpc %0\n\t" : "=m" (current->thread.fp_regs.fpc)); diff -u --recursive --new-file v2.4.14/linux/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c --- v2.4.14/linux/arch/s390/mm/fault.c Tue Oct 23 22:48:50 2001 +++ linux/arch/s390/mm/fault.c Fri Nov 9 13:58:02 2001 @@ -159,14 +159,17 @@ /* * Check whether we have a user MM in the first place. */ - if (in_interrupt() || !mm) + if (in_interrupt() || !mm || !(regs->psw.mask & _PSW_IO_MASK_BIT)) goto no_context; /* * When we get here, the fault happened in the current - * task's user address space, so we search the VMAs + * task's user address space, so we can switch on the + * interrupts again and then search the VMAs */ + __sti(); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); @@ -415,7 +418,11 @@ " la 2,0(%0)\n" " sacf 512\n" " ic 2,0(2)\n" - " sacf 0" + "0:sacf 0\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,0b\n" + ".previous" : : "a" (address) : "2" ); return; @@ -513,7 +520,7 @@ * external interrupt. */ subcode = S390_lowcore.cpu_addr; - if ((subcode & 0xff00) != 0x0600) + if ((subcode & 0xff00) != 0x0200) return; /* @@ -522,6 +529,13 @@ tsk = (struct task_struct *) (*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE); + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (subcode & 0x0080) { /* signal bit is set -> a page has been swapped in by VM */ qp = (wait_queue_head_t *) diff -u --recursive --new-file v2.4.14/linux/arch/s390x/defconfig linux/arch/s390x/defconfig --- v2.4.14/linux/arch/s390x/defconfig Tue Oct 23 22:48:50 2001 +++ linux/arch/s390x/defconfig Fri Nov 9 13:58:02 2001 @@ -185,19 +185,25 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set +# CONFIG_CMS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set # CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set +# CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set @@ -220,6 +226,7 @@ # Network File Systems # # CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set @@ -237,6 +244,8 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set +# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types diff -u --recursive --new-file v2.4.14/linux/arch/s390x/kernel/entry.S linux/arch/s390x/kernel/entry.S --- v2.4.14/linux/arch/s390x/kernel/entry.S Tue Oct 23 22:48:50 2001 +++ linux/arch/s390x/kernel/entry.S Fri Nov 9 13:58:02 2001 @@ -247,6 +247,17 @@ lghi %r2,-ENOSYS stg %r2,SP_R2(%r15) # give sysc_trace an -ENOSYS retval brasl %r14,syscall_trace + lg %r2,SP_R2(%r15) + cghi %r2,-ENOSYS + je sysc_tracesys_dn1 + sllg %r2,%r2,56 # strace wants to change the syscall + srlg %r2,%r2,53 # zap unused bits & multiply by 8 + tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ? + jo sysc_tracesys_noemu + la %r2,4(%r2) # use 31 bit emulation system calls +sysc_tracesys_noemu: + lgf %r8,0(%r2,%r7) # load address of system call routine +sysc_tracesys_dn1: lmg %r3,%r6,SP_R3(%r15) lg %r2,SP_ORIG_R2(%r15) basr %r14,%r8 # call sys_xxx @@ -672,7 +683,6 @@ GET_CURRENT pgm_no_sv: llgh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it - stosm 48(%r15),0x03 # reenable interrupts lghi %r3,0x7f nr %r3,%r8 # clear per-event-bit & move to r3 je pgm_dn # none of Martins exceptions occurred bypass diff -u --recursive --new-file v2.4.14/linux/arch/s390x/kernel/head.S linux/arch/s390x/kernel/head.S --- v2.4.14/linux/arch/s390x/kernel/head.S Tue Oct 23 22:48:50 2001 +++ linux/arch/s390x/kernel/head.S Fri Nov 9 13:58:02 2001 @@ -337,12 +337,12 @@ # reset files in VM reader # stidp __LC_CPUID # store cpuid - lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on P/390 ? - be start # no -> skip reset + tm __LC_CPUID,0xff # running VM ? + bno .Lnoreset la %r2,.Lreset lhi %r3,26 .long 0x83230008 +.Lnoreset: #endif # diff -u --recursive --new-file v2.4.14/linux/arch/s390x/kernel/init_task.c linux/arch/s390x/kernel/init_task.c --- v2.4.14/linux/arch/s390x/kernel/init_task.c Sun Sep 23 11:40:56 2001 +++ linux/arch/s390x/kernel/init_task.c Fri Nov 9 13:58:02 2001 @@ -12,6 +12,7 @@ #include <asm/uaccess.h> #include <asm/pgtable.h> +static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; diff -u --recursive --new-file v2.4.14/linux/arch/s390x/kernel/ioctl32.c linux/arch/s390x/kernel/ioctl32.c --- v2.4.14/linux/arch/s390x/kernel/ioctl32.c Tue Oct 23 22:48:50 2001 +++ linux/arch/s390x/kernel/ioctl32.c Wed Nov 7 14:39:36 2001 @@ -487,6 +487,13 @@ IOCTL32_HANDLER(SIOCADDRT, routing_ioctl), IOCTL32_HANDLER(SIOCDELRT, routing_ioctl), + IOCTL32_HANDLER(SIOCBONDENSLAVE, bond_ioctl), + IOCTL32_HANDLER(SIOCBONDRELEASE, bond_ioctl), + IOCTL32_HANDLER(SIOCBONDSETHWADDR, bond_ioctl), + IOCTL32_HANDLER(SIOCBONDSLAVEINFOQUERY, bond_ioctl), + IOCTL32_HANDLER(SIOCBONDINFOQUERY, bond_ioctl), + IOCTL32_HANDLER(SIOCBONDCHANGEACTIVE, bond_ioctl), + IOCTL32_HANDLER(EXT2_IOC32_GETFLAGS, do_ext2_ioctl), IOCTL32_HANDLER(EXT2_IOC32_SETFLAGS, do_ext2_ioctl), IOCTL32_HANDLER(EXT2_IOC32_GETVERSION, do_ext2_ioctl), diff -u --recursive --new-file v2.4.14/linux/arch/s390x/kernel/traps.c linux/arch/s390x/kernel/traps.c --- v2.4.14/linux/arch/s390x/kernel/traps.c Tue Oct 23 22:48:50 2001 +++ linux/arch/s390x/kernel/traps.c Fri Nov 9 13:58:02 2001 @@ -92,6 +92,13 @@ static void inline do_trap(long interruption_code, int signr, char *str, struct pt_regs *regs, siginfo_t *info) { + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + if (regs->psw.mask & PSW_PROBLEM_STATE) { struct task_struct *tsk = current; tsk->thread.trap_no = interruption_code; @@ -161,6 +168,14 @@ int do_sig = 0; location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + /* WARNING don't change this check back to */ /* int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); */ /* & then doing if(problem_state) an int is too small for this */ @@ -186,6 +201,14 @@ int do_sig = 0; location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); + __asm__ volatile ("stfpc %0\n\t" : "=m" (current->thread.fp_regs.fpc)); /* Same code should work when we implement fpu emulation */ diff -u --recursive --new-file v2.4.14/linux/arch/s390x/kernel/wrapper32.S linux/arch/s390x/kernel/wrapper32.S --- v2.4.14/linux/arch/s390x/kernel/wrapper32.S Tue Oct 23 22:48:50 2001 +++ linux/arch/s390x/kernel/wrapper32.S Fri Nov 9 13:58:02 2001 @@ -629,8 +629,10 @@ .globl sys32_llseek_wrapper sys32_llseek_wrapper: llgfr %r2,%r2 # unsigned int - lgfr %r3,%r3 # off_t - llgfr %r4,%r4 # unsigned int + llgfr %r3,%r3 # unsigned long + llgfr %r4,%r4 # unsigned long + llgtr %r5,%r5 # loff_t * + llgfr %r6,%r6 # unsigned int jg sys_llseek # branch to system call .globl sys32_getdents_wrapper diff -u --recursive --new-file v2.4.14/linux/arch/s390x/mm/fault.c linux/arch/s390x/mm/fault.c --- v2.4.14/linux/arch/s390x/mm/fault.c Tue Oct 23 22:48:50 2001 +++ linux/arch/s390x/mm/fault.c Fri Nov 9 13:58:02 2001 @@ -159,14 +159,17 @@ /* * Check whether we have a user MM in the first place. */ - if (in_interrupt() || !mm) + if (in_interrupt() || !mm || !(regs->psw.mask & _PSW_IO_MASK_BIT)) goto no_context; /* * When we get here, the fault happened in the current - * task's user address space, so we search the VMAs + * task's user address space, so we can switch on the + * interrupts again and then search the VMAs */ + __sti(); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); @@ -419,6 +422,13 @@ */ tsk = (struct task_struct *) (*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE); + + /* + * We got all needed information from the lowcore and can + * now safely switch on interrupts. + */ + if (regs->psw.mask & PSW_PROBLEM_STATE) + __sti(); if (subcode & 0x0080) { /* signal bit is set -> a page has been swapped in by VM */ diff -u --recursive --new-file v2.4.14/linux/arch/s390x/mm/init.c linux/arch/s390x/mm/init.c --- v2.4.14/linux/arch/s390x/mm/init.c Tue Oct 23 22:48:50 2001 +++ linux/arch/s390x/mm/init.c Fri Nov 9 13:58:02 2001 @@ -59,7 +59,7 @@ } if(pte_quicklist) { pte_free_slow(pte_alloc_one_fast(NULL, 0)); - freed += 4; + freed += 1; } } while(pgtable_cache_size > low); } diff -u --recursive --new-file v2.4.14/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.4.14/linux/arch/sparc64/kernel/ioctl32.c Mon Nov 5 15:55:27 2001 +++ linux/arch/sparc64/kernel/ioctl32.c Wed Nov 7 14:39:36 2001 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.127 2001/11/01 23:54:19 davem Exp $ +/* $Id: ioctl32.c,v 1.131 2001/11/07 01:13:23 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -71,6 +71,7 @@ #include <asm/audioio.h> #include <linux/ethtool.h> #include <linux/mii.h> +#include <linux/if_bonding.h> #include <asm/display7seg.h> #include <asm/watchdog.h> #include <asm/module.h> @@ -592,6 +593,58 @@ return err; } +static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + mm_segment_t old_fs; + int err, len; + u32 data; + + if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) + return -EFAULT; + ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); + if (!ifr.ifr_data) + return -EAGAIN; + + switch (cmd) { + case SIOCBONDENSLAVE: + case SIOCBONDRELEASE: + case SIOCBONDSETHWADDR: + case SIOCBONDCHANGEACTIVE: + len = IFNAMSIZ * sizeof(char); + break; + case SIOCBONDSLAVEINFOQUERY: + len = sizeof(struct ifslave); + break; + case SIOCBONDINFOQUERY: + len = sizeof(struct ifbond); + break; + default: + err = -EINVAL; + goto out; + }; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) { + err = -EFAULT; + goto out; + } + + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + set_fs (old_fs); + if (!err) { + len = copy_to_user((char *)A(data), ifr.ifr_data, len); + if (len) + err = -EFAULT; + } + +out: + free_page((unsigned long)ifr.ifr_data); + return err; +} + static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) { struct ifreq ifr; @@ -4488,6 +4541,12 @@ HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) +HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl) +HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl) +HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl) +HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl) +HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl) +HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl) HANDLE_IOCTL(SIOCADDRT, routing_ioctl) HANDLE_IOCTL(SIOCDELRT, routing_ioctl) /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ diff -u --recursive --new-file v2.4.14/linux/drivers/acpi/os.c linux/drivers/acpi/os.c --- v2.4.14/linux/drivers/acpi/os.c Mon Nov 5 15:55:28 2001 +++ linux/drivers/acpi/os.c Fri Nov 9 13:39:25 2001 @@ -189,11 +189,6 @@ return AE_ERROR; } - if ((unsigned long) phys < virt_to_phys(high_memory)) { - *virt = phys_to_virt((unsigned long) phys); - return AE_OK; - } - *virt = ioremap((unsigned long) phys, size); if (!*virt) return AE_ERROR; @@ -204,8 +199,7 @@ void acpi_os_unmap_memory(void *virt, u32 size) { - if (virt >= high_memory) - iounmap(virt); + iounmap(virt); } acpi_status diff -u --recursive --new-file v2.4.14/linux/drivers/acpi/ospm/processor/pr_osl.c linux/drivers/acpi/ospm/processor/pr_osl.c --- v2.4.14/linux/drivers/acpi/ospm/processor/pr_osl.c Mon Nov 5 15:55:28 2001 +++ linux/drivers/acpi/ospm/processor/pr_osl.c Fri Nov 9 13:58:02 2001 @@ -143,7 +143,7 @@ PR_CONTEXT *processor) { u32 i = 0; - struct proc_dir_entry *proc_entry = NULL; + struct proc_dir_entry *proc_entry = NULL, *proc; char processor_uid[16]; if (!processor) { @@ -165,15 +165,18 @@ sprintf(processor_uid, "%d", processor->uid); proc_entry = proc_mkdir(processor_uid, pr_proc_root); - if (!proc_entry) { + if (!proc_entry) return(AE_ERROR); - } - create_proc_read_entry(PR_PROC_STATUS, S_IFREG | S_IRUGO, - proc_entry, pr_osl_proc_read_status, (void*)processor); + proc = create_proc_read_entry(PR_PROC_STATUS, S_IFREG | S_IRUGO, + proc_entry, pr_osl_proc_read_status, (void*)processor); + if (!proc_entry) + return(AE_ERROR); - create_proc_read_entry(PR_PROC_INFO, S_IFREG | S_IRUGO, - proc_entry, pr_osl_proc_read_info, (void*)processor); + proc = create_proc_read_entry(PR_PROC_INFO, S_IFREG | S_IRUGO, + proc_entry, pr_osl_proc_read_info, (void*)processor); + if (!proc_entry) + return(AE_ERROR); return(AE_OK); } diff -u --recursive --new-file v2.4.14/linux/drivers/atm/Config.in linux/drivers/atm/Config.in --- v2.4.14/linux/drivers/atm/Config.in Mon Nov 5 15:55:28 2001 +++ linux/drivers/atm/Config.in Wed Nov 7 14:39:36 2001 @@ -40,6 +40,11 @@ bool ' Use suni PHY driver (155Mbps)' CONFIG_ATM_NICSTAR_USE_SUNI bool ' Use IDT77015 PHY driver (25Mbps)' CONFIG_ATM_NICSTAR_USE_IDT77105 fi + tristate 'IDT 77252 (NICStAR II)' CONFIG_ATM_IDT77252 + if [ "$CONFIG_ATM_IDT77252" != "n" ]; then + bool ' Receive ALL cells in raw queue' CONFIG_ATM_IDT77252_RCV_ALL + define_bool CONFIG_ATM_IDT77252_USE_SUNI y + fi tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then bool ' Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG diff -u --recursive --new-file v2.4.14/linux/drivers/atm/Makefile linux/drivers/atm/Makefile --- v2.4.14/linux/drivers/atm/Makefile Mon Nov 5 15:55:28 2001 +++ linux/drivers/atm/Makefile Wed Nov 7 14:39:36 2001 @@ -12,6 +12,7 @@ obj-$(CONFIG_ATM_ENI) += eni.o suni.o obj-$(CONFIG_ATM_ZATM) += zatm.o uPD98402.o obj-$(CONFIG_ATM_NICSTAR) += nicstar.o +obj-$(CONFIG_ATM_IDT77252) += idt77252.o ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) obj-$(CONFIG_ATM_NICSTAR) += suni.o @@ -19,6 +20,10 @@ ifeq ($(CONFIG_ATM_NICSTAR_USE_IDT77105),y) obj-$(CONFIG_ATM_NICSTAR) += idt77105.o +endif + +ifeq ($(CONFIG_ATM_IDT77252_USE_SUNI),y) + obj-$(CONFIG_ATM_IDT77252) += suni.o endif obj-$(CONFIG_ATM_HORIZON) += horizon.o diff -u --recursive --new-file v2.4.14/linux/drivers/atm/atmdev_init.c linux/drivers/atm/atmdev_init.c --- v2.4.14/linux/drivers/atm/atmdev_init.c Mon Nov 5 15:55:28 2001 +++ linux/drivers/atm/atmdev_init.c Wed Nov 7 14:39:36 2001 @@ -13,6 +13,9 @@ #ifdef CONFIG_ATM_NICSTAR extern int nicstar_detect(void); #endif +#ifdef CONFIG_ATM_IDT77252 +extern int idt77252_detect(void); +#endif #ifdef CONFIG_ATM_AMBASSADOR extern int amb_detect(void); #endif @@ -46,6 +49,9 @@ #endif #ifdef CONFIG_ATM_NICSTAR devs += nicstar_detect(); +#endif +#ifdef CONFIG_ATM_IDT77252 + devs += idt77252_detect(); #endif #ifdef CONFIG_ATM_AMBASSADOR devs += amb_detect(); diff -u --recursive --new-file v2.4.14/linux/drivers/atm/eni.c linux/drivers/atm/eni.c --- v2.4.14/linux/drivers/atm/eni.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/atm/eni.c Fri Nov 9 13:41:42 2001 @@ -2266,7 +2266,7 @@ } dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL); if (!dev) goto out2; - pci_dev->driver_data = dev; + pci_set_drvdata(pci_dev, dev); eni_dev->pci_dev = pci_dev; ENI_DEV(dev) = eni_dev; eni_dev->asic = ent->driver_data; diff -u --recursive --new-file v2.4.14/linux/drivers/atm/firestream.c linux/drivers/atm/firestream.c --- v2.4.14/linux/drivers/atm/firestream.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/atm/firestream.c Fri Nov 9 13:58:03 2001 @@ -912,6 +912,9 @@ if (IS_FS50(dev)) { /* Increment the channel numer: take a free one next time. */ for (to=33;to;to--, dev->channo++) { + /* We only have 32 channels */ + if (dev->channo >= 32) + dev->channo = 0; /* If we need to do RX, AND the RX is inuse, try the next */ if (DO_DIRECTION(rxtp) && dev->atm_vccs[dev->channo]) continue; @@ -1226,7 +1229,7 @@ { func_enter (); func_exit (); - return 0; + return -ENOIOCTLCMD; } diff -u --recursive --new-file v2.4.14/linux/drivers/atm/idt77252.c linux/drivers/atm/idt77252.c --- v2.4.14/linux/drivers/atm/idt77252.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/idt77252.c Wed Nov 7 14:39:36 2001 @@ -0,0 +1,3920 @@ +/******************************************************************* + * ident "$Id: idt77252.c,v 1.1 2001/11/05 21:52:22 ecd Exp $" + * + * $Author: ecd $ + * $Date: 2001/11/05 21:52:22 $ + * + * Copyright (c) 2000 ATecoM GmbH + * + * The author may be reached at ecd@atecom.com. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + *******************************************************************/ +static char const rcsid[] = +"$Id: idt77252.c,v 1.1 2001/11/05 21:52:22 ecd Exp $"; + + +#include <linux/module.h> +#include <linux/config.h> +#include <linux/pci.h> +#include <linux/skbuff.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/netdevice.h> +#include <linux/atmdev.h> +#include <linux/atm.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/bitops.h> +#include <linux/wait.h> +#include <asm/semaphore.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/atomic.h> +#include <asm/byteorder.h> + +#ifdef CONFIG_ATM_IDT77252_USE_SUNI +#include "suni.h" +#endif /* CONFIG_ATM_IDT77252_USE_SUNI */ + + +#define DEBUG 1 + +#include "idt77252.h" +#include "idt77252_tables.h" + +static unsigned int vpibits = 1; + + +#define CONFIG_ATM_IDT77252_SEND_IDLE 1 + + +/* + * Debug HACKs. + */ +#define DEBUG_MODULE 1 +#undef DEBUG_RAW_CELLS +#undef HAVE_EEPROM /* does not work, yet. */ + +#ifdef DEBUG +static unsigned long debug = DBG_GENERAL; +#endif + + +#define SAR_RX_DELAY (SAR_CFG_RXINT_NODELAY) + + +/* + * SCQ Handling. + */ +static struct scq_info *alloc_scq(struct idt77252_dev *, int); +static void free_scq(struct idt77252_dev *, struct scq_info *); +static int queue_skb(struct idt77252_dev *, struct vc_map *, + struct sk_buff *, int oam); +static void drain_scq(struct idt77252_dev *, struct vc_map *); +static unsigned long get_free_scd(struct idt77252_dev *, struct vc_map *); +static void fill_scd(struct idt77252_dev *, struct scq_info *, int); + +/* + * FBQ Handling. + */ +static int push_rx_skb(struct idt77252_dev *, + struct sk_buff *, int queue); +static void recycle_rx_skb(struct idt77252_dev *, struct sk_buff *); +static void flush_rx_pool(struct idt77252_dev *, struct rx_pool *); +static void recycle_rx_pool_skb(struct idt77252_dev *, + struct rx_pool *); +static void add_rx_skb(struct idt77252_dev *, int queue, + unsigned int size, unsigned int count); + +/* + * RSQ Handling. + */ +static int init_rsq(struct idt77252_dev *); +static void deinit_rsq(struct idt77252_dev *); +static void idt77252_rx(struct idt77252_dev *); + +/* + * TSQ handling. + */ +static int init_tsq(struct idt77252_dev *); +static void deinit_tsq(struct idt77252_dev *); +static void idt77252_tx(struct idt77252_dev *); + + +/* + * ATM Interface. + */ +static void idt77252_dev_close(struct atm_dev *dev); +static int idt77252_open(struct atm_vcc *vcc, short vpi, int vci); +static void idt77252_close(struct atm_vcc *vcc); +static int idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb); +static int idt77252_send_oam(struct atm_vcc *vcc, void *cell, + int flags); +static void idt77252_phy_put(struct atm_dev *dev, unsigned char value, + unsigned long addr); +static unsigned char idt77252_phy_get(struct atm_dev *dev, unsigned long addr); +static int idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, + int flags); +static int idt77252_proc_read(struct atm_dev *dev, loff_t * pos, + char *page); +static void idt77252_interrupt(int irq, void *dev_id, + struct pt_regs *regs); +static void idt77252_softint(void *dev_id); + + +static struct atmdev_ops idt77252_ops = +{ + idt77252_dev_close, /* dev_close */ + idt77252_open, /* open */ + idt77252_close, /* close */ + NULL, /* ioctl */ + NULL, /* getsockopt */ + NULL, /* setsockopt */ + idt77252_send, /* send */ + NULL, /* sg_send */ + idt77252_send_oam, /* send_oam */ + idt77252_phy_put, + idt77252_phy_get, + NULL, /* feedback */ + idt77252_change_qos, + NULL, /* free_rx_skb */ + idt77252_proc_read /* proc_read */ +}; + +static struct idt77252_dev *idt77252_chain = NULL; +static unsigned int idt77252_sram_write_errors = 0; + +/*****************************************************************************/ +/* */ +/* I/O and Utility Bus */ +/* */ +/*****************************************************************************/ + +static void +waitfor_idle(struct idt77252_dev *card) +{ + u32 stat; + + stat = readl(SAR_REG_STAT); + while (stat & SAR_STAT_CMDBZ) + stat = readl(SAR_REG_STAT); +} + +static u32 +read_sram(struct idt77252_dev *card, unsigned long addr) +{ + unsigned long flags; + u32 value; + + spin_lock_irqsave(&card->cmd_lock, flags); + writel(SAR_CMD_READ_SRAM | (addr << 2), SAR_REG_CMD); + waitfor_idle(card); + value = readl(SAR_REG_DR0); + spin_unlock_irqrestore(&card->cmd_lock, flags); + return value; +} + +static void +write_sram(struct idt77252_dev *card, unsigned long addr, u32 value) +{ + unsigned long flags; + + if ((idt77252_sram_write_errors == 0) && + (((addr > card->tst[0] + card->tst_size - 2) && + (addr < card->tst[0] + card->tst_size)) || + ((addr > card->tst[1] + card->tst_size - 2) && + (addr < card->tst[1] + card->tst_size)))) { + printk("%s: ERROR: TST JMP section at %08lx written: %08x\n", + card->name, addr, value); + } + + spin_lock_irqsave(&card->cmd_lock, flags); + writel(value, SAR_REG_DR0); + writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD); + waitfor_idle(card); + spin_unlock_irqrestore(&card->cmd_lock, flags); +} + +static u8 +read_utility(void *dev, unsigned long ubus_addr) +{ + struct idt77252_dev *card = dev; + unsigned long flags; + u8 value; + + if (!card) { + printk("Error: No such device.\n"); + return -1; + } + + spin_lock_irqsave(&card->cmd_lock, flags); + writel(SAR_CMD_READ_UTILITY + ubus_addr, SAR_REG_CMD); + waitfor_idle(card); + value = readl(SAR_REG_DR0); + spin_unlock_irqrestore(&card->cmd_lock, flags); + return value; +} + +static void +write_utility(void *dev, unsigned long ubus_addr, u8 value) +{ + struct idt77252_dev *card = dev; + unsigned long flags; + + if (!card) { + printk("Error: No such device.\n"); + return; + } + + spin_lock_irqsave(&card->cmd_lock, flags); + writel((u32) value, SAR_REG_DR0); + writel(SAR_CMD_WRITE_UTILITY + ubus_addr, SAR_REG_CMD); + waitfor_idle(card); + spin_unlock_irqrestore(&card->cmd_lock, flags); +} + +#ifdef HAVE_EEPROM +static u32 rdsrtab[] = +{ + SAR_GP_EECS | SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + SAR_GP_EEDO, + SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ + 0, + SAR_GP_EESCLK, /* 0 */ + SAR_GP_EEDO, + SAR_GP_EESCLK | SAR_GP_EEDO /* 1 */ +}; + +static u32 wrentab[] = +{ + SAR_GP_EECS | SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + SAR_GP_EEDO, + SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ + SAR_GP_EEDO, + SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK /* 0 */ +}; + +static u32 rdtab[] = +{ + SAR_GP_EECS | SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + SAR_GP_EEDO, + SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ + SAR_GP_EEDO, + SAR_GP_EESCLK | SAR_GP_EEDO /* 1 */ +}; + +static u32 wrtab[] = +{ + SAR_GP_EECS | SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + 0, + SAR_GP_EESCLK, /* 0 */ + SAR_GP_EEDO, + SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ + 0, + SAR_GP_EESCLK /* 0 */ +}; + +static u32 clktab[] = +{ + 0, + SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, + 0, + SAR_GP_EESCLK, + 0 +}; + +static u32 +idt77252_read_gp(struct idt77252_dev *card) +{ + u32 gp; + + gp = readl(SAR_REG_GP); +#if 0 + printk("RD: %s\n", gp & SAR_GP_EEDI ? "1" : "0"); +#endif + return gp; +} + +static void +idt77252_write_gp(struct idt77252_dev *card, u32 value) +{ + unsigned long flags; + +#if 0 + printk("WR: %s %s %s\n", value & SAR_GP_EECS ? " " : "/CS", + value & SAR_GP_EESCLK ? "HIGH" : "LOW ", + value & SAR_GP_EEDO ? "1" : "0"); +#endif + + spin_lock_irqsave(&card->cmd_lock, flags); + waitfor_idle(card); + writel(value, SAR_REG_GP); + spin_unlock_irqrestore(&card->cmd_lock, flags); +} + +static u8 +idt77252_eeprom_read_status(struct idt77252_dev *card) +{ + u8 byte; + u32 gp; + int i, j; + + gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); + + for (i = 0; i < sizeof(rdsrtab)/sizeof(rdsrtab[0]); i++) { + idt77252_write_gp(card, gp | rdsrtab[i]); + udelay(5); + } + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); + + byte = 0; + for (i = 0, j = 0; i < 8; i++) { + byte <<= 1; + + idt77252_write_gp(card, gp | clktab[j++]); + udelay(5); + + byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0; + + idt77252_write_gp(card, gp | clktab[j++]); + udelay(5); + } + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); + + return byte; +} + +static u8 +idt77252_eeprom_read_byte(struct idt77252_dev *card, u8 offset) +{ + u8 byte; + u32 gp; + int i, j; + + gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); + + for (i = 0; i < sizeof(rdtab)/sizeof(rdtab[0]); i++) { + idt77252_write_gp(card, gp | rdtab[i]); + udelay(5); + } + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); + + for (i = 0, j = 0; i < 8; i++) { + idt77252_write_gp(card, gp | clktab[j++] | + (offset & 1 ? SAR_GP_EEDO : 0)); + udelay(5); + + idt77252_write_gp(card, gp | clktab[j++] | + (offset & 1 ? SAR_GP_EEDO : 0)); + udelay(5); + + offset >>= 1; + } + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); + + byte = 0; + for (i = 0, j = 0; i < 8; i++) { + byte <<= 1; + + idt77252_write_gp(card, gp | clktab[j++]); + udelay(5); + + byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0; + + idt77252_write_gp(card, gp | clktab[j++]); + udelay(5); + } + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); + + return byte; +} + +static void +idt77252_eeprom_write_byte(struct idt77252_dev *card, u8 offset, u8 data) +{ + u32 gp; + int i, j; + + gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); + + for (i = 0; i < sizeof(wrentab)/sizeof(wrentab[0]); i++) { + idt77252_write_gp(card, gp | wrentab[i]); + udelay(5); + } + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); + + for (i = 0; i < sizeof(wrtab)/sizeof(wrtab[0]); i++) { + idt77252_write_gp(card, gp | wrtab[i]); + udelay(5); + } + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); + + for (i = 0, j = 0; i < 8; i++) { + idt77252_write_gp(card, gp | clktab[j++] | + (offset & 1 ? SAR_GP_EEDO : 0)); + udelay(5); + + idt77252_write_gp(card, gp | clktab[j++] | + (offset & 1 ? SAR_GP_EEDO : 0)); + udelay(5); + + offset >>= 1; + } + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); + + for (i = 0, j = 0; i < 8; i++) { + idt77252_write_gp(card, gp | clktab[j++] | + (data & 1 ? SAR_GP_EEDO : 0)); + udelay(5); + + idt77252_write_gp(card, gp | clktab[j++] | + (data & 1 ? SAR_GP_EEDO : 0)); + udelay(5); + + data >>= 1; + } + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); +} + +static void +idt77252_eeprom_init(struct idt77252_dev *card) +{ + u32 gp; + + gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); + + idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK); + udelay(5); + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); + idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK); + udelay(5); + idt77252_write_gp(card, gp | SAR_GP_EECS); + udelay(5); +} +#endif /* HAVE_EEPROM */ + + +#ifdef DEBUG +static void +dump_tct(struct idt77252_dev *card, int index) +{ + unsigned long tct; + int i; + + tct = (unsigned long) (card->tct_base + index * SAR_SRAM_TCT_SIZE); + + printk("%s: TCT %x:", card->name, index); + for (i = 0; i < 8; i++) { + printk(" %08x", read_sram(card, tct + i)); + } + printk("\n"); +} + +static void +idt77252_tx_dump(struct idt77252_dev *card) +{ + struct atm_vcc *vcc; + struct vc_map *vc; + int i; + + printk("%s\n", __FUNCTION__); + for (i = 0; i < card->tct_size; i++) { + vc = card->vcs[i]; + if (!vc) + continue; + + vcc = NULL; + if (vc->rx_vcc) + vcc = vc->rx_vcc; + else if (vc->tx_vcc) + vcc = vc->tx_vcc; + + if (!vcc) + continue; + + printk("%s: Connection %d:\n", card->name, vc->index); + dump_tct(card, vc->index); + } +} +#endif + + +/*****************************************************************************/ +/* */ +/* SCQ Handling */ +/* */ +/*****************************************************************************/ + +static int +sb_pool_add(struct idt77252_dev *card, struct sk_buff *skb, int queue) +{ + struct sb_pool *pool = &card->sbpool[queue]; + int index; + + index = pool->index; + while (pool->skb[index]) { + index = (index + 1) & FBQ_MASK; + if (index == pool->index) + return -ENOBUFS; + } + + pool->skb[index] = skb; + IDT77252_PRV_POOL(skb) = POOL_HANDLE(queue, index); + + pool->index = (index + 1) & FBQ_MASK; + return 0; +} + +static void +sb_pool_remove(struct idt77252_dev *card, struct sk_buff *skb) +{ + unsigned int queue, index; + u32 handle; + + handle = IDT77252_PRV_POOL(skb); + + queue = POOL_QUEUE(handle); + if (queue > 3) + return; + + index = POOL_INDEX(handle); + if (index > FBQ_SIZE - 1) + return; + + card->sbpool[queue].skb[index] = NULL; +} + +static struct sk_buff * +sb_pool_skb(struct idt77252_dev *card, u32 handle) +{ + unsigned int queue, index; + + queue = POOL_QUEUE(handle); + if (queue > 3) + return NULL; + + index = POOL_INDEX(handle); + if (index > FBQ_SIZE - 1) + return NULL; + + return card->sbpool[queue].skb[index]; +} + +static struct scq_info * +alloc_scq(struct idt77252_dev *card, int class) +{ + struct scq_info *scq; + + scq = (struct scq_info *) kmalloc(sizeof(struct scq_info), GFP_KERNEL); + if (!scq) + return NULL; + memset(scq, 0, sizeof(struct scq_info)); + + scq->base = pci_alloc_consistent(card->pcidev, SCQ_SIZE, + &scq->paddr); + if (scq->base == NULL) { + kfree(scq); + return NULL; + } + memset(scq->base, 0, SCQ_SIZE); + + scq->next = scq->base; + scq->last = scq->base + (SCQ_ENTRIES - 1); + atomic_set(&scq->used, 0); + + spin_lock_init(&scq->lock); + spin_lock_init(&scq->skblock); + + skb_queue_head_init(&scq->transmit); + skb_queue_head_init(&scq->pending); + + TXPRINTK("idt77252: SCQ: base 0x%p, next 0x%p, last 0x%p, paddr %08x\n", + scq->base, scq->next, scq->last, scq->paddr); + + return scq; +} + +static void +free_scq(struct idt77252_dev *card, struct scq_info *scq) +{ + struct sk_buff *skb; + struct atm_vcc *vcc; + + pci_free_consistent(card->pcidev, SCQ_SIZE, + scq->base, scq->paddr); + + while ((skb = skb_dequeue(&scq->transmit))) { + pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), + skb->len, PCI_DMA_TODEVICE); + + vcc = ATM_SKB(skb)->vcc; + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + } + + while ((skb = skb_dequeue(&scq->pending))) { + pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), + skb->len, PCI_DMA_TODEVICE); + + vcc = ATM_SKB(skb)->vcc; + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + } + + kfree(scq); +} + + +static int +push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb) +{ + struct scq_info *scq = vc->scq; + unsigned long flags; + struct scqe *tbd; + int entries; + + TXPRINTK("%s: SCQ: next 0x%p\n", card->name, scq->next); + + atomic_inc(&scq->used); + entries = atomic_read(&scq->used); + if (entries > (SCQ_ENTRIES - 1)) { + atomic_dec(&scq->used); + goto out; + } + + skb_queue_tail(&scq->transmit, skb); + + spin_lock_irqsave(&vc->lock, flags); + if (vc->estimator) { + struct atm_vcc *vcc = vc->tx_vcc; + + vc->estimator->cells += (skb->len + 47) / 48; + if (atomic_read(&vcc->tx_inuse) > (vcc->sk->sndbuf >> 1)) { + u32 cps = vc->estimator->maxcps; + + vc->estimator->cps = cps; + vc->estimator->avcps = cps << 5; + if (vc->lacr < vc->init_er) { + vc->lacr = vc->init_er; + writel(TCMDQ_LACR | (vc->lacr << 16) | + vc->index, SAR_REG_TCMDQ); + } + } + } + spin_unlock_irqrestore(&vc->lock, flags); + + tbd = &IDT77252_PRV_TBD(skb); + + spin_lock_irqsave(&scq->lock, flags); + scq->next->word_1 = cpu_to_le32(tbd->word_1 | + SAR_TBD_TSIF | SAR_TBD_GTSI); + scq->next->word_2 = cpu_to_le32(tbd->word_2); + scq->next->word_3 = cpu_to_le32(tbd->word_3); + scq->next->word_4 = cpu_to_le32(tbd->word_4); + + if (scq->next == scq->last) + scq->next = scq->base; + else + scq->next++; + + write_sram(card, scq->scd, + scq->paddr + + (u32)((unsigned long)scq->next - (unsigned long)scq->base)); + spin_unlock_irqrestore(&scq->lock, flags); + + scq->trans_start = jiffies; + + if (test_and_clear_bit(VCF_IDLE, &vc->flags)) { + writel(TCMDQ_START_LACR | (vc->lacr << 16) | vc->index, + SAR_REG_TCMDQ); + } + + TXPRINTK("%d entries in SCQ used (push).\n", atomic_read(&scq->used)); + + XPRINTK("%s: SCQ (after push %2d) head = 0x%x, next = 0x%p.\n", + card->name, atomic_read(&scq->used), + read_sram(card, scq->scd + 1), scq->next); + + return 0; + +out: + if (jiffies - scq->trans_start > HZ) { + printk("%s: Error pushing TBD for %d.%d\n", + card->name, vc->tx_vcc->vpi, vc->tx_vcc->vci); + idt77252_tx_dump(card); + scq->trans_start = jiffies; + } + + return -ENOBUFS; +} + + +static void +drain_scq(struct idt77252_dev *card, struct vc_map *vc) +{ + struct scq_info *scq = vc->scq; + struct sk_buff *skb; + struct atm_vcc *vcc; + + TXPRINTK("%s: SCQ (before drain %2d) next = 0x%p.\n", + card->name, atomic_read(&scq->used), scq->next); + + skb = skb_dequeue(&scq->transmit); + if (skb) { + TXPRINTK("%s: freeing skb at %p.\n", card->name, skb); + + pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), + skb->len, PCI_DMA_TODEVICE); + + vcc = ATM_SKB(skb)->vcc; + + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + + atomic_inc(&vcc->stats->tx); + } + + atomic_dec(&scq->used); + + spin_lock(&scq->skblock); + while ((skb = skb_dequeue(&scq->pending))) { + if (push_on_scq(card, vc, skb)) { + skb_queue_head(&vc->scq->pending, skb); + break; + } + } + spin_unlock(&scq->skblock); +} + +static int +queue_skb(struct idt77252_dev *card, struct vc_map *vc, + struct sk_buff *skb, int oam) +{ + struct atm_vcc *vcc; + struct scqe *tbd; + unsigned long flags; + int error; + int aal; + + if (skb->len == 0) { + printk("%s: invalid skb->len (%d)\n", card->name, skb->len); + return -EINVAL; + } + + TXPRINTK("%s: Sending %d bytes of data.\n", + card->name, skb->len); + + tbd = &IDT77252_PRV_TBD(skb); + vcc = ATM_SKB(skb)->vcc; + + IDT77252_PRV_PADDR(skb) = pci_map_single(card->pcidev, skb->data, + skb->len, PCI_DMA_TODEVICE); + + error = -EINVAL; + + if (oam) { + if (skb->len != 52) + goto errout; + + tbd->word_1 = SAR_TBD_OAM | ATM_CELL_PAYLOAD | SAR_TBD_EPDU; + tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4; + tbd->word_3 = 0x00000000; + tbd->word_4 = (skb->data[0] << 24) | (skb->data[1] << 16) | + (skb->data[2] << 8) | (skb->data[3] << 0); + + if (test_bit(VCF_RSV, &vc->flags)) + vc = card->vcs[0]; + + goto done; + } + + if (test_bit(VCF_RSV, &vc->flags)) { + printk("%s: Trying to transmit on reserved VC\n", card->name); + goto errout; + } + + aal = vcc->qos.aal; + + switch (aal) { + case ATM_AAL0: + case ATM_AAL34: + if (skb->len > 52) + goto errout; + + if (aal == ATM_AAL0) + tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL0 | + ATM_CELL_PAYLOAD; + else + tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL34 | + ATM_CELL_PAYLOAD; + + tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4; + tbd->word_3 = 0x00000000; + tbd->word_4 = (skb->data[0] << 24) | (skb->data[1] << 16) | + (skb->data[2] << 8) | (skb->data[3] << 0); + break; + + case ATM_AAL5: + tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL5 | skb->len; + tbd->word_2 = IDT77252_PRV_PADDR(skb); + tbd->word_3 = skb->len; + tbd->word_4 = (vcc->vpi << SAR_TBD_VPI_SHIFT) | + (vcc->vci << SAR_TBD_VCI_SHIFT); + break; + + case ATM_AAL1: + case ATM_AAL2: + default: + printk("%s: Traffic type not supported.\n", card->name); + error = -EPROTONOSUPPORT; + goto errout; + } + +done: + spin_lock_irqsave(&vc->scq->skblock, flags); + skb_queue_tail(&vc->scq->pending, skb); + + while ((skb = skb_dequeue(&vc->scq->pending))) { + if (push_on_scq(card, vc, skb)) { + skb_queue_head(&vc->scq->pending, skb); + break; + } + } + spin_unlock_irqrestore(&vc->scq->skblock, flags); + + return 0; + +errout: + pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), + skb->len, PCI_DMA_TODEVICE); + return error; +} + +static unsigned long +get_free_scd(struct idt77252_dev *card, struct vc_map *vc) +{ + int i; + + for (i = 0; i < card->scd_size; i++) { + if (!card->scd2vc[i]) { + card->scd2vc[i] = vc; + vc->scd_index = i; + return card->scd_base + i * SAR_SRAM_SCD_SIZE; + } + } + return 0; +} + +static void +fill_scd(struct idt77252_dev *card, struct scq_info *scq, int class) +{ + write_sram(card, scq->scd, scq->paddr); + write_sram(card, scq->scd + 1, 0x00000000); + write_sram(card, scq->scd + 2, 0xffffffff); + write_sram(card, scq->scd + 3, 0x00000000); +} + +static void +clear_scd(struct idt77252_dev *card, struct scq_info *scq, int class) +{ + return; +} + +/*****************************************************************************/ +/* */ +/* RSQ Handling */ +/* */ +/*****************************************************************************/ + +static int +init_rsq(struct idt77252_dev *card) +{ + struct rsq_entry *rsqe; + + card->rsq.base = pci_alloc_consistent(card->pcidev, RSQSIZE, + &card->rsq.paddr); + if (card->rsq.base == NULL) { + printk("%s: can't allocate RSQ.\n", card->name); + return -1; + } + memset(card->rsq.base, 0, RSQSIZE); + + card->rsq.last = card->rsq.base + RSQ_NUM_ENTRIES - 1; + card->rsq.next = card->rsq.last; + for (rsqe = card->rsq.base; rsqe <= card->rsq.last; rsqe++) + rsqe->word_4 = 0; + + writel((unsigned long) card->rsq.last - (unsigned long) card->rsq.base, + SAR_REG_RSQH); + writel(card->rsq.paddr, SAR_REG_RSQB); + + IPRINTK("%s: RSQ base at 0x%lx (0x%x).\n", card->name, + (unsigned long) card->rsq.base, + readl(SAR_REG_RSQB)); + IPRINTK("%s: RSQ head = 0x%x, base = 0x%x, tail = 0x%x.\n", + card->name, + readl(SAR_REG_RSQH), + readl(SAR_REG_RSQB), + readl(SAR_REG_RSQT)); + + return 0; +} + +static void +deinit_rsq(struct idt77252_dev *card) +{ + pci_free_consistent(card->pcidev, RSQSIZE, + card->rsq.base, card->rsq.paddr); +} + +static void +dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) +{ + struct atm_vcc *vcc; + struct sk_buff *skb; + struct rx_pool *rpp; + struct vc_map *vc; + u32 header, vpi, vci; + u32 stat; + int i; + + stat = le32_to_cpu(rsqe->word_4); + + if (stat & SAR_RSQE_IDLE) { + RXPRINTK("%s: message about inactive connection.\n", + card->name); + return; + } + + skb = sb_pool_skb(card, le32_to_cpu(rsqe->word_2)); + if (skb == NULL) { + printk("%s: NULL skb in %s, rsqe: %08x %08x %08x %08x\n", + card->name, __FUNCTION__, + le32_to_cpu(rsqe->word_1), le32_to_cpu(rsqe->word_2), + le32_to_cpu(rsqe->word_3), le32_to_cpu(rsqe->word_4)); + return; + } + + header = le32_to_cpu(rsqe->word_1); + vpi = (header >> 16) & 0x00ff; + vci = (header >> 0) & 0xffff; + + RXPRINTK("%s: SDU for %d.%d received in buffer 0x%p (data 0x%p).\n", + card->name, vpi, vci, skb, skb->data); + + if ((vpi >= (1 << card->vpibits)) || (vci != (vci & card->vcimask))) { + printk("%s: SDU received for out-of-range vc %u.%u\n", + card->name, vpi, vci); + recycle_rx_skb(card, skb); + return; + } + + vc = card->vcs[VPCI2VC(card, vpi, vci)]; + if (!vc || !test_bit(VCF_RX, &vc->flags)) { + printk("%s: SDU received on non RX vc %u.%u\n", + card->name, vpi, vci); + recycle_rx_skb(card, skb); + return; + } + + vcc = vc->rx_vcc; + + pci_dma_sync_single(card->pcidev, IDT77252_PRV_PADDR(skb), + skb->end - skb->data, PCI_DMA_FROMDEVICE); + + if ((vcc->qos.aal == ATM_AAL0) || + (vcc->qos.aal == ATM_AAL34)) { + struct sk_buff *sb; + unsigned char *cell; + u32 aal0; + + cell = skb->data; + for (i = (stat & SAR_RSQE_CELLCNT); i; i--) { + if ((sb = dev_alloc_skb(64)) == NULL) { + printk("%s: Can't allocate buffers for aal0.\n", + card->name); + atomic_add(i, &vcc->stats->rx_drop); + break; + } + if (!atm_charge(vcc, sb->truesize)) { + RXPRINTK("%s: atm_charge() dropped aal0 packets.\n", + card->name); + atomic_add(i - 1, &vcc->stats->rx_drop); + dev_kfree_skb(sb); + break; + } + aal0 = (vpi << ATM_HDR_VPI_SHIFT) | + (vci << ATM_HDR_VCI_SHIFT); + aal0 |= (stat & SAR_RSQE_EPDU) ? 0x00000002 : 0; + aal0 |= (stat & SAR_RSQE_CLP) ? 0x00000001 : 0; + + *((u32 *) sb->data) = aal0; + skb_put(sb, sizeof(u32)); + memcpy(skb_put(sb, ATM_CELL_PAYLOAD), + cell, ATM_CELL_PAYLOAD); + + ATM_SKB(sb)->vcc = vcc; + sb->stamp = xtime; + vcc->push(vcc, sb); + atomic_inc(&vcc->stats->rx); + + cell += ATM_CELL_PAYLOAD; + } + + recycle_rx_skb(card, skb); + return; + } + if (vcc->qos.aal != ATM_AAL5) { + printk("%s: Unexpected AAL type in dequeue_rx(): %d.\n", + card->name, vcc->qos.aal); + recycle_rx_skb(card, skb); + return; + } + skb->len = (stat & SAR_RSQE_CELLCNT) * ATM_CELL_PAYLOAD; + + rpp = &vc->rcv.rx_pool; + + rpp->len += skb->len; + if (!rpp->count++) + rpp->first = skb; + *rpp->last = skb; + rpp->last = &IDT77252_PRV_NEXT(skb); + + if (stat & SAR_RSQE_EPDU) { + unsigned char *l1l2; + unsigned int len; + + l1l2 = (unsigned char *) ((unsigned long) skb->data + skb->len - 6); + + len = (l1l2[0] << 8) | l1l2[1]; + len = len ? len : 0x10000; + + RXPRINTK("%s: PDU has %d bytes.\n", card->name, len); + + if ((len + 8 > rpp->len) || (len + (47 + 8) < rpp->len)) { + RXPRINTK("%s: AAL5 PDU size mismatch: %d != %d. " + "(CDC: %08x)\n", + card->name, len, rpp->len, readl(SAR_REG_CDC)); + recycle_rx_pool_skb(card, rpp); + atomic_inc(&vcc->stats->rx_err); + return; + } + if (stat & SAR_RSQE_CRC) { + RXPRINTK("%s: AAL5 CRC error.\n", card->name); + recycle_rx_pool_skb(card, rpp); + atomic_inc(&vcc->stats->rx_err); + return; + } + if (rpp->count > 1) { + struct sk_buff *sb; + + skb = dev_alloc_skb(rpp->len); + if (!skb) { + RXPRINTK("%s: Can't alloc RX skb.\n", + card->name); + recycle_rx_pool_skb(card, rpp); + atomic_inc(&vcc->stats->rx_err); + return; + } + if (!atm_charge(vcc, skb->truesize)) { + recycle_rx_pool_skb(card, rpp); + dev_kfree_skb(skb); + return; + } + sb = rpp->first; + for (i = 0; i < rpp->count; i++) { + memcpy(skb_put(skb, sb->len), + sb->data, sb->len); + sb = IDT77252_PRV_NEXT(sb); + } + + recycle_rx_pool_skb(card, rpp); + + skb_trim(skb, len); + ATM_SKB(skb)->vcc = vcc; + skb->stamp = xtime; + + vcc->push(vcc, skb); + atomic_inc(&vcc->stats->rx); + + return; + } + flush_rx_pool(card, rpp); + + if (!atm_charge(vcc, skb->truesize)) { + recycle_rx_skb(card, skb); + return; + } + + pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), + skb->end - skb->data, PCI_DMA_FROMDEVICE); + sb_pool_remove(card, skb); + + skb_trim(skb, len); + ATM_SKB(skb)->vcc = vcc; + skb->stamp = xtime; + + vcc->push(vcc, skb); + atomic_inc(&vcc->stats->rx); + + if (skb->truesize > SAR_FB_SIZE_3) + add_rx_skb(card, 3, SAR_FB_SIZE_3, 1); + else if (skb->truesize > SAR_FB_SIZE_2) + add_rx_skb(card, 2, SAR_FB_SIZE_2, 1); + else if (skb->truesize > SAR_FB_SIZE_1) + add_rx_skb(card, 1, SAR_FB_SIZE_1, 1); + else + add_rx_skb(card, 0, SAR_FB_SIZE_0, 1); + return; + } +} + +static void +idt77252_rx(struct idt77252_dev *card) +{ + struct rsq_entry *rsqe; + + if (card->rsq.next == card->rsq.last) + rsqe = card->rsq.base; + else + rsqe = card->rsq.next + 1; + + if (!(le32_to_cpu(rsqe->word_4) & SAR_RSQE_VALID)) { + RXPRINTK("%s: no entry in RSQ.\n", card->name); + return; + } + + do { + dequeue_rx(card, rsqe); + rsqe->word_4 = 0; + card->rsq.next = rsqe; + if (card->rsq.next == card->rsq.last) + rsqe = card->rsq.base; + else + rsqe = card->rsq.next + 1; + } while (le32_to_cpu(rsqe->word_4) & SAR_RSQE_VALID); + + writel((unsigned long) card->rsq.next - (unsigned long) card->rsq.base, + SAR_REG_RSQH); +} + +static void +idt77252_rx_raw(struct idt77252_dev *card) +{ + struct sk_buff *queue; + u32 head, tail; + struct atm_vcc *vcc; + struct vc_map *vc; + struct sk_buff *sb; + + if (card->raw_cell_head == NULL) { + u32 handle = le32_to_cpu(*(card->raw_cell_hnd + 1)); + card->raw_cell_head = sb_pool_skb(card, handle); + } + + queue = card->raw_cell_head; + if (!queue) + return; + + head = IDT77252_PRV_PADDR(queue) + (queue->data - queue->head - 16); + tail = readl(SAR_REG_RAWCT); + + pci_dma_sync_single(card->pcidev, IDT77252_PRV_PADDR(queue), + queue->end - queue->head - 16, PCI_DMA_FROMDEVICE); + + while (head != tail) { + unsigned int vpi, vci, pti; + u32 header; + + header = le32_to_cpu(*(u32 *) &queue->data[0]); + + vpi = (header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; + vci = (header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; + pti = (header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; + +#ifdef DEBUG_RAW_CELLS +{ + int i; + + printk("%s: raw cell %x.%02x.%04x.%x.%x\n", + card->name, (header >> 28) & 0x000f, + (header >> 20) & 0x00ff, + (header >> 4) & 0xffff, + (header >> 1) & 0x0007, + (header >> 0) & 0x0001); + for (i = 16; i < 64; i++) + printk(" %02x", queue->data[i]); + printk("\n"); +} +#endif + if (vpi >= (1<<card->vpibits) || vci >= (1<<card->vcibits)) { +#ifdef DEBUG_RAW_CELLS + printk("%s: SDU received for out-of-range vc %u.%u\n", + card->name, vpi, vci); +#endif + goto drop; + } + + vc = card->vcs[VPCI2VC(card, vpi, vci)]; + if (!vc || !test_bit(VCF_RX, &vc->flags)) { +#ifdef DEBUG_RAW_CELLS + printk("%s: SDU received on non RX vc %u.%u\n", + card->name, vpi, vci); +#endif + goto drop; + } + + vcc = vc->rx_vcc; + + if (vcc->qos.aal != ATM_AAL0) { +#ifdef DEBUG_RAW_CELLS + printk("%s: raw cell for non AAL0 vc %u.%u\n", + card->name, vpi, vci); +#endif + atomic_inc(&vcc->stats->rx_drop); + goto drop; + } + + if ((sb = dev_alloc_skb(64)) == NULL) { + printk("%s: Can't allocate buffers for AAL0.\n", + card->name); + atomic_inc(&vcc->stats->rx_err); + goto drop; + } + + if ((vcc->sk != NULL) && !atm_charge(vcc, sb->truesize)) { + RXPRINTK("%s: atm_charge() dropped AAL0 packets.\n", + card->name); + dev_kfree_skb(sb); + goto drop; + } + + *((u32 *) sb->data) = header; + skb_put(sb, sizeof(u32)); + memcpy(skb_put(sb, ATM_CELL_PAYLOAD), &(queue->data[16]), + ATM_CELL_PAYLOAD); + + ATM_SKB(sb)->vcc = vcc; + sb->stamp = xtime; + vcc->push(vcc, sb); + atomic_inc(&vcc->stats->rx); + +drop: + skb_pull(queue, 64); + + head = IDT77252_PRV_PADDR(queue) + + (queue->data - queue->head - 16); + + if (queue->len < 128) { + struct sk_buff *next; + u32 handle; + + head = le32_to_cpu(*(u32 *) &queue->data[0]); + handle = le32_to_cpu(*(u32 *) &queue->data[4]); + + next = sb_pool_skb(card, handle); + recycle_rx_skb(card, queue); + + if (next) { + card->raw_cell_head = next; + queue = card->raw_cell_head; + pci_dma_sync_single(card->pcidev, + IDT77252_PRV_PADDR(queue), + queue->end - queue->data, + PCI_DMA_FROMDEVICE); + } else { + card->raw_cell_head = NULL; + printk("%s: raw cell queue overrun\n", + card->name); + break; + } + } + } +} + + +/*****************************************************************************/ +/* */ +/* TSQ Handling */ +/* */ +/*****************************************************************************/ + +static int +init_tsq(struct idt77252_dev *card) +{ + struct tsq_entry *tsqe; + + card->tsq.base = pci_alloc_consistent(card->pcidev, RSQSIZE, + &card->tsq.paddr); + if (card->tsq.base == NULL) { + printk("%s: can't allocate TSQ.\n", card->name); + return -1; + } + memset(card->tsq.base, 0, TSQSIZE); + + card->tsq.last = card->tsq.base + TSQ_NUM_ENTRIES - 1; + card->tsq.next = card->tsq.last; + for (tsqe = card->tsq.base; tsqe <= card->tsq.last; tsqe++) + tsqe->word_2 = cpu_to_le32(SAR_TSQE_INVALID); + + writel(card->tsq.paddr, SAR_REG_TSQB); + writel((unsigned long) card->tsq.next - (unsigned long) card->tsq.base, + SAR_REG_TSQH); + + return 0; +} + +static void +deinit_tsq(struct idt77252_dev *card) +{ + pci_free_consistent(card->pcidev, TSQSIZE, + card->tsq.base, card->tsq.paddr); +} + +static void +idt77252_tx(struct idt77252_dev *card) +{ + struct tsq_entry *tsqe; + unsigned int vpi, vci; + struct vc_map *vc; + u32 conn, stat; + + if (card->tsq.next == card->tsq.last) + tsqe = card->tsq.base; + else + tsqe = card->tsq.next + 1; + + TXPRINTK("idt77252_tx: tsq %p: base %p, next %p, last %p\n", tsqe, + card->tsq.base, card->tsq.next, card->tsq.last); + TXPRINTK("idt77252_tx: tsqb %08x, tsqt %08x, tsqh %08x, \n", + readl(SAR_REG_TSQB), + readl(SAR_REG_TSQT), + readl(SAR_REG_TSQH)); + + stat = le32_to_cpu(tsqe->word_2); + + if (stat & SAR_TSQE_INVALID) + return; + + do { + TXPRINTK("tsqe: 0x%p [0x%08x 0x%08x]\n", tsqe, + le32_to_cpu(tsqe->word_1), + le32_to_cpu(tsqe->word_2)); + + switch (stat & SAR_TSQE_TYPE) { + case SAR_TSQE_TYPE_TIMER: + TXPRINTK("%s: Timer RollOver detected.\n", card->name); + break; + + case SAR_TSQE_TYPE_IDLE: + + conn = le32_to_cpu(tsqe->word_1); + + if (SAR_TSQE_TAG(stat) == 0x10) { +#ifdef NOTDEF + printk("%s: Connection %d halted.\n", + card->name, + le32_to_cpu(tsqe->word_1) & 0x1fff); +#endif + break; + } + + vc = card->vcs[conn & 0x1fff]; + if (!vc) { + printk("%s: could not find VC from conn %d\n", + card->name, conn & 0x1fff); + break; + } + + printk("%s: Connection %d IDLE.\n", + card->name, vc->index); + + set_bit(VCF_IDLE, &vc->flags); + break; + + case SAR_TSQE_TYPE_TSR: + + conn = le32_to_cpu(tsqe->word_1); + + vc = card->vcs[conn & 0x1fff]; + if (!vc) { + printk("%s: no VC at index %d\n", + card->name, + le32_to_cpu(tsqe->word_1) & 0x1fff); + break; + } + + drain_scq(card, vc); + break; + + case SAR_TSQE_TYPE_TBD_COMP: + + conn = le32_to_cpu(tsqe->word_1); + + vpi = (conn >> SAR_TBD_VPI_SHIFT) & 0x00ff; + vci = (conn >> SAR_TBD_VCI_SHIFT) & 0xffff; + + if (vpi >= (1 << card->vpibits) || + vci >= (1 << card->vcibits)) { + printk("%s: TBD complete: " + "out of range VPI.VCI %u.%u\n", + card->name, vpi, vci); + break; + } + + vc = card->vcs[VPCI2VC(card, vpi, vci)]; + if (!vc) { + printk("%s: TBD complete: " + "no VC at VPI.VCI %u.%u\n", + card->name, vpi, vci); + break; + } + + drain_scq(card, vc); + break; + } + + tsqe->word_2 = cpu_to_le32(SAR_TSQE_INVALID); + + card->tsq.next = tsqe; + if (card->tsq.next == card->tsq.last) + tsqe = card->tsq.base; + else + tsqe = card->tsq.next + 1; + + TXPRINTK("tsqe: %p: base %p, next %p, last %p\n", tsqe, + card->tsq.base, card->tsq.next, card->tsq.last); + + stat = le32_to_cpu(tsqe->word_2); + + } while (!(stat & SAR_TSQE_INVALID)); + + writel((unsigned long)card->tsq.next - (unsigned long)card->tsq.base, + SAR_REG_TSQH); + + XPRINTK("idt77252_tx-after writel%d: TSQ head = 0x%x, tail = 0x%x, next = 0x%p.\n", + card->index, readl(SAR_REG_TSQH), + readl(SAR_REG_TSQT), card->tsq.next); +} + + +static void +tst_timer(unsigned long data) +{ + struct idt77252_dev *card = (struct idt77252_dev *)data; + unsigned long base, idle, jump; + unsigned long flags; + u32 pc; + int e; + + spin_lock_irqsave(&card->tst_lock, flags); + + base = card->tst[card->tst_index]; + idle = card->tst[card->tst_index ^ 1]; + + if (test_bit(TST_SWITCH_WAIT, &card->tst_state)) { + jump = base + card->tst_size - 2; + + pc = readl(SAR_REG_NOW) >> 2; + if ((pc ^ idle) & ~(card->tst_size - 1)) { + mod_timer(&card->tst_timer, jiffies + 1); + goto out; + } + + clear_bit(TST_SWITCH_WAIT, &card->tst_state); + + card->tst_index ^= 1; + write_sram(card, jump, TSTE_OPC_JMP | (base << 2)); + + base = card->tst[card->tst_index]; + idle = card->tst[card->tst_index ^ 1]; + + for (e = 0; e < card->tst_size - 2; e++) { + if (card->soft_tst[e].tste & TSTE_PUSH_IDLE) { + write_sram(card, idle + e, + card->soft_tst[e].tste & TSTE_MASK); + card->soft_tst[e].tste &= ~(TSTE_PUSH_IDLE); + } + } + } + + if (test_and_clear_bit(TST_SWITCH_PENDING, &card->tst_state)) { + + for (e = 0; e < card->tst_size - 2; e++) { + if (card->soft_tst[e].tste & TSTE_PUSH_ACTIVE) { + write_sram(card, idle + e, + card->soft_tst[e].tste & TSTE_MASK); + card->soft_tst[e].tste &= ~(TSTE_PUSH_ACTIVE); + card->soft_tst[e].tste |= TSTE_PUSH_IDLE; + } + } + + jump = base + card->tst_size - 2; + + write_sram(card, jump, TSTE_OPC_NULL); + set_bit(TST_SWITCH_WAIT, &card->tst_state); + + mod_timer(&card->tst_timer, jiffies + 1); + } + +out: + spin_unlock_irqrestore(&card->tst_lock, flags); +} + +static int +__fill_tst(struct idt77252_dev *card, struct vc_map *vc, + int n, unsigned int opc) +{ + unsigned long cl, avail; + unsigned long idle; + int e, r; + u32 data; + + avail = card->tst_size - 2; + for (e = 0; e < avail; e++) { + if (card->soft_tst[e].vc == NULL) + break; + } + if (e >= avail) { + printk("%s: No free TST entries found\n", card->name); + return -1; + } + + NPRINTK("%s: conn %d: first TST entry at %d.\n", + card->name, vc ? vc->index : -1, e); + + r = n; + cl = avail; + data = opc & TSTE_OPC_MASK; + if (vc && (opc != TSTE_OPC_NULL)) + data = opc | vc->index; + + idle = card->tst[card->tst_index ^ 1]; + + /* + * Fill Soft TST. + */ + while (r > 0) { + if ((cl >= avail) && (card->soft_tst[e].vc == NULL)) { + if (vc) + card->soft_tst[e].vc = vc; + else + card->soft_tst[e].vc = (void *)-1; + + card->soft_tst[e].tste = data; + if (timer_pending(&card->tst_timer)) + card->soft_tst[e].tste |= TSTE_PUSH_ACTIVE; + else { + write_sram(card, idle + e, data); + card->soft_tst[e].tste |= TSTE_PUSH_IDLE; + } + + cl -= card->tst_size; + r--; + } + + if (++e == avail) + e = 0; + cl += n; + } + + return 0; +} + +static int +fill_tst(struct idt77252_dev *card, struct vc_map *vc, int n, unsigned int opc) +{ + unsigned long flags; + int res; + + spin_lock_irqsave(&card->tst_lock, flags); + + res = __fill_tst(card, vc, n, opc); + + set_bit(TST_SWITCH_PENDING, &card->tst_state); + if (!timer_pending(&card->tst_timer)) + mod_timer(&card->tst_timer, jiffies + 1); + + spin_unlock_irqrestore(&card->tst_lock, flags); + return res; +} + +static int +__clear_tst(struct idt77252_dev *card, struct vc_map *vc) +{ + unsigned long idle; + int e; + + idle = card->tst[card->tst_index ^ 1]; + + for (e = 0; e < card->tst_size - 2; e++) { + if (card->soft_tst[e].vc == vc) { + card->soft_tst[e].vc = NULL; + + card->soft_tst[e].tste = TSTE_OPC_VAR; + if (timer_pending(&card->tst_timer)) + card->soft_tst[e].tste |= TSTE_PUSH_ACTIVE; + else { + write_sram(card, idle + e, TSTE_OPC_VAR); + card->soft_tst[e].tste |= TSTE_PUSH_IDLE; + } + } + } + + return 0; +} + +static int +clear_tst(struct idt77252_dev *card, struct vc_map *vc) +{ + unsigned long flags; + int res; + + spin_lock_irqsave(&card->tst_lock, flags); + + res = __clear_tst(card, vc); + + set_bit(TST_SWITCH_PENDING, &card->tst_state); + if (!timer_pending(&card->tst_timer)) + mod_timer(&card->tst_timer, jiffies + 1); + + spin_unlock_irqrestore(&card->tst_lock, flags); + return res; +} + +static int +change_tst(struct idt77252_dev *card, struct vc_map *vc, + int n, unsigned int opc) +{ + unsigned long flags; + int res; + + spin_lock_irqsave(&card->tst_lock, flags); + + __clear_tst(card, vc); + res = __fill_tst(card, vc, n, opc); + + set_bit(TST_SWITCH_PENDING, &card->tst_state); + if (!timer_pending(&card->tst_timer)) + mod_timer(&card->tst_timer, jiffies + 1); + + spin_unlock_irqrestore(&card->tst_lock, flags); + return res; +} + + +static int +set_tct(struct idt77252_dev *card, struct vc_map *vc) +{ + unsigned long tct; + + tct = (unsigned long) (card->tct_base + vc->index * SAR_SRAM_TCT_SIZE); + + switch (vc->class) { + case SCHED_CBR: + OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n", + card->name, tct, vc->scq->scd); + + write_sram(card, tct + 0, TCT_CBR | vc->scq->scd); + write_sram(card, tct + 1, 0); + write_sram(card, tct + 2, 0); + write_sram(card, tct + 3, 0); + write_sram(card, tct + 4, 0); + write_sram(card, tct + 5, 0); + write_sram(card, tct + 6, 0); + write_sram(card, tct + 7, 0); + break; + + case SCHED_UBR: + OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n", + card->name, tct, vc->scq->scd); + + write_sram(card, tct + 0, TCT_UBR | vc->scq->scd); + write_sram(card, tct + 1, 0); + write_sram(card, tct + 2, TCT_TSIF); + write_sram(card, tct + 3, TCT_HALT | TCT_IDLE); + write_sram(card, tct + 4, 0); + write_sram(card, tct + 5, vc->init_er); + write_sram(card, tct + 6, 0); + write_sram(card, tct + 7, TCT_FLAG_UBR); + break; + + case SCHED_VBR: + case SCHED_ABR: + default: + return -ENOSYS; + } + + return 0; +} + +/*****************************************************************************/ +/* */ +/* FBQ Handling */ +/* */ +/*****************************************************************************/ + +static __inline__ int +idt77252_fbq_level(struct idt77252_dev *card, int queue) +{ + return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) & 0x0f; +} + +static __inline__ int +idt77252_fbq_full(struct idt77252_dev *card, int queue) +{ + return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) == 0x0f; +} + +static int +push_rx_skb(struct idt77252_dev *card, struct sk_buff *skb, int queue) +{ + unsigned long flags; + u32 handle; + u32 addr; + + skb->data = skb->tail = skb->head; + skb->len = 0; + + skb_reserve(skb, 16); + + switch (queue) { + case 0: + skb_put(skb, SAR_FB_SIZE_0); + break; + case 1: + skb_put(skb, SAR_FB_SIZE_1); + break; + case 2: + skb_put(skb, SAR_FB_SIZE_2); + break; + case 3: + skb_put(skb, SAR_FB_SIZE_3); + break; + default: + dev_kfree_skb(skb); + return -1; + } + + if (idt77252_fbq_full(card, queue)) + return -1; + + memset(&skb->data[(skb->len & ~(0x3f)) - 64], 0, 2 * sizeof(u32)); + + handle = IDT77252_PRV_POOL(skb); + addr = IDT77252_PRV_PADDR(skb); + + spin_lock_irqsave(&card->cmd_lock, flags); + writel(handle, card->fbq[queue]); + writel(addr, card->fbq[queue]); + spin_unlock_irqrestore(&card->cmd_lock, flags); + + return 0; +} + +static void +add_rx_skb(struct idt77252_dev *card, int queue, + unsigned int size, unsigned int count) +{ + struct sk_buff *skb; + dma_addr_t paddr; + u32 handle; + + while (count--) { + skb = dev_alloc_skb(size); + if (!skb) + return; + + if (sb_pool_add(card, skb, queue)) { + printk("%s: SB POOL full\n", __FUNCTION__); + goto outfree; + } + + paddr = pci_map_single(card->pcidev, skb->data, + skb->end - skb->data, + PCI_DMA_FROMDEVICE); + IDT77252_PRV_PADDR(skb) = paddr; + + if (push_rx_skb(card, skb, queue)) { + printk("%s: FB QUEUE full\n", __FUNCTION__); + goto outunmap; + } + } + + return; + +outunmap: + pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), + skb->end - skb->data, PCI_DMA_FROMDEVICE); + + handle = IDT77252_PRV_POOL(skb); + card->sbpool[POOL_QUEUE(handle)].skb[POOL_INDEX(handle)] = NULL; + +outfree: + dev_kfree_skb(skb); +} + + +static void +recycle_rx_skb(struct idt77252_dev *card, struct sk_buff *skb) +{ + u32 handle = IDT77252_PRV_POOL(skb); + int err; + + err = push_rx_skb(card, skb, POOL_QUEUE(handle)); + if (err) { + pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), + skb->end - skb->data, PCI_DMA_FROMDEVICE); + sb_pool_remove(card, skb); + dev_kfree_skb(skb); + } +} + +static void +flush_rx_pool(struct idt77252_dev *card, struct rx_pool *rpp) +{ + rpp->len = 0; + rpp->count = 0; + rpp->first = NULL; + rpp->last = &rpp->first; +} + +static void +recycle_rx_pool_skb(struct idt77252_dev *card, struct rx_pool *rpp) +{ + struct sk_buff *skb, *next; + int i; + + skb = rpp->first; + for (i = 0; i < rpp->count; i++) { + next = IDT77252_PRV_NEXT(skb); + recycle_rx_skb(card, skb); + skb = next; + } + flush_rx_pool(card, rpp); +} + +/*****************************************************************************/ +/* */ +/* ATM Interface */ +/* */ +/*****************************************************************************/ + +static void +idt77252_phy_put(struct atm_dev *dev, unsigned char value, unsigned long addr) +{ + write_utility(dev->dev_data, 0x100 + (addr & 0x1ff), value); +} + +static unsigned char +idt77252_phy_get(struct atm_dev *dev, unsigned long addr) +{ + return read_utility(dev->dev_data, 0x100 + (addr & 0x1ff)); +} + +static int +idt77252_send_skb(struct atm_vcc *vcc, struct sk_buff *skb, int oam) +{ + struct atm_dev *dev = vcc->dev; + struct idt77252_dev *card = dev->dev_data; + struct vc_map *vc = vcc->dev_data; + int err; + + if (vc == NULL) { + printk("%s: NULL connection in send().\n", card->name); + atomic_inc(&vcc->stats->tx_err); + dev_kfree_skb(skb); + return -EINVAL; + } + if (!test_bit(VCF_TX, &vc->flags)) { + printk("%s: Trying to transmit on a non-tx VC.\n", card->name); + atomic_inc(&vcc->stats->tx_err); + dev_kfree_skb(skb); + return -EINVAL; + } + + switch (vcc->qos.aal) { + case ATM_AAL0: + case ATM_AAL1: + case ATM_AAL5: + break; + default: + printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal); + atomic_inc(&vcc->stats->tx_err); + dev_kfree_skb(skb); + return -EINVAL; + } + + if (ATM_SKB(skb)->iovcnt != 0) { + printk("%s: No scatter-gather yet.\n", card->name); + atomic_inc(&vcc->stats->tx_err); + dev_kfree_skb(skb); + return -EINVAL; + } + ATM_SKB(skb)->vcc = vcc; + + err = queue_skb(card, vc, skb, oam); + if (err) { + atomic_inc(&vcc->stats->tx_err); + dev_kfree_skb(skb); + return err; + } + + return 0; +} + +int +idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + return idt77252_send_skb(vcc, skb, 0); +} + +static int +idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags) +{ + struct atm_dev *dev = vcc->dev; + struct idt77252_dev *card = dev->dev_data; + struct sk_buff *skb; + + skb = dev_alloc_skb(64); + if (!skb) { + printk("%s: Out of memory in send_oam().\n", card->name); + atomic_inc(&vcc->stats->tx_err); + return -ENOMEM; + } + atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse); + ATM_SKB(skb)->iovcnt = 0; + + memcpy(skb_put(skb, 52), cell, 52); + + return idt77252_send_skb(vcc, skb, 1); +} + +static __inline__ unsigned int +idt77252_fls(unsigned int x) +{ + int r = 1; + + if (x == 0) + return 0; + if (x & 0xffff0000) { + x >>= 16; + r += 16; + } + if (x & 0xff00) { + x >>= 8; + r += 8; + } + if (x & 0xf0) { + x >>= 4; + r += 4; + } + if (x & 0xc) { + x >>= 2; + r += 2; + } + if (x & 0x2) + r += 1; + return r; +} + +static u16 +idt77252_int_to_atmfp(unsigned int rate) +{ + u16 m, e; + + if (rate == 0) + return 0; + e = idt77252_fls(rate) - 1; + if (e < 9) + m = (rate - (1 << e)) << (9 - e); + else if (e == 9) + m = (rate - (1 << e)); + else /* e > 9 */ + m = (rate - (1 << e)) >> (e - 9); + return 0x4000 | (e << 9) | m; +} + +static u8 +idt77252_rate_logindex(struct idt77252_dev *card, int pcr) +{ + u16 afp; + + afp = idt77252_int_to_atmfp(pcr < 0 ? -pcr : pcr); + if (pcr < 0) + return rate_to_log[(afp >> 5) & 0x1ff]; + return rate_to_log[((afp >> 5) + 1) & 0x1ff]; +} + +static void +idt77252_est_timer(unsigned long data) +{ + struct vc_map *vc = (struct vc_map *)data; + struct idt77252_dev *card = vc->card; + struct rate_estimator *est; + unsigned long flags; + u32 rate, cps; + u64 ncells; + u8 lacr; + + spin_lock_irqsave(&vc->lock, flags); + est = vc->estimator; + if (!est) + goto out; + + ncells = est->cells; + + rate = ((u32)(ncells - est->last_cells)) << (7 - est->interval); + est->last_cells = ncells; + est->avcps += ((long)rate - (long)est->avcps) >> est->ewma_log; + est->cps = (est->avcps + 0x1f) >> 5; + + cps = est->cps; + if (cps < (est->maxcps >> 4)) + cps = est->maxcps >> 4; + + lacr = idt77252_rate_logindex(card, cps); + if (lacr > vc->max_er) + lacr = vc->max_er; + + if (lacr != vc->lacr) { + vc->lacr = lacr; + writel(TCMDQ_LACR|(vc->lacr << 16)|vc->index, SAR_REG_TCMDQ); + } + + est->timer.expires = jiffies + ((HZ / 4) << est->interval); + add_timer(&est->timer); + +out: + spin_unlock_irqrestore(&vc->lock, flags); +} + +static struct rate_estimator * +idt77252_init_est(struct vc_map *vc, int pcr) +{ + struct rate_estimator *est; + + est = kmalloc(sizeof(struct rate_estimator), GFP_KERNEL); + if (!est) + return NULL; + memset(est, 0, sizeof(*est)); + + est->maxcps = pcr < 0 ? -pcr : pcr; + est->cps = est->maxcps; + est->avcps = est->cps << 5; + + est->interval = 2; /* XXX: make this configurable */ + est->ewma_log = 2; /* XXX: make this configurable */ + est->timer.data = (unsigned long)vc; + est->timer.function = idt77252_est_timer; + init_timer(&est->timer); + + est->timer.expires = jiffies + ((HZ / 4) << est->interval); + add_timer(&est->timer); + + return est; +} + +static int +idt77252_init_cbr(struct idt77252_dev *card, struct vc_map *vc, + struct atm_vcc *vcc, struct atm_qos *qos) +{ + int tst_free, tst_used, tst_entries; + unsigned long tmpl, modl; + int tcr, tcra; + + if ((qos->txtp.max_pcr == 0) && + (qos->txtp.pcr == 0) && (qos->txtp.min_pcr == 0)) { + printk("%s: trying to open a CBR VC with cell rate = 0\n", + card->name); + return -EINVAL; + } + + tst_used = 0; + tst_free = card->tst_free; + if (test_bit(VCF_TX, &vc->flags)) + tst_used = vc->ntste; + tst_free += tst_used; + + tcr = atm_pcr_goal(&qos->txtp); + tcra = tcr >= 0 ? tcr : -tcr; + + TXPRINTK("%s: CBR target cell rate = %d\n", card->name, tcra); + + tmpl = (unsigned long) tcra * ((unsigned long) card->tst_size - 2); + modl = tmpl % (unsigned long)card->utopia_pcr; + + tst_entries = (int) (tmpl / card->utopia_pcr); + if (tcr > 0) { + if (modl > 0) + tst_entries++; + } else if (tcr == 0) { + tst_entries = tst_free - SAR_TST_RESERVED; + if (tst_entries <= 0) { + printk("%s: no CBR bandwidth free.\n", card->name); + return -ENOSR; + } + } + + if (tst_entries == 0) { + printk("%s: selected CBR bandwidth < granularity.\n", + card->name); + return -EINVAL; + } + + if (tst_entries > (tst_free - SAR_TST_RESERVED)) { + printk("%s: not enough CBR bandwidth free.\n", card->name); + return -ENOSR; + } + + vc->ntste = tst_entries; + + card->tst_free = tst_free - tst_entries; + if (test_bit(VCF_TX, &vc->flags)) { + if (tst_used == tst_entries) + return 0; + + OPRINTK("%s: modify %d -> %d entries in TST.\n", + card->name, tst_used, tst_entries); + change_tst(card, vc, tst_entries, TSTE_OPC_CBR); + return 0; + } + + OPRINTK("%s: setting %d entries in TST.\n", card->name, tst_entries); + fill_tst(card, vc, tst_entries, TSTE_OPC_CBR); + return 0; +} + +static int +idt77252_init_ubr(struct idt77252_dev *card, struct vc_map *vc, + struct atm_vcc *vcc, struct atm_qos *qos) +{ + unsigned long flags; + int tcr; + + spin_lock_irqsave(&vc->lock, flags); + if (vc->estimator) { + del_timer(&vc->estimator->timer); + kfree(vc->estimator); + vc->estimator = NULL; + } + spin_unlock_irqrestore(&vc->lock, flags); + + tcr = atm_pcr_goal(&qos->txtp); + if (tcr == 0) + tcr = card->link_pcr; + + vc->estimator = idt77252_init_est(vc, tcr); + + vc->class = SCHED_UBR; + vc->init_er = idt77252_rate_logindex(card, tcr); + vc->lacr = vc->init_er; + if (tcr < 0) + vc->max_er = vc->init_er; + else + vc->max_er = 0xff; + + return 0; +} + +static int +idt77252_init_tx(struct idt77252_dev *card, struct vc_map *vc, + struct atm_vcc *vcc, struct atm_qos *qos) +{ + int error; + + if (test_bit(VCF_TX, &vc->flags)) + return -EBUSY; + + switch (qos->txtp.traffic_class) { + case ATM_CBR: + vc->class = SCHED_CBR; + break; + + case ATM_UBR: + vc->class = SCHED_UBR; + break; + + case ATM_VBR: + case ATM_ABR: + default: + return -EPROTONOSUPPORT; + } + + vc->scq = alloc_scq(card, vc->class); + if (!vc->scq) { + printk("%s: can't get SCQ.\n", card->name); + return -ENOMEM; + } + + vc->scq->scd = get_free_scd(card, vc); + if (vc->scq->scd == 0) { + printk("%s: no SCD available.\n", card->name); + free_scq(card, vc->scq); + return -ENOMEM; + } + + fill_scd(card, vc->scq, vc->class); + + if (set_tct(card, vc)) { + printk("%s: class %d not supported.\n", + card->name, qos->txtp.traffic_class); + + card->scd2vc[vc->scd_index] = NULL; + free_scq(card, vc->scq); + return -EPROTONOSUPPORT; + } + + switch (vc->class) { + case SCHED_CBR: + error = idt77252_init_cbr(card, vc, vcc, qos); + if (error) { + card->scd2vc[vc->scd_index] = NULL; + free_scq(card, vc->scq); + return error; + } + + clear_bit(VCF_IDLE, &vc->flags); + writel(TCMDQ_START | vc->index, SAR_REG_TCMDQ); + break; + + case SCHED_UBR: + error = idt77252_init_ubr(card, vc, vcc, qos); + if (error) { + card->scd2vc[vc->scd_index] = NULL; + free_scq(card, vc->scq); + return error; + } + + set_bit(VCF_IDLE, &vc->flags); + break; + } + + vc->tx_vcc = vcc; + set_bit(VCF_TX, &vc->flags); + return 0; +} + +static int +idt77252_init_rx(struct idt77252_dev *card, struct vc_map *vc, + struct atm_vcc *vcc, struct atm_qos *qos) +{ + unsigned long flags; + unsigned long addr; + u32 rcte = 0; + + if (test_bit(VCF_RX, &vc->flags)) + return -EBUSY; + + vc->rx_vcc = vcc; + set_bit(VCF_RX, &vc->flags); + + if ((vcc->vci == 3) || (vcc->vci == 4)) + return 0; + + flush_rx_pool(card, &vc->rcv.rx_pool); + + rcte |= SAR_RCTE_CONNECTOPEN; + rcte |= SAR_RCTE_RAWCELLINTEN; + + switch (qos->aal) { + case ATM_AAL0: + rcte |= SAR_RCTE_RCQ; + break; + case ATM_AAL1: + rcte |= SAR_RCTE_OAM; /* Let SAR drop Video */ + break; + case ATM_AAL34: + rcte |= SAR_RCTE_AAL34; + break; + case ATM_AAL5: + rcte |= SAR_RCTE_AAL5; + break; + default: + rcte |= SAR_RCTE_RCQ; + break; + } + + if (qos->aal != ATM_AAL5) + rcte |= SAR_RCTE_FBP_1; + else if (qos->rxtp.max_sdu > SAR_FB_SIZE_2) + rcte |= SAR_RCTE_FBP_3; + else if (qos->rxtp.max_sdu > SAR_FB_SIZE_1) + rcte |= SAR_RCTE_FBP_2; + else if (qos->rxtp.max_sdu > SAR_FB_SIZE_0) + rcte |= SAR_RCTE_FBP_1; + else + rcte |= SAR_RCTE_FBP_01; + + addr = card->rct_base + (vc->index << 2); + + OPRINTK("%s: writing RCT at 0x%lx\n", card->name, addr); + write_sram(card, addr, rcte); + + spin_lock_irqsave(&card->cmd_lock, flags); + writel(SAR_CMD_OPEN_CONNECTION | (addr << 2), SAR_REG_CMD); + waitfor_idle(card); + spin_unlock_irqrestore(&card->cmd_lock, flags); + + return 0; +} + +static int +idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci) +{ + struct atm_vcc *walk; + + if (*vpi == ATM_VPI_ANY) { + *vpi = 0; + walk = vcc->dev->vccs; + while (walk) { + if ((walk->vci == *vci) && (walk->vpi == *vpi)) { + (*vpi)++; + walk = vcc->dev->vccs; + continue; + } + walk = walk->next; + } + } + + if (*vci == ATM_VCI_ANY) { + *vci = ATM_NOT_RSV_VCI; + walk = vcc->dev->vccs; + while (walk) { + if ((walk->vci == *vci) && (walk->vpi == *vpi)) { + (*vci)++; + walk = vcc->dev->vccs; + continue; + } + walk = walk->next; + } + } + + return 0; +} + +static int +idt77252_open(struct atm_vcc *vcc, short vpi, int vci) +{ + struct atm_dev *dev = vcc->dev; + struct idt77252_dev *card = dev->dev_data; + struct vc_map *vc; + unsigned int index; + unsigned int inuse; + int error; + + idt77252_find_vcc(vcc, &vpi, &vci); + + if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) + return 0; + + if (vpi >= (1 << card->vpibits)) { + printk("%s: unsupported VPI: %d\n", card->name, vpi); + return -EINVAL; + } + + if (vci >= (1 << card->vcibits)) { + printk("%s: unsupported VCI: %d\n", card->name, vci); + return -EINVAL; + } + + vcc->vpi = vpi; + vcc->vci = vci; + set_bit(ATM_VF_ADDR, &vcc->flags); + + down(&card->mutex); + + OPRINTK("%s: opening vpi.vci: %d.%d\n", card->name, vpi, vci); + + switch (vcc->qos.aal) { + case ATM_AAL0: + case ATM_AAL1: + case ATM_AAL5: + break; + default: + printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal); + up(&card->mutex); + return -EPROTONOSUPPORT; + } + + index = VPCI2VC(card, vpi, vci); + if (!card->vcs[index]) { + card->vcs[index] = kmalloc(sizeof(struct vc_map), GFP_KERNEL); + if (!card->vcs[index]) { + printk("%s: can't alloc vc in open()\n", card->name); + up(&card->mutex); + return -ENOMEM; + } + memset(card->vcs[index], 0, sizeof(struct vc_map)); + + card->vcs[index]->card = card; + card->vcs[index]->index = index; + + spin_lock_init(&card->vcs[index]->lock); + } + vc = card->vcs[index]; + + vcc->dev_data = vc; + + IPRINTK("%s: idt77252_open: vc = %d (%d.%d) %s/%s (max RX SDU: %u)\n", + card->name, vc->index, vcc->vpi, vcc->vci, + vcc->qos.rxtp.traffic_class != ATM_NONE ? "rx" : "--", + vcc->qos.txtp.traffic_class != ATM_NONE ? "tx" : "--", + vcc->qos.rxtp.max_sdu); + + inuse = 0; + if (vcc->qos.txtp.traffic_class != ATM_NONE && + test_bit(VCF_TX, &vc->flags)) + inuse = 1; + if (vcc->qos.rxtp.traffic_class != ATM_NONE && + test_bit(VCF_RX, &vc->flags)) + inuse += 2; + + if (inuse) { + printk("%s: %s vci already in use.\n", card->name, + inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); + up(&card->mutex); + return -EADDRINUSE; + } + + if (vcc->qos.txtp.traffic_class != ATM_NONE) { + error = idt77252_init_tx(card, vc, vcc, &vcc->qos); + if (error) { + up(&card->mutex); + return error; + } + } + + if (vcc->qos.rxtp.traffic_class != ATM_NONE) { + error = idt77252_init_rx(card, vc, vcc, &vcc->qos); + if (error) { + up(&card->mutex); + return error; + } + } + + set_bit(ATM_VF_READY, &vcc->flags); + MOD_INC_USE_COUNT; + + up(&card->mutex); + return 0; +} + +static void +idt77252_close(struct atm_vcc *vcc) +{ + struct atm_dev *dev = vcc->dev; + struct idt77252_dev *card = dev->dev_data; + struct vc_map *vc = vcc->dev_data; + unsigned long flags; + unsigned long addr; + int timeout; + + down(&card->mutex); + + IPRINTK("%s: idt77252_close: vc = %d (%d.%d)\n", + card->name, vc->index, vcc->vpi, vcc->vci); + + clear_bit(ATM_VF_READY, &vcc->flags); + + if (vcc->qos.rxtp.traffic_class != ATM_NONE) { + + spin_lock_irqsave(&vc->lock, flags); + clear_bit(VCF_RX, &vc->flags); + vc->rx_vcc = NULL; + spin_unlock_irqrestore(&vc->lock, flags); + + if ((vcc->vci == 3) || (vcc->vci == 4)) + goto done; + + addr = card->rct_base + vc->index * SAR_SRAM_RCT_SIZE; + + spin_lock_irqsave(&card->cmd_lock, flags); + writel(SAR_CMD_CLOSE_CONNECTION | (addr << 2), SAR_REG_CMD); + waitfor_idle(card); + spin_unlock_irqrestore(&card->cmd_lock, flags); + + if (vc->rcv.rx_pool.count) { + DPRINTK("%s: closing a VC with pending rx buffers.\n", + card->name); + + recycle_rx_pool_skb(card, &vc->rcv.rx_pool); + } + } + +done: + if (vcc->qos.txtp.traffic_class != ATM_NONE) { + + spin_lock_irqsave(&vc->lock, flags); + clear_bit(VCF_TX, &vc->flags); + clear_bit(VCF_IDLE, &vc->flags); + clear_bit(VCF_RSV, &vc->flags); + vc->tx_vcc = NULL; + + if (vc->estimator) { + del_timer(&vc->estimator->timer); + kfree(vc->estimator); + vc->estimator = NULL; + } + spin_unlock_irqrestore(&vc->lock, flags); + + timeout = 5 * HZ; + while (atomic_read(&vc->scq->used) > 0) { + timeout = schedule_timeout(timeout); + if (!timeout) + break; + } + if (!timeout) + printk("%s: SCQ drain timeout: %u used\n", + card->name, atomic_read(&vc->scq->used)); + + writel(TCMDQ_HALT | vc->index, SAR_REG_TCMDQ); + clear_scd(card, vc->scq, vc->class); + + if (vc->class == SCHED_CBR) { + clear_tst(card, vc); + card->tst_free += vc->ntste; + vc->ntste = 0; + } + + card->scd2vc[vc->scd_index] = NULL; + free_scq(card, vc->scq); + } + + MOD_DEC_USE_COUNT; + up(&card->mutex); +} + +static int +idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags) +{ + struct atm_dev *dev = vcc->dev; + struct idt77252_dev *card = dev->dev_data; + struct vc_map *vc = vcc->dev_data; + int error = 0; + + down(&card->mutex); + + if (qos->txtp.traffic_class != ATM_NONE) { + if (!test_bit(VCF_TX, &vc->flags)) { + error = idt77252_init_tx(card, vc, vcc, qos); + if (error) + goto out; + } else { + switch (qos->txtp.traffic_class) { + case ATM_CBR: + error = idt77252_init_cbr(card, vc, vcc, qos); + if (error) + goto out; + break; + + case ATM_UBR: + error = idt77252_init_ubr(card, vc, vcc, qos); + if (error) + goto out; + + if (!test_bit(VCF_IDLE, &vc->flags)) { + writel(TCMDQ_LACR | (vc->lacr << 16) | + vc->index, SAR_REG_TCMDQ); + } + break; + + case ATM_VBR: + case ATM_ABR: + error = -EOPNOTSUPP; + goto out; + } + } + } + + if ((qos->rxtp.traffic_class != ATM_NONE) && + !test_bit(VCF_RX, &vc->flags)) { + error = idt77252_init_rx(card, vc, vcc, qos); + if (error) + goto out; + } + + memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); + + set_bit(ATM_VF_HASQOS, &vcc->flags); + +out: + up(&card->mutex); + return error; +} + +static int +idt77252_proc_read(struct atm_dev *dev, loff_t * pos, char *page) +{ + struct idt77252_dev *card = dev->dev_data; + int i, left; + + left = (int) *pos; + if (!left--) + return sprintf(page, "IDT77252 Interrupts:\n"); + if (!left--) + return sprintf(page, "TSIF: %u\n", card->irqstat[15]); + if (!left--) + return sprintf(page, "TXICP: %u\n", card->irqstat[14]); + if (!left--) + return sprintf(page, "TSQF: %u\n", card->irqstat[12]); + if (!left--) + return sprintf(page, "TMROF: %u\n", card->irqstat[11]); + if (!left--) + return sprintf(page, "PHYI: %u\n", card->irqstat[10]); + if (!left--) + return sprintf(page, "FBQ3A: %u\n", card->irqstat[8]); + if (!left--) + return sprintf(page, "FBQ2A: %u\n", card->irqstat[7]); + if (!left--) + return sprintf(page, "RSQF: %u\n", card->irqstat[6]); + if (!left--) + return sprintf(page, "EPDU: %u\n", card->irqstat[5]); + if (!left--) + return sprintf(page, "RAWCF: %u\n", card->irqstat[4]); + if (!left--) + return sprintf(page, "FBQ1A: %u\n", card->irqstat[3]); + if (!left--) + return sprintf(page, "FBQ0A: %u\n", card->irqstat[2]); + if (!left--) + return sprintf(page, "RSQAF: %u\n", card->irqstat[1]); + if (!left--) + return sprintf(page, "IDT77252 Transmit Connection Table:\n"); + + for (i = 0; i < card->tct_size; i++) { + unsigned long tct; + struct atm_vcc *vcc; + struct vc_map *vc; + char *p; + + vc = card->vcs[i]; + if (!vc) + continue; + + vcc = NULL; + if (vc->tx_vcc) + vcc = vc->tx_vcc; + if (!vcc) + continue; + if (left--) + continue; + + p = page; + p += sprintf(p, " %4u: %u.%u: ", i, vcc->vpi, vcc->vci); + tct = (unsigned long) (card->tct_base + i * SAR_SRAM_TCT_SIZE); + + for (i = 0; i < 8; i++) + p += sprintf(p, " %08x", read_sram(card, tct + i)); + p += sprintf(p, "\n"); + return p - page; + } + return 0; +} + +/*****************************************************************************/ +/* */ +/* Interrupt handler */ +/* */ +/*****************************************************************************/ + +static void +idt77252_collect_stat(struct idt77252_dev *card) +{ + u32 cdc, vpec, icc; + + cdc = readl(SAR_REG_CDC); + vpec = readl(SAR_REG_VPEC); + icc = readl(SAR_REG_ICC); + +#ifdef NOTDEF + printk("%s:", card->name); + + if (cdc & 0x7f0000) { + char *s = ""; + + printk(" ["); + if (cdc & (1 << 22)) { + printk("%sRM ID", s); + s = " | "; + } + if (cdc & (1 << 21)) { + printk("%sCON TAB", s); + s = " | "; + } + if (cdc & (1 << 20)) { + printk("%sNO FB", s); + s = " | "; + } + if (cdc & (1 << 19)) { + printk("%sOAM CRC", s); + s = " | "; + } + if (cdc & (1 << 18)) { + printk("%sRM CRC", s); + s = " | "; + } + if (cdc & (1 << 17)) { + printk("%sRM FIFO", s); + s = " | "; + } + if (cdc & (1 << 16)) { + printk("%sRX FIFO", s); + s = " | "; + } + printk("]"); + } + + printk(" CDC %04x, VPEC %04x, ICC: %04x\n", + cdc & 0xffff, vpec & 0xffff, icc & 0xffff); +#endif +} + +static void +idt77252_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) +{ + struct idt77252_dev *card = dev_id; + u32 stat; + + stat = readl(SAR_REG_STAT) & 0xffff; + if (!stat) /* no interrupt for us */ + return; + + if (test_and_set_bit(IDT77252_BIT_INTERRUPT, &card->flags)) { + printk("%s: Re-entering irq_handler()\n", card->name); + goto out; + } + + writel(stat, SAR_REG_STAT); /* reset interrupt */ + + if (stat & SAR_STAT_TSIF) { /* entry written to TSQ */ + INTPRINTK("%s: TSIF\n", card->name); + card->irqstat[15]++; + idt77252_tx(card); + } + if (stat & SAR_STAT_TXICP) { /* Incomplete CS-PDU has */ + INTPRINTK("%s: TXICP\n", card->name); + card->irqstat[14]++; +#ifdef DEBUG + idt77252_tx_dump(card); +#endif + } + if (stat & SAR_STAT_TSQF) { /* TSQ 7/8 full */ + INTPRINTK("%s: TSQF\n", card->name); + card->irqstat[12]++; + idt77252_tx(card); + } + if (stat & SAR_STAT_TMROF) { /* Timer overflow */ + INTPRINTK("%s: TMROF\n", card->name); + card->irqstat[11]++; + idt77252_collect_stat(card); + } + + if (stat & SAR_STAT_EPDU) { /* Got complete CS-PDU */ + INTPRINTK("%s: EPDU\n", card->name); + card->irqstat[5]++; + idt77252_rx(card); + } + if (stat & SAR_STAT_RSQAF) { /* RSQ is 7/8 full */ + INTPRINTK("%s: RSQAF\n", card->name); + card->irqstat[1]++; + idt77252_rx(card); + } + if (stat & SAR_STAT_RSQF) { /* RSQ is full */ + INTPRINTK("%s: RSQF\n", card->name); + card->irqstat[6]++; + idt77252_rx(card); + } + if (stat & SAR_STAT_RAWCF) { /* Raw cell received */ + INTPRINTK("%s: RAWCF\n", card->name); + card->irqstat[4]++; + idt77252_rx_raw(card); + } + + if (stat & SAR_STAT_PHYI) { /* PHY device interrupt */ + INTPRINTK("%s: PHYI", card->name); + card->irqstat[10]++; + if (card->atmdev->phy && card->atmdev->phy->interrupt) + card->atmdev->phy->interrupt(card->atmdev); + } + + if (stat & (SAR_STAT_FBQ0A | SAR_STAT_FBQ1A | + SAR_STAT_FBQ2A | SAR_STAT_FBQ3A)) { + + writel(readl(SAR_REG_CFG) & ~(SAR_CFG_FBIE), SAR_REG_CFG); + + INTPRINTK("%s: FBQA: %04x\n", card->name, stat); + + if (stat & SAR_STAT_FBQ0A) + card->irqstat[2]++; + if (stat & SAR_STAT_FBQ1A) + card->irqstat[3]++; + if (stat & SAR_STAT_FBQ2A) + card->irqstat[7]++; + if (stat & SAR_STAT_FBQ3A) + card->irqstat[8]++; + + queue_task(&card->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + +out: + clear_bit(IDT77252_BIT_INTERRUPT, &card->flags); +} + +static void +idt77252_softint(void *dev_id) +{ + struct idt77252_dev *card = dev_id; + u32 stat; + int done; + + for (done = 1; ; done = 1) { + stat = readl(SAR_REG_STAT) >> 16; + + if ((stat & 0x0f) < SAR_FBQ0_HIGH) { + add_rx_skb(card, 0, SAR_FB_SIZE_0, 32); + done = 0; + } + + stat >>= 4; + if ((stat & 0x0f) < SAR_FBQ1_HIGH) { + add_rx_skb(card, 1, SAR_FB_SIZE_1, 32); + done = 0; + } + + stat >>= 4; + if ((stat & 0x0f) < SAR_FBQ2_HIGH) { + add_rx_skb(card, 2, SAR_FB_SIZE_2, 32); + done = 0; + } + + stat >>= 4; + if ((stat & 0x0f) < SAR_FBQ3_HIGH) { + add_rx_skb(card, 3, SAR_FB_SIZE_3, 32); + done = 0; + } + + if (done) + break; + } + + writel(readl(SAR_REG_CFG) | SAR_CFG_FBIE, SAR_REG_CFG); +} + + +static int +open_card_oam(struct idt77252_dev *card) +{ + unsigned long flags; + unsigned long addr; + struct vc_map *vc; + int vpi, vci; + int index; + u32 rcte; + + for (vpi = 0; vpi < (1 << card->vpibits); vpi++) { + for (vci = 3; vci < 5; vci++) { + index = VPCI2VC(card, vpi, vci); + + vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL); + if (!vc) { + printk("%s: can't alloc vc\n", card->name); + return -ENOMEM; + } + memset(vc, 0, sizeof(struct vc_map)); + + vc->index = index; + card->vcs[index] = vc; + + flush_rx_pool(card, &vc->rcv.rx_pool); + + rcte = SAR_RCTE_CONNECTOPEN | + SAR_RCTE_RAWCELLINTEN | + SAR_RCTE_RCQ | + SAR_RCTE_FBP_1; + + addr = card->rct_base + (vc->index << 2); + write_sram(card, addr, rcte); + + spin_lock_irqsave(&card->cmd_lock, flags); + writel(SAR_CMD_OPEN_CONNECTION | (addr << 2), + SAR_REG_CMD); + waitfor_idle(card); + spin_unlock_irqrestore(&card->cmd_lock, flags); + } + } + + return 0; +} + +static void +close_card_oam(struct idt77252_dev *card) +{ + unsigned long flags; + unsigned long addr; + struct vc_map *vc; + int vpi, vci; + int index; + + for (vpi = 0; vpi < (1 << card->vpibits); vpi++) { + for (vci = 3; vci < 5; vci++) { + index = VPCI2VC(card, vpi, vci); + vc = card->vcs[index]; + + addr = card->rct_base + vc->index * SAR_SRAM_RCT_SIZE; + + spin_lock_irqsave(&card->cmd_lock, flags); + writel(SAR_CMD_CLOSE_CONNECTION | (addr << 2), + SAR_REG_CMD); + waitfor_idle(card); + spin_unlock_irqrestore(&card->cmd_lock, flags); + + if (vc->rcv.rx_pool.count) { + DPRINTK("%s: closing a VC " + "with pending rx buffers.\n", + card->name); + + recycle_rx_pool_skb(card, &vc->rcv.rx_pool); + } + } + } +} + +static int +open_card_ubr0(struct idt77252_dev *card) +{ + struct vc_map *vc; + + vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL); + if (!vc) { + printk("%s: can't alloc vc\n", card->name); + return -ENOMEM; + } + memset(vc, 0, sizeof(struct vc_map)); + card->vcs[0] = vc; + vc->class = SCHED_UBR0; + + vc->scq = alloc_scq(card, vc->class); + if (!vc->scq) { + printk("%s: can't get SCQ.\n", card->name); + return -ENOMEM; + } + + card->scd2vc[0] = vc; + vc->scd_index = 0; + vc->scq->scd = card->scd_base; + + fill_scd(card, vc->scq, vc->class); + + write_sram(card, card->tct_base + 0, TCT_UBR | card->scd_base); + write_sram(card, card->tct_base + 1, 0); + write_sram(card, card->tct_base + 2, 0); + write_sram(card, card->tct_base + 3, 0); + write_sram(card, card->tct_base + 4, 0); + write_sram(card, card->tct_base + 5, 0); + write_sram(card, card->tct_base + 6, 0); + write_sram(card, card->tct_base + 7, TCT_FLAG_UBR); + + clear_bit(VCF_IDLE, &vc->flags); + writel(TCMDQ_START | 0, SAR_REG_TCMDQ); + return 0; +} + +static int +idt77252_dev_open(struct idt77252_dev *card) +{ + u32 conf; + + if (!test_bit(IDT77252_BIT_INIT, &card->flags)) { + printk("%s: SAR not yet initialized.\n", card->name); + return -1; + } + + conf = SAR_CFG_RXPTH| /* enable receive path */ + SAR_RX_DELAY | /* interrupt on complete PDU */ + SAR_CFG_RAWIE | /* interrupt enable on raw cells */ + SAR_CFG_RQFIE | /* interrupt on RSQ almost full */ + SAR_CFG_TMOIE | /* interrupt on timer overflow */ + SAR_CFG_FBIE | /* interrupt on low free buffers */ + SAR_CFG_TXEN | /* transmit operation enable */ + SAR_CFG_TXINT | /* interrupt on transmit status */ + SAR_CFG_TXUIE | /* interrupt on transmit underrun */ + SAR_CFG_TXSFI | /* interrupt on TSQ almost full */ + SAR_CFG_PHYIE /* enable PHY interrupts */ + ; + +#ifdef CONFIG_ATM_IDT77252_RCV_ALL + /* Test RAW cell receive. */ + conf |= SAR_CFG_VPECA; +#endif + + writel(readl(SAR_REG_CFG) | conf, SAR_REG_CFG); + + if (open_card_oam(card)) { + printk("%s: Error initializing OAM.\n", card->name); + return -1; + } + + if (open_card_ubr0(card)) { + printk("%s: Error initializing UBR0.\n", card->name); + return -1; + } + + IPRINTK("%s: opened IDT77252 ABR SAR.\n", card->name); + return 0; +} + +void +idt77252_dev_close(struct atm_dev *dev) +{ + struct idt77252_dev *card = dev->dev_data; + u32 conf; + + close_card_oam(card); + + conf = SAR_CFG_RXPTH | /* enable receive path */ + SAR_RX_DELAY | /* interrupt on complete PDU */ + SAR_CFG_RAWIE | /* interrupt enable on raw cells */ + SAR_CFG_RQFIE | /* interrupt on RSQ almost full */ + SAR_CFG_TMOIE | /* interrupt on timer overflow */ + SAR_CFG_FBIE | /* interrupt on low free buffers */ + SAR_CFG_TXEN | /* transmit operation enable */ + SAR_CFG_TXINT | /* interrupt on transmit status */ + SAR_CFG_TXUIE | /* interrupt on xmit underrun */ + SAR_CFG_TXSFI /* interrupt on TSQ almost full */ + ; + + writel(readl(SAR_REG_CFG) & ~(conf), SAR_REG_CFG); + + DIPRINTK("%s: closed IDT77252 ABR SAR.\n", card->name); +} + + +/*****************************************************************************/ +/* */ +/* Initialisation and Deinitialization of IDT77252 */ +/* */ +/*****************************************************************************/ + + +static void +deinit_card(struct idt77252_dev *card) +{ + struct sk_buff *skb; + int i, j; + + if (!test_bit(IDT77252_BIT_INIT, &card->flags)) { + printk("%s: SAR not yet initialized.\n", card->name); + return; + } + DIPRINTK("idt77252: deinitialize card %u\n", card->index); + + writel(0, SAR_REG_CFG); + + if (card->atmdev) + atm_dev_deregister(card->atmdev); + + for (i = 0; i < 4; i++) { + for (j = 0; j < FBQ_SIZE; j++) { + skb = card->sbpool[i].skb[j]; + if (skb) { + pci_unmap_single(card->pcidev, + IDT77252_PRV_PADDR(skb), + skb->end - skb->data, + PCI_DMA_FROMDEVICE); + card->sbpool[i].skb[j] = NULL; + dev_kfree_skb(skb); + } + } + } + + if (card->soft_tst) + vfree(card->soft_tst); + + if (card->scd2vc) + vfree(card->scd2vc); + + if (card->vcs) + vfree(card->vcs); + + if (card->raw_cell_hnd) { + pci_free_consistent(card->pcidev, 2 * sizeof(u32), + card->raw_cell_hnd, card->raw_cell_paddr); + } + + if (card->rsq.base) { + DIPRINTK("%s: Release RSQ ...\n", card->name); + deinit_rsq(card); + } + + if (card->tsq.base) { + DIPRINTK("%s: Release TSQ ...\n", card->name); + deinit_tsq(card); + } + + DIPRINTK("idt77252: Release IRQ.\n"); + free_irq(card->pcidev->irq, card); + + for (i = 0; i < 4; i++) { + if (card->fbq[i]) + iounmap((void *) card->fbq[i]); + } + + if (card->membase) + iounmap((void *) card->membase); + + clear_bit(IDT77252_BIT_INIT, &card->flags); + DIPRINTK("%s: Card deinitialized.\n", card->name); +} + + +static int +init_sram(struct idt77252_dev *card) +{ + int i; + + for (i = 0; i < card->sramsize; i += 4) + write_sram(card, (i >> 2), 0); + + /* set SRAM layout for THIS card */ + if (card->sramsize == (512 * 1024)) { + card->tct_base = SAR_SRAM_TCT_128_BASE; + card->tct_size = (SAR_SRAM_TCT_128_TOP - card->tct_base + 1) + / SAR_SRAM_TCT_SIZE; + card->rct_base = SAR_SRAM_RCT_128_BASE; + card->rct_size = (SAR_SRAM_RCT_128_TOP - card->rct_base + 1) + / SAR_SRAM_RCT_SIZE; + card->rt_base = SAR_SRAM_RT_128_BASE; + card->scd_base = SAR_SRAM_SCD_128_BASE; + card->scd_size = (SAR_SRAM_SCD_128_TOP - card->scd_base + 1) + / SAR_SRAM_SCD_SIZE; + card->tst[0] = SAR_SRAM_TST1_128_BASE; + card->tst[1] = SAR_SRAM_TST2_128_BASE; + card->tst_size = SAR_SRAM_TST1_128_TOP - card->tst[0] + 1; + card->abrst_base = SAR_SRAM_ABRSTD_128_BASE; + card->abrst_size = SAR_ABRSTD_SIZE_8K; + card->fifo_base = SAR_SRAM_FIFO_128_BASE; + card->fifo_size = SAR_RXFD_SIZE_32K; + } else { + card->tct_base = SAR_SRAM_TCT_32_BASE; + card->tct_size = (SAR_SRAM_TCT_32_TOP - card->tct_base + 1) + / SAR_SRAM_TCT_SIZE; + card->rct_base = SAR_SRAM_RCT_32_BASE; + card->rct_size = (SAR_SRAM_RCT_32_TOP - card->rct_base + 1) + / SAR_SRAM_RCT_SIZE; + card->rt_base = SAR_SRAM_RT_32_BASE; + card->scd_base = SAR_SRAM_SCD_32_BASE; + card->scd_size = (SAR_SRAM_SCD_32_TOP - card->scd_base + 1) + / SAR_SRAM_SCD_SIZE; + card->tst[0] = SAR_SRAM_TST1_32_BASE; + card->tst[1] = SAR_SRAM_TST2_32_BASE; + card->tst_size = (SAR_SRAM_TST1_32_TOP - card->tst[0] + 1); + card->abrst_base = SAR_SRAM_ABRSTD_32_BASE; + card->abrst_size = SAR_ABRSTD_SIZE_1K; + card->fifo_base = SAR_SRAM_FIFO_32_BASE; + card->fifo_size = SAR_RXFD_SIZE_4K; + } + + /* Initialize TCT */ + for (i = 0; i < card->tct_size; i++) { + write_sram(card, i * SAR_SRAM_TCT_SIZE + 0, 0); + write_sram(card, i * SAR_SRAM_TCT_SIZE + 1, 0); + write_sram(card, i * SAR_SRAM_TCT_SIZE + 2, 0); + write_sram(card, i * SAR_SRAM_TCT_SIZE + 3, 0); + write_sram(card, i * SAR_SRAM_TCT_SIZE + 4, 0); + write_sram(card, i * SAR_SRAM_TCT_SIZE + 5, 0); + write_sram(card, i * SAR_SRAM_TCT_SIZE + 6, 0); + write_sram(card, i * SAR_SRAM_TCT_SIZE + 7, 0); + } + + /* Initialize RCT */ + for (i = 0; i < card->rct_size; i++) { + write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE, + (u32) SAR_RCTE_RAWCELLINTEN); + write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 1, + (u32) 0); + write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 2, + (u32) 0); + write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 3, + (u32) 0xffffffff); + } + + writel((SAR_FBQ0_LOW << 28) | 0x00000000 | 0x00000000 | + (SAR_FB_SIZE_0 / 48), SAR_REG_FBQS0); + writel((SAR_FBQ1_LOW << 28) | 0x00000000 | 0x00000000 | + (SAR_FB_SIZE_1 / 48), SAR_REG_FBQS1); + writel((SAR_FBQ2_LOW << 28) | 0x00000000 | 0x00000000 | + (SAR_FB_SIZE_2 / 48), SAR_REG_FBQS2); + writel((SAR_FBQ3_LOW << 28) | 0x00000000 | 0x00000000 | + (SAR_FB_SIZE_3 / 48), SAR_REG_FBQS3); + + /* Initialize rate table */ + for (i = 0; i < 256; i++) { + write_sram(card, card->rt_base + i, log_to_rate[i]); + } + + for (i = 0; i < 128; i++) { + unsigned int tmp; + + tmp = rate_to_log[(i << 2) + 0] << 0; + tmp |= rate_to_log[(i << 2) + 1] << 8; + tmp |= rate_to_log[(i << 2) + 2] << 16; + tmp |= rate_to_log[(i << 2) + 3] << 24; + write_sram(card, card->rt_base + 256 + i, tmp); + } + +#if 0 /* Fill RDF and AIR tables. */ + for (i = 0; i < 128; i++) { + unsigned int tmp; + + tmp = RDF[0][(i << 1) + 0] << 16; + tmp |= RDF[0][(i << 1) + 1] << 0; + write_sram(card, card->rt_base + 512 + i, tmp); + } + + for (i = 0; i < 128; i++) { + unsigned int tmp; + + tmp = AIR[0][(i << 1) + 0] << 16; + tmp |= AIR[0][(i << 1) + 1] << 0; + write_sram(card, card->rt_base + 640 + i, tmp); + } +#endif + + IPRINTK("%s: initialize rate table ...\n", card->name); + writel(card->rt_base << 2, SAR_REG_RTBL); + + /* Initialize TSTs */ + IPRINTK("%s: initialize TST ...\n", card->name); + card->tst_free = card->tst_size - 2; /* last two are jumps */ + + for (i = card->tst[0]; i < card->tst[0] + card->tst_size - 2; i++) + write_sram(card, i, TSTE_OPC_VAR); + write_sram(card, i++, TSTE_OPC_JMP | (card->tst[0] << 2)); + idt77252_sram_write_errors = 1; + write_sram(card, i++, TSTE_OPC_JMP | (card->tst[1] << 2)); + idt77252_sram_write_errors = 0; + for (i = card->tst[1]; i < card->tst[1] + card->tst_size - 2; i++) + write_sram(card, i, TSTE_OPC_VAR); + write_sram(card, i++, TSTE_OPC_JMP | (card->tst[1] << 2)); + idt77252_sram_write_errors = 1; + write_sram(card, i++, TSTE_OPC_JMP | (card->tst[0] << 2)); + idt77252_sram_write_errors = 0; + + card->tst_index = 0; + writel(card->tst[0] << 2, SAR_REG_TSTB); + + /* Initialize ABRSTD and Receive FIFO */ + IPRINTK("%s: initialize ABRSTD ...\n", card->name); + writel(card->abrst_size | (card->abrst_base << 2), + SAR_REG_ABRSTD); + + IPRINTK("%s: initialize receive fifo ...\n", card->name); + writel(card->fifo_size | (card->fifo_base << 2), + SAR_REG_RXFD); + + IPRINTK("%s: SRAM initialization complete.\n", card->name); + return 0; +} + +static int +init_card(struct atm_dev *dev) +{ + struct idt77252_dev *card = dev->dev_data; + struct pci_dev *pcidev = card->pcidev; + unsigned long tmpl, modl; + unsigned int linkrate, rsvdcr; + unsigned int tst_entries; + struct net_device *tmp; + char tname[10]; + + u32 size; + u_char pci_byte; + u32 conf; + int i, k; + + if (test_bit(IDT77252_BIT_INIT, &card->flags)) { + printk("Error: SAR already initialized.\n"); + return -1; + } + +/*****************************************************************/ +/* P C I C O N F I G U R A T I O N */ +/*****************************************************************/ + + /* Set PCI Retry-Timeout and TRDY timeout */ + IPRINTK("%s: Checking PCI retries.\n", card->name); + if (pci_read_config_byte(pcidev, 0x40, &pci_byte) != 0) { + printk("%s: can't read PCI retry timeout.\n", card->name); + deinit_card(card); + return -1; + } + if (pci_byte != 0) { + IPRINTK("%s: PCI retry timeout: %d, set to 0.\n", + card->name, pci_byte); + if (pci_write_config_byte(pcidev, 0x40, 0) != 0) { + printk("%s: can't set PCI retry timeout.\n", + card->name); + deinit_card(card); + return -1; + } + } + IPRINTK("%s: Checking PCI TRDY.\n", card->name); + if (pci_read_config_byte(pcidev, 0x41, &pci_byte) != 0) { + printk("%s: can't read PCI TRDY timeout.\n", card->name); + deinit_card(card); + return -1; + } + if (pci_byte != 0) { + IPRINTK("%s: PCI TRDY timeout: %d, set to 0.\n", + card->name, pci_byte); + if (pci_write_config_byte(pcidev, 0x41, 0) != 0) { + printk("%s: can't set PCI TRDY timeout.\n", card->name); + deinit_card(card); + return -1; + } + } + /* Reset Timer register */ + if (readl(SAR_REG_STAT) & SAR_STAT_TMROF) { + printk("%s: resetting timer overflow.\n", card->name); + writel(SAR_STAT_TMROF, SAR_REG_STAT); + } + IPRINTK("%s: Request IRQ ... ", card->name); + if (request_irq(pcidev->irq, idt77252_interrupt, SA_INTERRUPT|SA_SHIRQ, + card->name, card) != 0) { + printk("%s: can't allocate IRQ.\n", card->name); + deinit_card(card); + return -1; + } + IPRINTK("got %d.\n", pcidev->irq); + +/*****************************************************************/ +/* C H E C K A N D I N I T S R A M */ +/*****************************************************************/ + + IPRINTK("%s: Initializing SRAM\n", card->name); + + /* preset size of connecton table, so that init_sram() knows about it */ + conf = SAR_CFG_TX_FIFO_SIZE_9 | /* Use maximum fifo size */ + SAR_CFG_RXSTQ_SIZE_8k | /* Receive Status Queue is 8k */ + SAR_CFG_IDLE_CLP | /* Set CLP on idle cells */ +#ifndef CONFIG_ATM_IDT77252_SEND_IDLE + SAR_CFG_NO_IDLE | /* Do not send idle cells */ +#endif + 0; + + if (card->sramsize == (512 * 1024)) + conf |= SAR_CFG_CNTBL_1k; + else + conf |= SAR_CFG_CNTBL_512; + + switch (vpibits) { + case 0: + conf |= SAR_CFG_VPVCS_0; + break; + default: + case 1: + conf |= SAR_CFG_VPVCS_1; + break; + case 2: + conf |= SAR_CFG_VPVCS_2; + break; + case 8: + conf |= SAR_CFG_VPVCS_8; + break; + } + + writel(readl(SAR_REG_CFG) | conf, SAR_REG_CFG); + + if (init_sram(card) < 0) + return -1; + +/********************************************************************/ +/* A L L O C R A M A N D S E T V A R I O U S T H I N G S */ +/********************************************************************/ + /* Initialize TSQ */ + if (0 != init_tsq(card)) { + deinit_card(card); + return -1; + } + /* Initialize RSQ */ + if (0 != init_rsq(card)) { + deinit_card(card); + return -1; + } + + card->vpibits = vpibits; + if (card->sramsize == (512 * 1024)) { + card->vcibits = 10 - card->vpibits; + } else { + card->vcibits = 9 - card->vpibits; + } + + card->vcimask = 0; + for (k = 0, i = 1; k < card->vcibits; k++) { + card->vcimask |= i; + i <<= 1; + } + + IPRINTK("%s: Setting VPI/VCI mask to zero.\n", card->name); + writel(0, SAR_REG_VPM); + + /* Little Endian Order */ + writel(0, SAR_REG_GP); + + /* Initialize RAW Cell Handle Register */ + card->raw_cell_hnd = pci_alloc_consistent(card->pcidev, 2 * sizeof(u32), + &card->raw_cell_paddr); + if (!card->raw_cell_hnd) { + printk("%s: memory allocation failure.\n", card->name); + deinit_card(card); + return -1; + } + memset(card->raw_cell_hnd, 0, 2 * sizeof(u32)); + writel(card->raw_cell_paddr, SAR_REG_RAWHND); + IPRINTK("%s: raw cell handle is at 0x%p.\n", card->name, + card->raw_cell_hnd); + + size = sizeof(struct vc_map *) * card->tct_size; + IPRINTK("%s: allocate %d byte for VC map.\n", card->name, size); + if (NULL == (card->vcs = vmalloc(size))) { + printk("%s: memory allocation failure.\n", card->name); + deinit_card(card); + return -1; + } + memset(card->vcs, 0, size); + + size = sizeof(struct vc_map *) * card->scd_size; + IPRINTK("%s: allocate %d byte for SCD to VC mapping.\n", + card->name, size); + if (NULL == (card->scd2vc = vmalloc(size))) { + printk("%s: memory allocation failure.\n", card->name); + deinit_card(card); + return -1; + } + memset(card->scd2vc, 0, size); + + size = sizeof(struct tst_info) * (card->tst_size - 2); + IPRINTK("%s: allocate %d byte for TST to VC mapping.\n", + card->name, size); + if (NULL == (card->soft_tst = vmalloc(size))) { + printk("%s: memory allocation failure.\n", card->name); + deinit_card(card); + return -1; + } + for (i = 0; i < card->tst_size - 2; i++) { + card->soft_tst[i].tste = TSTE_OPC_VAR; + card->soft_tst[i].vc = NULL; + } + + if (dev->phy == NULL) { + printk("%s: No LT device defined.\n", card->name); + deinit_card(card); + return -1; + } + if (dev->phy->ioctl == NULL) { + printk("%s: LT had no IOCTL funtion defined.\n", card->name); + deinit_card(card); + return -1; + } + +#ifdef CONFIG_ATM_IDT77252_USE_SUNI + /* + * this is a jhs hack to get around special functionality in the + * phy driver for the atecom hardware; the functionality doesn't + * exist in the linux atm suni driver + * + * it isn't the right way to do things, but as the guy from NIST + * said, talking about their measurement of the fine structure + * constant, "it's good enough for government work." + */ + linkrate = 149760000; +#endif + + card->link_pcr = (linkrate / 8 / 53); + printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n", + card->name, linkrate, card->link_pcr); + +#ifdef CONFIG_ATM_IDT77252_SEND_IDLE + card->utopia_pcr = card->link_pcr; +#else + card->utopia_pcr = (160000000 / 8 / 54); +#endif + + rsvdcr = 0; + if (card->utopia_pcr > card->link_pcr) + rsvdcr = card->utopia_pcr - card->link_pcr; + + tmpl = (unsigned long) rsvdcr * ((unsigned long) card->tst_size - 2); + modl = tmpl % (unsigned long)card->utopia_pcr; + tst_entries = (int) (tmpl / (unsigned long)card->utopia_pcr); + if (modl) + tst_entries++; + card->tst_free -= tst_entries; + fill_tst(card, NULL, tst_entries, TSTE_OPC_NULL); + +#ifdef HAVE_EEPROM + idt77252_eeprom_init(card); + printk("%s: EEPROM: %02x:", card->name, + idt77252_eeprom_read_status(card)); + + for (i = 0; i < 0x80; i++) { + printk(" %02x", + idt77252_eeprom_read_byte(card, i) + ); + } + printk("\n"); +#endif /* HAVE_EEPROM */ + + /* + * XXX: <hack> + */ + sprintf(tname, "eth%d", card->index); + tmp = dev_get_by_name(tname); /* jhs: was "tmp = dev_get(tname);" */ + if (tmp) { + memcpy(card->atmdev->esi, tmp->dev_addr, 6); + + printk("%s: ESI %02x:%02x:%02x:%02x:%02x:%02x\n", + card->name, card->atmdev->esi[0], card->atmdev->esi[1], + card->atmdev->esi[2], card->atmdev->esi[3], + card->atmdev->esi[4], card->atmdev->esi[5]); + } + /* + * XXX: </hack> + */ + + /* Set Maximum Deficit Count for now. */ + writel(0xffff, SAR_REG_MDFCT); + + set_bit(IDT77252_BIT_INIT, &card->flags); + + XPRINTK("%s: IDT77252 ABR SAR initialization complete.\n", card->name); + return 0; +} + + +/*****************************************************************************/ +/* */ +/* Probing of IDT77252 ABR SAR */ +/* */ +/*****************************************************************************/ + + +static int +preset_idt77252(struct idt77252_dev *card) +{ + u16 pci_command; + +/*****************************************************************/ +/* P C I C O N F I G U R A T I O N */ +/*****************************************************************/ + + XPRINTK("%s: Enable PCI master and memory access for SAR.\n", + card->name); + if (pci_read_config_word(card->pcidev, PCI_COMMAND, &pci_command)) { + printk("%s: can't read PCI_COMMAND.\n", card->name); + deinit_card(card); + return -1; + } + if (!(pci_command & PCI_COMMAND_IO)) { + printk("%s: PCI_COMMAND: %04x (???)\n", + card->name, pci_command); + deinit_card(card); + return (-1); + } + pci_command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + if (pci_write_config_word(card->pcidev, PCI_COMMAND, pci_command)) { + printk("%s: can't write PCI_COMMAND.\n", card->name); + deinit_card(card); + return -1; + } +/*****************************************************************/ +/* G E N E R I C R E S E T */ +/*****************************************************************/ + + /* Software reset */ + writel(SAR_CFG_SWRST, SAR_REG_CFG); + mdelay(1); + writel(0, SAR_REG_CFG); + + IPRINTK("%s: Software resetted.\n", card->name); + return 0; +} + + +unsigned long +probe_sram(struct idt77252_dev *card) +{ + u32 data, addr; + + writel(0, SAR_REG_DR0); + writel(SAR_CMD_WRITE_SRAM | (0 << 2), SAR_REG_CMD); + + for (addr = 0x4000; addr < 0x80000; addr += 0x4000) { + writel(0xdeadbeef, SAR_REG_DR0); + writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD); + + writel(SAR_CMD_READ_SRAM | (0 << 2), SAR_REG_CMD); + data = readl(SAR_REG_DR0); + + if (data != 0) + break; + } + + return addr * sizeof(u32); +} + +int +idt77252_probe(void) +{ + struct idt77252_dev **last, *card; + struct pci_dev *pcidev = NULL; + struct atm_dev *dev; + ushort revision = 0; + int i, index = 0; + + last = &idt77252_chain; + + if (!pci_present()) { + printk(KERN_NOTICE "idt77252: no PCI subsystem found.\n"); + return -ENODEV; + } + + while ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT, + PCI_DEVICE_ID_IDT_IDT77252, + pcidev))) { + unsigned long membase, srambase; + + if (pci_read_config_word(pcidev, PCI_REVISION_ID, &revision)) { + printk("idt77252-%d: can't read PCI_REVISION_ID\n", + index); + continue; + } + card = kmalloc(sizeof(struct idt77252_dev), GFP_KERNEL); + if (!card) { + printk("idt77252-%d: can't allocate private data\n", + index); + continue; + } + memset(card, 0, sizeof(struct idt77252_dev)); + + card->revision = revision; + card->index = index; + card->pcidev = pcidev; + sprintf(card->name, "idt77252-%d", card->index); + + card->tqueue.routine = idt77252_softint; + card->tqueue.data = (void *)card; + + membase = pci_resource_start(pcidev, 1); + srambase = pci_resource_start(pcidev, 2); + + init_MUTEX(&card->mutex); + spin_lock_init(&card->cmd_lock); + spin_lock_init(&card->tst_lock); + + card->tst_timer.data = (unsigned long)card; + card->tst_timer.function = tst_timer; + init_timer(&card->tst_timer); + + /* Do the I/O remapping... */ + card->membase = (unsigned long) ioremap(membase, 1024); + if (!card->membase) { + printk("%s: can't ioremap() membase\n", card->name); + kfree(card); + continue; + } + + if (preset_idt77252(card)) { + printk("%s: preset failed\n", card->name); + iounmap((void *) card->membase); + kfree(card); + continue; + } + + dev = atm_dev_register("idt77252", &idt77252_ops, -1, 0); + if (!dev) { + printk("%s: can't register atm device\n", card->name); + iounmap((void *) card->membase); + kfree(card); + continue; + } + dev->dev_data = card; + card->atmdev = dev; + +#ifdef CONFIG_ATM_IDT77252_USE_SUNI + suni_init(dev); + if (!dev->phy) { + printk("%s: can't init SUNI\n", card->name); + deinit_card(card); + kfree(card); + continue; + } +#endif /* CONFIG_ATM_IDT77252_USE_SUNI */ + + card->sramsize = probe_sram(card); + + for (i = 0; i < 4; i++) { + card->fbq[i] = (unsigned long) + ioremap(srambase | 0x200000 | (i << 18), 4); + if (!card->fbq[i]) { + printk("%s: can't ioremap() FBQ%d\n", + card->name, i); + deinit_card(card); + kfree(card); + goto next; + } + } + + printk("%s: ABR SAR (Rev %c): MEM %08lx SRAM %08lx [%u KB]\n", + card->name, ((revision > 1) && (revision < 25)) ? + 'A' + revision - 1 : '?', + membase, srambase, card->sramsize / 1024); + + if (init_card(dev)) { + printk("%s: init_card failed\n", card->name); + + deinit_card(card); + kfree(card); + continue; + } + dev->ci_range.vpi_bits = card->vpibits; + dev->ci_range.vci_bits = card->vcibits; + dev->link_rate = card->link_pcr; + + if (dev->phy->start) + dev->phy->start(dev); + + if (idt77252_dev_open(card)) { + printk("%s: dev_open failed\n", card->name); + + if (dev->phy->stop) + dev->phy->stop(dev); + deinit_card(card); + kfree(card); + continue; + } + + *last = card; + last = &card->next; + index++; + next: + } + + return index; +} + +#ifdef MODULE + +MODULE_PARM(vpibits, "i"); +MODULE_AUTHOR("Eddie C. Dost <ecd@atecom.com>"); +MODULE_DESCRIPTION("IDT77252 ABR SAR Driver"); +#ifdef DEBUG +MODULE_PARM(debug, "i"); +#endif + +int +init_module(void) +{ + int v; + + printk("idt77252 init_module: %s at %p\n", __FUNCTION__, init_module); + + /* + * this modification is somewhat silly, as atmdev_init.c doesn't + * check for EIO, it only accumulates the return value in the sum + * of atm adaptors found. + */ + v = idt77252_probe(); + if (v < 0) + return -EIO; + + return 0; +} + +void +cleanup_module(void) +{ + struct idt77252_dev *card; + struct atm_dev *dev; + + while (idt77252_chain) { + card = idt77252_chain; + dev = card->atmdev; + idt77252_chain = card->next; + + if (dev->phy->stop) + dev->phy->stop(dev); + deinit_card(card); + kfree(card); + } + + DIPRINTK("idt77252: finished cleanup-module().\n"); +} + +#else + +int __init idt77252_detect(void) +{ + int v; + + v = idt77252_probe(); + if (v < 0) + return -EIO; + else + return v; +} + +#endif /* MODULE */ diff -u --recursive --new-file v2.4.14/linux/drivers/atm/idt77252.h linux/drivers/atm/idt77252.h --- v2.4.14/linux/drivers/atm/idt77252.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/idt77252.h Wed Nov 7 14:39:36 2001 @@ -0,0 +1,824 @@ +/******************************************************************* + * ident "$Id: idt77252.h,v 1.1 2001/11/05 21:52:22 ecd Exp $" + * + * $Author: ecd $ + * $Date: 2001/11/05 21:52:22 $ + * + * Copyright (c) 2000 ATecoM GmbH + * + * The author may be reached at ecd@atecom.com. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + *******************************************************************/ + +#ifndef _IDT77252_H +#define _IDT77252_H 1 + + +#include <linux/ptrace.h> +#include <linux/skbuff.h> + + +/*****************************************************************************/ +/* */ +/* Makros */ +/* */ +/*****************************************************************************/ +#define VPCI2VC(card, vpi, vci) \ + (((vpi) << card->vcibits) | ((vci) & card->vcimask)) + +/*****************************************************************************/ +/* */ +/* DEBUGGING definitions */ +/* */ +/*****************************************************************************/ + +#define DBG_TINY 0x00000200 +#define DBG_GENERAL 0x00000100 +#define DBG_XGENERAL 0x00000080 +#define DBG_INIT 0x00000040 +#define DBG_DEINIT 0x00000020 +#define DBG_INTERRUPT 0x00000010 +#define DBG_OPEN_CONN 0x00000008 +#define DBG_CLOSE_CONN 0x00000004 +#define DBG_RX_DATA 0x00000002 +#define DBG_TX_DATA 0x00000001 + +#ifdef DEBUG + +#define CPRINTK(args...) do { if (debug & DBG_CLOSE_CONN) printk(args); } while(0) +#define OPRINTK(args...) do { if (debug & DBG_OPEN_CONN) printk(args); } while(0) +#define IPRINTK(args...) do { if (debug & DBG_INIT) printk(args); } while(0) +#define INTPRINTK(args...) do { if (debug & DBG_INTERRUPT) printk(args); } while(0) +#define DIPRINTK(args...) do { if (debug & DBG_DEINIT) printk(args); } while(0) +#define TXPRINTK(args...) do { if (debug & DBG_TX_DATA) printk(args); } while(0) +#define RXPRINTK(args...) do { if (debug & DBG_RX_DATA) printk(args); } while(0) +#define XPRINTK(args...) do { if (debug & DBG_XGENERAL) printk(args); } while(0) +#define DPRINTK(args...) do { if (debug & DBG_GENERAL) printk(args); } while(0) +#define NPRINTK(args...) do { if (debug & DBG_TINY) printk(args); } while(0) + +#else + +#define CPRINTK(args...) do { } while(0) +#define OPRINTK(args...) do { } while(0) +#define IPRINTK(args...) do { } while(0) +#define INTPRINTK(args...) do { } while(0) +#define DIPRINTK(args...) do { } while(0) +#define TXPRINTK(args...) do { } while(0) +#define RXPRINTK(args...) do { } while(0) +#define XPRINTK(args...) do { } while(0) +#define DPRINTK(args...) do { } while(0) +#define NPRINTK(args...) do { } while(0) + +#endif + +#define SCHED_UBR0 0 +#define SCHED_UBR 1 +#define SCHED_VBR 2 +#define SCHED_ABR 3 +#define SCHED_CBR 4 + +#define SCQFULL_TIMEOUT HZ + +/*****************************************************************************/ +/* */ +/* Free Buffer Queue Layout */ +/* */ +/*****************************************************************************/ +#define SAR_FB_SIZE_0 (2048 - 256) +#define SAR_FB_SIZE_1 (4096 - 256) +#define SAR_FB_SIZE_2 (8192 - 256) +#define SAR_FB_SIZE_3 (16384 - 256) + +#define SAR_FBQ0_LOW 4 +#define SAR_FBQ0_HIGH 8 +#define SAR_FBQ1_LOW 2 +#define SAR_FBQ1_HIGH 4 +#define SAR_FBQ2_LOW 1 +#define SAR_FBQ2_HIGH 2 +#define SAR_FBQ3_LOW 1 +#define SAR_FBQ3_HIGH 2 + +#if 0 +#define SAR_TST_RESERVED 44 /* Num TST reserved for UBR/ABR/VBR */ +#else +#define SAR_TST_RESERVED 0 /* Num TST reserved for UBR/ABR/VBR */ +#endif + +#define TCT_CBR 0x00000000 +#define TCT_UBR 0x00000000 +#define TCT_VBR 0x40000000 +#define TCT_ABR 0x80000000 +#define TCT_TYPE 0xc0000000 + +#define TCT_RR 0x20000000 +#define TCT_LMCR 0x08000000 +#define TCT_SCD_MASK 0x0007ffff + +#define TCT_TSIF 0x00004000 +#define TCT_HALT 0x80000000 +#define TCT_IDLE 0x40000000 +#define TCT_FLAG_UBR 0x80000000 + +/*****************************************************************************/ +/* */ +/* Structure describing an IDT77252 */ +/* */ +/*****************************************************************************/ + +struct scqe +{ + u32 word_1; + u32 word_2; + u32 word_3; + u32 word_4; +}; + +#define SCQ_ENTRIES 64 +#define SCQ_SIZE (SCQ_ENTRIES * sizeof(struct scqe)) +#define SCQ_MASK (SCQ_SIZE - 1) + +struct scq_info +{ + struct scqe *base; + struct scqe *next; + struct scqe *last; + dma_addr_t paddr; + spinlock_t lock; + atomic_t used; + unsigned long trans_start; + unsigned long scd; + spinlock_t skblock; + struct sk_buff_head transmit; + struct sk_buff_head pending; +}; + +struct rx_pool { + struct sk_buff *first; + struct sk_buff **last; + unsigned int len; + unsigned int count; +}; + +struct aal1 { + unsigned int total; + unsigned int count; + struct sk_buff *data; + unsigned char sequence; +}; + +struct rate_estimator { + struct timer_list timer; + unsigned int interval; + unsigned int ewma_log; + u64 cells; + u64 last_cells; + long avcps; + u32 cps; + u32 maxcps; +}; + +struct vc_map { + unsigned int index; + unsigned long flags; +#define VCF_TX 0 +#define VCF_RX 1 +#define VCF_IDLE 2 +#define VCF_RSV 3 + unsigned int class; + u8 init_er; + u8 lacr; + u8 max_er; + unsigned int ntste; + spinlock_t lock; + struct atm_vcc *tx_vcc; + struct atm_vcc *rx_vcc; + struct idt77252_dev *card; + struct scq_info *scq; /* To keep track of the SCQ */ + struct rate_estimator *estimator; + int scd_index; + union { + struct rx_pool rx_pool; + struct aal1 aal1; + } rcv; +}; + +/*****************************************************************************/ +/* */ +/* RCTE - Receive Connection Table Entry */ +/* */ +/*****************************************************************************/ + +struct rct_entry +{ + u32 word_1; + u32 buffer_handle; + u32 dma_address; + u32 aal5_crc32; +}; + +/*****************************************************************************/ +/* */ +/* RSQ - Receive Status Queue */ +/* */ +/*****************************************************************************/ + +#define SAR_RSQE_VALID 0x80000000 +#define SAR_RSQE_IDLE 0x40000000 +#define SAR_RSQE_BUF_MASK 0x00030000 +#define SAR_RSQE_BUF_ASGN 0x00008000 +#define SAR_RSQE_NZGFC 0x00004000 +#define SAR_RSQE_EPDU 0x00002000 +#define SAR_RSQE_BUF_CONT 0x00001000 +#define SAR_RSQE_EFCIE 0x00000800 +#define SAR_RSQE_CLP 0x00000400 +#define SAR_RSQE_CRC 0x00000200 +#define SAR_RSQE_CELLCNT 0x000001FF + + +#define RSQSIZE 8192 +#define RSQ_NUM_ENTRIES (RSQSIZE / 16) +#define RSQ_ALIGNMENT 8192 + +struct rsq_entry { + u32 word_1; + u32 word_2; + u32 word_3; + u32 word_4; +}; + +struct rsq_info { + struct rsq_entry *base; + struct rsq_entry *next; + struct rsq_entry *last; + dma_addr_t paddr; +} rsq_info; + + +/*****************************************************************************/ +/* */ +/* TSQ - Transmit Status Queue */ +/* */ +/*****************************************************************************/ + +#define SAR_TSQE_INVALID 0x80000000 +#define SAR_TSQE_TIMESTAMP 0x00FFFFFF +#define SAR_TSQE_TYPE 0x60000000 +#define SAR_TSQE_TYPE_TIMER 0x00000000 +#define SAR_TSQE_TYPE_TSR 0x20000000 +#define SAR_TSQE_TYPE_IDLE 0x40000000 +#define SAR_TSQE_TYPE_TBD_COMP 0x60000000 + +#define SAR_TSQE_TAG(stat) (((stat) >> 24) & 0x1f) + +#define TSQSIZE 8192 +#define TSQ_NUM_ENTRIES 1024 +#define TSQ_ALIGNMENT 8192 + +struct tsq_entry +{ + u32 word_1; + u32 word_2; +}; + +struct tsq_info +{ + struct tsq_entry *base; + struct tsq_entry *next; + struct tsq_entry *last; + dma_addr_t paddr; +}; + +struct tst_info +{ + struct vc_map *vc; + u32 tste; +}; + +#define TSTE_MASK 0x601fffff + +#define TSTE_OPC_MASK 0x60000000 +#define TSTE_OPC_NULL 0x00000000 +#define TSTE_OPC_CBR 0x20000000 +#define TSTE_OPC_VAR 0x40000000 +#define TSTE_OPC_JMP 0x60000000 + +#define TSTE_PUSH_IDLE 0x01000000 +#define TSTE_PUSH_ACTIVE 0x02000000 + +#define TST_SWITCH_DONE 0 +#define TST_SWITCH_PENDING 1 +#define TST_SWITCH_WAIT 2 + +#define FBQ_SHIFT 9 +#define FBQ_SIZE (1 << FBQ_SHIFT) +#define FBQ_MASK (FBQ_SIZE - 1) + +struct sb_pool +{ + unsigned int index; + struct sk_buff *skb[FBQ_SIZE]; +}; + +#define POOL_HANDLE(queue, index) (((queue + 1) << 16) | (index)) +#define POOL_QUEUE(handle) (((handle) >> 16) - 1) +#define POOL_INDEX(handle) ((handle) & 0xffff) + +struct idt77252_dev +{ + struct tsq_info tsq; /* Transmit Status Queue */ + struct rsq_info rsq; /* Receive Status Queue */ + + struct pci_dev *pcidev; /* PCI handle (desriptor) */ + struct atm_dev *atmdev; /* ATM device desriptor */ + + unsigned long membase; /* SAR's memory base address */ + unsigned long srambase; /* SAR's sram base address */ + unsigned long fbq[4]; /* FBQ fill addresses */ + + struct semaphore mutex; + spinlock_t cmd_lock; /* for r/w utility/sram */ + + unsigned long softstat; + unsigned long flags; /* see blow */ + + struct tq_struct tqueue; + + unsigned long tct_base; /* TCT base address in SRAM */ + unsigned long rct_base; /* RCT base address in SRAM */ + unsigned long rt_base; /* Rate Table base in SRAM */ + unsigned long scd_base; /* SCD base address in SRAM */ + unsigned long tst[2]; /* TST base address in SRAM */ + unsigned long abrst_base; /* ABRST base address in SRAM */ + unsigned long fifo_base; /* RX FIFO base in SRAM */ + + unsigned long irqstat[16]; + + unsigned int sramsize; /* SAR's sram size */ + + unsigned int tct_size; /* total TCT entries */ + unsigned int rct_size; /* total RCT entries */ + unsigned int scd_size; /* length of SCD */ + unsigned int tst_size; /* total TST entries */ + unsigned int tst_free; /* free TSTEs in TST */ + unsigned int abrst_size; /* size of ABRST in words */ + unsigned int fifo_size; /* size of RX FIFO in words */ + + unsigned int vpibits; /* Bits used for VPI index */ + unsigned int vcibits; /* Bits used for VCI index */ + unsigned int vcimask; /* Mask for VCI index */ + + unsigned int utopia_pcr; /* Utopia Itf's Cell Rate */ + unsigned int link_pcr; /* PHY's Peek Cell Rate */ + + struct vc_map **vcs; /* Open Connections */ + struct vc_map **scd2vc; /* SCD to Connection map */ + + struct tst_info *soft_tst; /* TST to Connection map */ + unsigned int tst_index; /* Current TST in use */ + struct timer_list tst_timer; + spinlock_t tst_lock; + unsigned long tst_state; + + struct sb_pool sbpool[4]; /* Pool of RX skbuffs */ + struct sk_buff *raw_cell_head; /* Pointer to raw cell queue */ + u32 *raw_cell_hnd; /* Pointer to RCQ handle */ + dma_addr_t raw_cell_paddr; + + int index; /* SAR's ID */ + int revision; /* chip revision */ + + char name[16]; /* Device name */ + + struct idt77252_dev *next; +}; + + +/* definition for flag field above */ +#define IDT77252_BIT_INIT 1 +#define IDT77252_BIT_INTERRUPT 2 + + +#define ATM_CELL_PAYLOAD 48 + +#define FREEBUF_ALIGNMENT 16 + +/*****************************************************************************/ +/* */ +/* Makros */ +/* */ +/*****************************************************************************/ +#define ALIGN_ADDRESS(addr, alignment) \ + ((((u32)(addr)) + (((u32)(alignment))-1)) & ~(((u32)(alignment)) - 1)) + + +/*****************************************************************************/ +/* */ +/* ABR SAR Network operation Register */ +/* */ +/*****************************************************************************/ + +#define SAR_REG_DR0 (card->membase + 0x00) +#define SAR_REG_DR1 (card->membase + 0x04) +#define SAR_REG_DR2 (card->membase + 0x08) +#define SAR_REG_DR3 (card->membase + 0x0C) +#define SAR_REG_CMD (card->membase + 0x10) +#define SAR_REG_CFG (card->membase + 0x14) +#define SAR_REG_STAT (card->membase + 0x18) +#define SAR_REG_RSQB (card->membase + 0x1C) +#define SAR_REG_RSQT (card->membase + 0x20) +#define SAR_REG_RSQH (card->membase + 0x24) +#define SAR_REG_CDC (card->membase + 0x28) +#define SAR_REG_VPEC (card->membase + 0x2C) +#define SAR_REG_ICC (card->membase + 0x30) +#define SAR_REG_RAWCT (card->membase + 0x34) +#define SAR_REG_TMR (card->membase + 0x38) +#define SAR_REG_TSTB (card->membase + 0x3C) +#define SAR_REG_TSQB (card->membase + 0x40) +#define SAR_REG_TSQT (card->membase + 0x44) +#define SAR_REG_TSQH (card->membase + 0x48) +#define SAR_REG_GP (card->membase + 0x4C) +#define SAR_REG_VPM (card->membase + 0x50) +#define SAR_REG_RXFD (card->membase + 0x54) +#define SAR_REG_RXFT (card->membase + 0x58) +#define SAR_REG_RXFH (card->membase + 0x5C) +#define SAR_REG_RAWHND (card->membase + 0x60) +#define SAR_REG_RXSTAT (card->membase + 0x64) +#define SAR_REG_ABRSTD (card->membase + 0x68) +#define SAR_REG_ABRRQ (card->membase + 0x6C) +#define SAR_REG_VBRRQ (card->membase + 0x70) +#define SAR_REG_RTBL (card->membase + 0x74) +#define SAR_REG_MDFCT (card->membase + 0x78) +#define SAR_REG_TXSTAT (card->membase + 0x7C) +#define SAR_REG_TCMDQ (card->membase + 0x80) +#define SAR_REG_IRCP (card->membase + 0x84) +#define SAR_REG_FBQP0 (card->membase + 0x88) +#define SAR_REG_FBQP1 (card->membase + 0x8C) +#define SAR_REG_FBQP2 (card->membase + 0x90) +#define SAR_REG_FBQP3 (card->membase + 0x94) +#define SAR_REG_FBQS0 (card->membase + 0x98) +#define SAR_REG_FBQS1 (card->membase + 0x9C) +#define SAR_REG_FBQS2 (card->membase + 0xA0) +#define SAR_REG_FBQS3 (card->membase + 0xA4) +#define SAR_REG_FBQWP0 (card->membase + 0xA8) +#define SAR_REG_FBQWP1 (card->membase + 0xAC) +#define SAR_REG_FBQWP2 (card->membase + 0xB0) +#define SAR_REG_FBQWP3 (card->membase + 0xB4) +#define SAR_REG_NOW (card->membase + 0xB8) + + +/*****************************************************************************/ +/* */ +/* Commands */ +/* */ +/*****************************************************************************/ + +#define SAR_CMD_NO_OPERATION 0x00000000 +#define SAR_CMD_OPENCLOSE_CONNECTION 0x20000000 +#define SAR_CMD_WRITE_SRAM 0x40000000 +#define SAR_CMD_READ_SRAM 0x50000000 +#define SAR_CMD_READ_UTILITY 0x80000000 +#define SAR_CMD_WRITE_UTILITY 0x90000000 + +#define SAR_CMD_OPEN_CONNECTION (SAR_CMD_OPENCLOSE_CONNECTION | 0x00080000) +#define SAR_CMD_CLOSE_CONNECTION SAR_CMD_OPENCLOSE_CONNECTION + + +/*****************************************************************************/ +/* */ +/* Configuration Register bits */ +/* */ +/*****************************************************************************/ + +#define SAR_CFG_SWRST 0x80000000 /* Software reset */ +#define SAR_CFG_LOOP 0x40000000 /* Internal Loopback */ +#define SAR_CFG_RXPTH 0x20000000 /* Receive Path Enable */ +#define SAR_CFG_IDLE_CLP 0x10000000 /* SAR set CLP Bits of Null Cells */ +#define SAR_CFG_TX_FIFO_SIZE_1 0x04000000 /* TX FIFO Size = 1 cell */ +#define SAR_CFG_TX_FIFO_SIZE_2 0x08000000 /* TX FIFO Size = 2 cells */ +#define SAR_CFG_TX_FIFO_SIZE_4 0x0C000000 /* TX FIFO Size = 4 cells */ +#define SAR_CFG_TX_FIFO_SIZE_9 0x00000000 /* TX FIFO Size = 9 cells (full) */ +#define SAR_CFG_NO_IDLE 0x02000000 /* SAR sends no Null Cells */ +#define SAR_CFG_RSVD1 0x01000000 /* Reserved */ +#define SAR_CFG_RXSTQ_SIZE_2k 0x00000000 /* RX Stat Queue Size = 2048 byte */ +#define SAR_CFG_RXSTQ_SIZE_4k 0x00400000 /* RX Stat Queue Size = 4096 byte */ +#define SAR_CFG_RXSTQ_SIZE_8k 0x00800000 /* RX Stat Queue Size = 8192 byte */ +#define SAR_CFG_RXSTQ_SIZE_R 0x00C00000 /* RX Stat Queue Size = reserved */ +#define SAR_CFG_ICAPT 0x00200000 /* accept Invalid Cells */ +#define SAR_CFG_IGGFC 0x00100000 /* Ignore GFC */ +#define SAR_CFG_VPVCS_0 0x00000000 /* VPI/VCI Select bit range */ +#define SAR_CFG_VPVCS_1 0x00040000 /* VPI/VCI Select bit range */ +#define SAR_CFG_VPVCS_2 0x00080000 /* VPI/VCI Select bit range */ +#define SAR_CFG_VPVCS_8 0x000C0000 /* VPI/VCI Select bit range */ +#define SAR_CFG_CNTBL_1k 0x00000000 /* Connection Table Size */ +#define SAR_CFG_CNTBL_4k 0x00010000 /* Connection Table Size */ +#define SAR_CFG_CNTBL_16k 0x00020000 /* Connection Table Size */ +#define SAR_CFG_CNTBL_512 0x00030000 /* Connection Table Size */ +#define SAR_CFG_VPECA 0x00008000 /* VPI/VCI Error Cell Accept */ +#define SAR_CFG_RXINT_NOINT 0x00000000 /* No Interrupt on PDU received */ +#define SAR_CFG_RXINT_NODELAY 0x00001000 /* Interrupt without delay to host*/ +#define SAR_CFG_RXINT_256US 0x00002000 /* Interrupt with delay 256 usec */ +#define SAR_CFG_RXINT_505US 0x00003000 /* Interrupt with delay 505 usec */ +#define SAR_CFG_RXINT_742US 0x00004000 /* Interrupt with delay 742 usec */ +#define SAR_CFG_RAWIE 0x00000800 /* Raw Cell Queue Interrupt Enable*/ +#define SAR_CFG_RQFIE 0x00000400 /* RSQ Almost Full Int Enable */ +#define SAR_CFG_RSVD2 0x00000200 /* Reserved */ +#define SAR_CFG_CACHE 0x00000100 /* DMA on Cache Line Boundary */ +#define SAR_CFG_TMOIE 0x00000080 /* Timer Roll Over Int Enable */ +#define SAR_CFG_FBIE 0x00000040 /* Free Buffer Queue Int Enable */ +#define SAR_CFG_TXEN 0x00000020 /* Transmit Operation Enable */ +#define SAR_CFG_TXINT 0x00000010 /* Transmit status Int Enable */ +#define SAR_CFG_TXUIE 0x00000008 /* Transmit underrun Int Enable */ +#define SAR_CFG_UMODE 0x00000004 /* Utopia Mode Select */ +#define SAR_CFG_TXSFI 0x00000002 /* Transmit status Full Int Enable*/ +#define SAR_CFG_PHYIE 0x00000001 /* PHY Interrupt Enable */ + +#define SAR_CFG_TX_FIFO_SIZE_MASK 0x0C000000 /* TX FIFO Size Mask */ +#define SAR_CFG_RXSTQSIZE_MASK 0x00C00000 +#define SAR_CFG_CNTBL_MASK 0x00030000 +#define SAR_CFG_RXINT_MASK 0x00007000 + + +/*****************************************************************************/ +/* */ +/* Status Register bits */ +/* */ +/*****************************************************************************/ + +#define SAR_STAT_FRAC_3 0xF0000000 /* Fraction of Free Buffer Queue 3 */ +#define SAR_STAT_FRAC_2 0x0F000000 /* Fraction of Free Buffer Queue 2 */ +#define SAR_STAT_FRAC_1 0x00F00000 /* Fraction of Free Buffer Queue 1 */ +#define SAR_STAT_FRAC_0 0x000F0000 /* Fraction of Free Buffer Queue 0 */ +#define SAR_STAT_TSIF 0x00008000 /* Transmit Status Indicator */ +#define SAR_STAT_TXICP 0x00004000 /* Transmit Status Indicator */ +#define SAR_STAT_RSVD1 0x00002000 /* Reserved */ +#define SAR_STAT_TSQF 0x00001000 /* Transmit Status Queue full */ +#define SAR_STAT_TMROF 0x00000800 /* Timer overflow */ +#define SAR_STAT_PHYI 0x00000400 /* PHY device Interrupt flag */ +#define SAR_STAT_CMDBZ 0x00000200 /* ABR SAR Comand Busy Flag */ +#define SAR_STAT_FBQ3A 0x00000100 /* Free Buffer Queue 3 Attention */ +#define SAR_STAT_FBQ2A 0x00000080 /* Free Buffer Queue 2 Attention */ +#define SAR_STAT_RSQF 0x00000040 /* Receive Status Queue full */ +#define SAR_STAT_EPDU 0x00000020 /* End Of PDU Flag */ +#define SAR_STAT_RAWCF 0x00000010 /* Raw Cell Flag */ +#define SAR_STAT_FBQ1A 0x00000008 /* Free Buffer Queue 1 Attention */ +#define SAR_STAT_FBQ0A 0x00000004 /* Free Buffer Queue 0 Attention */ +#define SAR_STAT_RSQAF 0x00000002 /* Receive Status Queue almost full*/ +#define SAR_STAT_RSVD2 0x00000001 /* Reserved */ + + +/*****************************************************************************/ +/* */ +/* General Purpose Register bits */ +/* */ +/*****************************************************************************/ + +#define SAR_GP_TXNCC_MASK 0xff000000 /* Transmit Negative Credit Count */ +#define SAR_GP_EEDI 0x00010000 /* EEPROM Data In */ +#define SAR_GP_BIGE 0x00008000 /* Big Endian Operation */ +#define SAR_GP_RM_NORMAL 0x00000000 /* Normal handling of RM cells */ +#define SAR_GP_RM_TO_RCQ 0x00002000 /* put RM cells into Raw Cell Queue */ +#define SAR_GP_RM_RSVD 0x00004000 /* Reserved */ +#define SAR_GP_RM_INHIBIT 0x00006000 /* Inhibit update of Connection tab */ +#define SAR_GP_PHY_RESET 0x00000008 /* PHY Reset */ +#define SAR_GP_EESCLK 0x00000004 /* EEPROM SCLK */ +#define SAR_GP_EECS 0x00000002 /* EEPROM Chip Select */ +#define SAR_GP_EEDO 0x00000001 /* EEPROM Data Out */ + + +/*****************************************************************************/ +/* */ +/* SAR local SRAM layout for 128k work SRAM */ +/* */ +/*****************************************************************************/ + +#define SAR_SRAM_SCD_SIZE 12 +#define SAR_SRAM_TCT_SIZE 8 +#define SAR_SRAM_RCT_SIZE 4 + +#define SAR_SRAM_TCT_128_BASE 0x00000 +#define SAR_SRAM_TCT_128_TOP 0x01fff +#define SAR_SRAM_RCT_128_BASE 0x02000 +#define SAR_SRAM_RCT_128_TOP 0x02fff +#define SAR_SRAM_FB0_128_BASE 0x03000 +#define SAR_SRAM_FB0_128_TOP 0x033ff +#define SAR_SRAM_FB1_128_BASE 0x03400 +#define SAR_SRAM_FB1_128_TOP 0x037ff +#define SAR_SRAM_FB2_128_BASE 0x03800 +#define SAR_SRAM_FB2_128_TOP 0x03bff +#define SAR_SRAM_FB3_128_BASE 0x03c00 +#define SAR_SRAM_FB3_128_TOP 0x03fff +#define SAR_SRAM_SCD_128_BASE 0x04000 +#define SAR_SRAM_SCD_128_TOP 0x07fff +#define SAR_SRAM_TST1_128_BASE 0x08000 +#define SAR_SRAM_TST1_128_TOP 0x0bfff +#define SAR_SRAM_TST2_128_BASE 0x0c000 +#define SAR_SRAM_TST2_128_TOP 0x0ffff +#define SAR_SRAM_ABRSTD_128_BASE 0x10000 +#define SAR_SRAM_ABRSTD_128_TOP 0x13fff +#define SAR_SRAM_RT_128_BASE 0x14000 +#define SAR_SRAM_RT_128_TOP 0x15fff + +#define SAR_SRAM_FIFO_128_BASE 0x18000 +#define SAR_SRAM_FIFO_128_TOP 0x1ffff + + +/*****************************************************************************/ +/* */ +/* SAR local SRAM layout for 32k work SRAM */ +/* */ +/*****************************************************************************/ + +#define SAR_SRAM_TCT_32_BASE 0x00000 +#define SAR_SRAM_TCT_32_TOP 0x00fff +#define SAR_SRAM_RCT_32_BASE 0x01000 +#define SAR_SRAM_RCT_32_TOP 0x017ff +#define SAR_SRAM_FB0_32_BASE 0x01800 +#define SAR_SRAM_FB0_32_TOP 0x01bff +#define SAR_SRAM_FB1_32_BASE 0x01c00 +#define SAR_SRAM_FB1_32_TOP 0x01fff +#define SAR_SRAM_FB2_32_BASE 0x02000 +#define SAR_SRAM_FB2_32_TOP 0x023ff +#define SAR_SRAM_FB3_32_BASE 0x02400 +#define SAR_SRAM_FB3_32_TOP 0x027ff +#define SAR_SRAM_SCD_32_BASE 0x02800 +#define SAR_SRAM_SCD_32_TOP 0x03fff +#define SAR_SRAM_TST1_32_BASE 0x04000 +#define SAR_SRAM_TST1_32_TOP 0x04fff +#define SAR_SRAM_TST2_32_BASE 0x05000 +#define SAR_SRAM_TST2_32_TOP 0x05fff +#define SAR_SRAM_ABRSTD_32_BASE 0x06000 +#define SAR_SRAM_ABRSTD_32_TOP 0x067ff +#define SAR_SRAM_RT_32_BASE 0x06800 +#define SAR_SRAM_RT_32_TOP 0x06fff +#define SAR_SRAM_FIFO_32_BASE 0x07000 +#define SAR_SRAM_FIFO_32_TOP 0x07fff + + +/*****************************************************************************/ +/* */ +/* TSR - Transmit Status Request */ +/* */ +/*****************************************************************************/ + +#define SAR_TSR_TYPE_TSR 0x80000000 +#define SAR_TSR_TYPE_TBD 0x00000000 +#define SAR_TSR_TSIF 0x20000000 +#define SAR_TSR_TAG_MASK 0x01F00000 + + +/*****************************************************************************/ +/* */ +/* TBD - Transmit Buffer Descriptor */ +/* */ +/*****************************************************************************/ + +#define SAR_TBD_EPDU 0x40000000 +#define SAR_TBD_TSIF 0x20000000 +#define SAR_TBD_OAM 0x10000000 +#define SAR_TBD_AAL0 0x00000000 +#define SAR_TBD_AAL34 0x04000000 +#define SAR_TBD_AAL5 0x08000000 +#define SAR_TBD_GTSI 0x02000000 +#define SAR_TBD_TAG_MASK 0x01F00000 + +#define SAR_TBD_VPI_MASK 0x0FF00000 +#define SAR_TBD_VCI_MASK 0x000FFFF0 +#define SAR_TBD_VC_MASK (SAR_TBD_VPI_MASK | SAR_TBD_VCI_MASK) + +#define SAR_TBD_VPI_SHIFT 20 +#define SAR_TBD_VCI_SHIFT 4 + + +/*****************************************************************************/ +/* */ +/* RXFD - Receive FIFO Descriptor */ +/* */ +/*****************************************************************************/ + +#define SAR_RXFD_SIZE_MASK 0x0F000000 +#define SAR_RXFD_SIZE_512 0x00000000 /* 512 words */ +#define SAR_RXFD_SIZE_1K 0x01000000 /* 1k words */ +#define SAR_RXFD_SIZE_2K 0x02000000 /* 2k words */ +#define SAR_RXFD_SIZE_4K 0x03000000 /* 4k words */ +#define SAR_RXFD_SIZE_8K 0x04000000 /* 8k words */ +#define SAR_RXFD_SIZE_16K 0x05000000 /* 16k words */ +#define SAR_RXFD_SIZE_32K 0x06000000 /* 32k words */ +#define SAR_RXFD_SIZE_64K 0x07000000 /* 64k words */ +#define SAR_RXFD_SIZE_128K 0x08000000 /* 128k words */ +#define SAR_RXFD_SIZE_256K 0x09000000 /* 256k words */ +#define SAR_RXFD_ADDR_MASK 0x001ffc00 + + +/*****************************************************************************/ +/* */ +/* ABRSTD - ABR + VBR Schedule Tables */ +/* */ +/*****************************************************************************/ + +#define SAR_ABRSTD_SIZE_MASK 0x07000000 +#define SAR_ABRSTD_SIZE_512 0x00000000 /* 512 words */ +#define SAR_ABRSTD_SIZE_1K 0x01000000 /* 1k words */ +#define SAR_ABRSTD_SIZE_2K 0x02000000 /* 2k words */ +#define SAR_ABRSTD_SIZE_4K 0x03000000 /* 4k words */ +#define SAR_ABRSTD_SIZE_8K 0x04000000 /* 8k words */ +#define SAR_ABRSTD_SIZE_16K 0x05000000 /* 16k words */ +#define SAR_ABRSTD_ADDR_MASK 0x001ffc00 + + +/*****************************************************************************/ +/* */ +/* RCTE - Receive Connection Table Entry */ +/* */ +/*****************************************************************************/ + +#define SAR_RCTE_IL_MASK 0xE0000000 /* inactivity limit */ +#define SAR_RCTE_IC_MASK 0x1C000000 /* inactivity count */ +#define SAR_RCTE_RSVD 0x02000000 /* reserved */ +#define SAR_RCTE_LCD 0x01000000 /* last cell data */ +#define SAR_RCTE_CI_VC 0x00800000 /* EFCI in previous cell of VC */ +#define SAR_RCTE_FBP_01 0x00000000 /* 1. cell->FBQ0, others->FBQ1 */ +#define SAR_RCTE_FBP_1 0x00200000 /* use FBQ 1 for all cells */ +#define SAR_RCTE_FBP_2 0x00400000 /* use FBQ 2 for all cells */ +#define SAR_RCTE_FBP_3 0x00600000 /* use FBQ 3 for all cells */ +#define SAR_RCTE_NZ_GFC 0x00100000 /* non zero GFC in all cell of VC */ +#define SAR_RCTE_CONNECTOPEN 0x00080000 /* VC is open */ +#define SAR_RCTE_AAL_MASK 0x00070000 /* mask for AAL type field s.b. */ +#define SAR_RCTE_RAWCELLINTEN 0x00008000 /* raw cell interrupt enable */ +#define SAR_RCTE_RXCONCELLADDR 0x00004000 /* RX constant cell address */ +#define SAR_RCTE_BUFFSTAT_MASK 0x00003000 /* buffer status */ +#define SAR_RCTE_EFCI 0x00000800 /* EFCI Congestion flag */ +#define SAR_RCTE_CLP 0x00000400 /* Cell Loss Priority flag */ +#define SAR_RCTE_CRC 0x00000200 /* Recieved CRC Error */ +#define SAR_RCTE_CELLCNT_MASK 0x000001FF /* cell Count */ + +#define SAR_RCTE_AAL0 0x00000000 /* AAL types for ALL field */ +#define SAR_RCTE_AAL34 0x00010000 +#define SAR_RCTE_AAL5 0x00020000 +#define SAR_RCTE_RCQ 0x00030000 +#define SAR_RCTE_OAM 0x00040000 + +#define TCMDQ_START 0x01000000 +#define TCMDQ_LACR 0x02000000 +#define TCMDQ_START_LACR 0x03000000 +#define TCMDQ_INIT_ER 0x04000000 +#define TCMDQ_HALT 0x05000000 + + +struct idt77252_skb_prv { + struct scqe tbd; /* Transmit Buffer Descriptor */ + u32 pool; /* sb_pool index */ + dma_addr_t paddr; /* DMA handle */ + void *vaddr; /* DMA virtual address */ + unsigned int size; /* DMA buffer size */ + struct sk_buff *next; /* next PDU buffer */ +}; + +#define IDT77252_PRV_TBD(skb) \ + (((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->tbd) +#define IDT77252_PRV_POOL(skb) \ + (((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->pool) +#define IDT77252_PRV_PADDR(skb) \ + (((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->paddr) +#define IDT77252_PRV_VADDR(skb) \ + (((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->vaddr) +#define IDT77252_PRV_SIZE(skb) \ + (((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->size) +#define IDT77252_PRV_NEXT(skb) \ + (((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->next) + +/*****************************************************************************/ +/* */ +/* PCI related items */ +/* */ +/*****************************************************************************/ + +#ifndef PCI_VENDOR_ID_IDT +#define PCI_VENDOR_ID_IDT 0x111D +#endif /* PCI_VENDOR_ID_IDT */ + +#ifndef PCI_DEVICE_ID_IDT_IDT77252 +#define PCI_DEVICE_ID_IDT_IDT77252 0x0003 +#endif /* PCI_DEVICE_ID_IDT_IDT772052 */ + + +#endif /* !(_IDT77252_H) */ diff -u --recursive --new-file v2.4.14/linux/drivers/atm/idt77252_tables.h linux/drivers/atm/idt77252_tables.h --- v2.4.14/linux/drivers/atm/idt77252_tables.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/idt77252_tables.h Wed Nov 7 14:39:36 2001 @@ -0,0 +1,780 @@ +/* Do not edit, automatically generated by `./genrtbl'. + * + * Cell Line Rate: 353207.55 (155520000 bps) + */ + +static unsigned int log_to_rate[] = +{ +/* 000 */ 0x8d022e27, /* cps = 10.02, nrm = 3, interval = 35264.00 */ +/* 001 */ 0x8d362e11, /* cps = 10.42, nrm = 3, interval = 33856.00 */ +/* 002 */ 0x8d6e2bf8, /* cps = 10.86, nrm = 3, interval = 32512.00 */ +/* 003 */ 0x8da82bcf, /* cps = 11.31, nrm = 3, interval = 31200.00 */ +/* 004 */ 0x8de42ba8, /* cps = 11.78, nrm = 3, interval = 29952.00 */ +/* 005 */ 0x8e242b82, /* cps = 12.28, nrm = 3, interval = 28736.00 */ +/* 006 */ 0x8e662b5e, /* cps = 12.80, nrm = 3, interval = 27584.00 */ +/* 007 */ 0x8eaa2b3c, /* cps = 13.33, nrm = 3, interval = 26496.00 */ +/* 008 */ 0x8ef22b1a, /* cps = 13.89, nrm = 3, interval = 25408.00 */ +/* 009 */ 0x8f3e2afa, /* cps = 14.48, nrm = 3, interval = 24384.00 */ +/* 010 */ 0x8f8a2adc, /* cps = 15.08, nrm = 3, interval = 23424.00 */ +/* 011 */ 0x8fdc2abe, /* cps = 15.72, nrm = 3, interval = 22464.00 */ +/* 012 */ 0x90182aa2, /* cps = 16.38, nrm = 3, interval = 21568.00 */ +/* 013 */ 0x90422a87, /* cps = 17.03, nrm = 3, interval = 20704.00 */ +/* 014 */ 0x90702a6d, /* cps = 17.75, nrm = 3, interval = 19872.00 */ +/* 015 */ 0x90a02a54, /* cps = 18.50, nrm = 3, interval = 19072.00 */ +/* 016 */ 0x90d22a3c, /* cps = 19.28, nrm = 3, interval = 18304.00 */ +/* 017 */ 0x91062a25, /* cps = 20.09, nrm = 3, interval = 17568.00 */ +/* 018 */ 0x913c2a0f, /* cps = 20.94, nrm = 3, interval = 16864.00 */ +/* 019 */ 0x917427f3, /* cps = 21.81, nrm = 3, interval = 16176.00 */ +/* 020 */ 0x91b027ca, /* cps = 22.75, nrm = 3, interval = 15520.00 */ +/* 021 */ 0x91ec27a3, /* cps = 23.69, nrm = 3, interval = 14896.00 */ +/* 022 */ 0x922c277e, /* cps = 24.69, nrm = 3, interval = 14304.00 */ +/* 023 */ 0x926e275a, /* cps = 25.72, nrm = 3, interval = 13728.00 */ +/* 024 */ 0x92b42737, /* cps = 26.81, nrm = 3, interval = 13168.00 */ +/* 025 */ 0x92fc2716, /* cps = 27.94, nrm = 3, interval = 12640.00 */ +/* 026 */ 0x934626f6, /* cps = 29.09, nrm = 3, interval = 12128.00 */ +/* 027 */ 0x939426d8, /* cps = 30.31, nrm = 3, interval = 11648.00 */ +/* 028 */ 0x93e426bb, /* cps = 31.56, nrm = 3, interval = 11184.00 */ +/* 029 */ 0x941e269e, /* cps = 32.94, nrm = 3, interval = 10720.00 */ +/* 030 */ 0x944a2683, /* cps = 34.31, nrm = 3, interval = 10288.00 */ +/* 031 */ 0x9476266a, /* cps = 35.69, nrm = 3, interval = 9888.00 */ +/* 032 */ 0x94a62651, /* cps = 37.19, nrm = 3, interval = 9488.00 */ +/* 033 */ 0x94d82639, /* cps = 38.75, nrm = 3, interval = 9104.00 */ +/* 034 */ 0x950c6622, /* cps = 40.38, nrm = 4, interval = 8736.00 */ +/* 035 */ 0x9544660c, /* cps = 42.12, nrm = 4, interval = 8384.00 */ +/* 036 */ 0x957c63ee, /* cps = 43.88, nrm = 4, interval = 8048.00 */ +/* 037 */ 0x95b663c6, /* cps = 45.69, nrm = 4, interval = 7728.00 */ +/* 038 */ 0x95f4639f, /* cps = 47.62, nrm = 4, interval = 7416.00 */ +/* 039 */ 0x96346379, /* cps = 49.62, nrm = 4, interval = 7112.00 */ +/* 040 */ 0x96766356, /* cps = 51.69, nrm = 4, interval = 6832.00 */ +/* 041 */ 0x96bc6333, /* cps = 53.88, nrm = 4, interval = 6552.00 */ +/* 042 */ 0x97046312, /* cps = 56.12, nrm = 4, interval = 6288.00 */ +/* 043 */ 0x974e62f3, /* cps = 58.44, nrm = 4, interval = 6040.00 */ +/* 044 */ 0x979e62d4, /* cps = 60.94, nrm = 4, interval = 5792.00 */ +/* 045 */ 0x97f062b7, /* cps = 63.50, nrm = 4, interval = 5560.00 */ +/* 046 */ 0x9822629b, /* cps = 66.12, nrm = 4, interval = 5336.00 */ +/* 047 */ 0x984e6280, /* cps = 68.88, nrm = 4, interval = 5120.00 */ +/* 048 */ 0x987e6266, /* cps = 71.88, nrm = 4, interval = 4912.00 */ +/* 049 */ 0x98ac624e, /* cps = 74.75, nrm = 4, interval = 4720.00 */ +/* 050 */ 0x98e06236, /* cps = 78.00, nrm = 4, interval = 4528.00 */ +/* 051 */ 0x9914a21f, /* cps = 81.25, nrm = 8, interval = 4344.00 */ +/* 052 */ 0x994aa209, /* cps = 84.62, nrm = 8, interval = 4168.00 */ +/* 053 */ 0x99829fe9, /* cps = 88.12, nrm = 8, interval = 4004.00 */ +/* 054 */ 0x99be9fc1, /* cps = 91.88, nrm = 8, interval = 3844.00 */ +/* 055 */ 0x99fc9f9a, /* cps = 95.75, nrm = 8, interval = 3688.00 */ +/* 056 */ 0x9a3c9f75, /* cps = 99.75, nrm = 8, interval = 3540.00 */ +/* 057 */ 0x9a809f51, /* cps = 104.00, nrm = 8, interval = 3396.00 */ +/* 058 */ 0x9ac49f2f, /* cps = 108.25, nrm = 8, interval = 3260.00 */ +/* 059 */ 0x9b0e9f0e, /* cps = 112.88, nrm = 8, interval = 3128.00 */ +/* 060 */ 0x9b589eef, /* cps = 117.50, nrm = 8, interval = 3004.00 */ +/* 061 */ 0x9ba69ed1, /* cps = 122.38, nrm = 8, interval = 2884.00 */ +/* 062 */ 0x9bf89eb4, /* cps = 127.50, nrm = 8, interval = 2768.00 */ +/* 063 */ 0x9c269e98, /* cps = 132.75, nrm = 8, interval = 2656.00 */ +/* 064 */ 0x9c549e7d, /* cps = 138.50, nrm = 8, interval = 2548.00 */ +/* 065 */ 0x9c849e63, /* cps = 144.50, nrm = 8, interval = 2444.00 */ +/* 066 */ 0x9cb29e4b, /* cps = 150.25, nrm = 8, interval = 2348.00 */ +/* 067 */ 0x9ce69e33, /* cps = 156.75, nrm = 8, interval = 2252.00 */ +/* 068 */ 0x9d1cde1c, /* cps = 163.50, nrm = 16, interval = 2160.00 */ +/* 069 */ 0x9d50de07, /* cps = 170.00, nrm = 16, interval = 2076.00 */ +/* 070 */ 0x9d8adbe4, /* cps = 177.25, nrm = 16, interval = 1992.00 */ +/* 071 */ 0x9dc4dbbc, /* cps = 184.50, nrm = 16, interval = 1912.00 */ +/* 072 */ 0x9e02db96, /* cps = 192.25, nrm = 16, interval = 1836.00 */ +/* 073 */ 0x9e42db71, /* cps = 200.25, nrm = 16, interval = 1762.00 */ +/* 074 */ 0x9e86db4d, /* cps = 208.75, nrm = 16, interval = 1690.00 */ +/* 075 */ 0x9ecedb2b, /* cps = 217.75, nrm = 16, interval = 1622.00 */ +/* 076 */ 0x9f16db0a, /* cps = 226.75, nrm = 16, interval = 1556.00 */ +/* 077 */ 0x9f62daeb, /* cps = 236.25, nrm = 16, interval = 1494.00 */ +/* 078 */ 0x9fb2dacd, /* cps = 246.25, nrm = 16, interval = 1434.00 */ +/* 079 */ 0xa002dab0, /* cps = 256.50, nrm = 16, interval = 1376.00 */ +/* 080 */ 0xa02eda94, /* cps = 267.50, nrm = 16, interval = 1320.00 */ +/* 081 */ 0xa05ada7a, /* cps = 278.50, nrm = 16, interval = 1268.00 */ +/* 082 */ 0xa088da60, /* cps = 290.00, nrm = 16, interval = 1216.00 */ +/* 083 */ 0xa0b8da48, /* cps = 302.00, nrm = 16, interval = 1168.00 */ +/* 084 */ 0xa0ecda30, /* cps = 315.00, nrm = 16, interval = 1120.00 */ +/* 085 */ 0xa1211a1a, /* cps = 328.00, nrm = 32, interval = 1076.00 */ +/* 086 */ 0xa1591a04, /* cps = 342.00, nrm = 32, interval = 1032.00 */ +/* 087 */ 0xa19117df, /* cps = 356.00, nrm = 32, interval = 991.00 */ +/* 088 */ 0xa1cd17b7, /* cps = 371.00, nrm = 32, interval = 951.00 */ +/* 089 */ 0xa20b1791, /* cps = 386.50, nrm = 32, interval = 913.00 */ +/* 090 */ 0xa24d176c, /* cps = 403.00, nrm = 32, interval = 876.00 */ +/* 091 */ 0xa28f1749, /* cps = 419.50, nrm = 32, interval = 841.00 */ +/* 092 */ 0xa2d71727, /* cps = 437.50, nrm = 32, interval = 807.00 */ +/* 093 */ 0xa31f1707, /* cps = 455.50, nrm = 32, interval = 775.00 */ +/* 094 */ 0xa36d16e7, /* cps = 475.00, nrm = 32, interval = 743.00 */ +/* 095 */ 0xa3bd16c9, /* cps = 495.00, nrm = 32, interval = 713.00 */ +/* 096 */ 0xa40716ad, /* cps = 515.00, nrm = 32, interval = 685.00 */ +/* 097 */ 0xa4331691, /* cps = 537.00, nrm = 32, interval = 657.00 */ +/* 098 */ 0xa45f1677, /* cps = 559.00, nrm = 32, interval = 631.00 */ +/* 099 */ 0xa48f165d, /* cps = 583.00, nrm = 32, interval = 605.00 */ +/* 100 */ 0xa4bf1645, /* cps = 607.00, nrm = 32, interval = 581.00 */ +/* 101 */ 0xa4f1162e, /* cps = 632.00, nrm = 32, interval = 558.00 */ +/* 102 */ 0xa5291617, /* cps = 660.00, nrm = 32, interval = 535.00 */ +/* 103 */ 0xa55f1602, /* cps = 687.00, nrm = 32, interval = 514.00 */ +/* 104 */ 0xa59913da, /* cps = 716.00, nrm = 32, interval = 493.00 */ +/* 105 */ 0xa5d513b2, /* cps = 746.00, nrm = 32, interval = 473.00 */ +/* 106 */ 0xa613138c, /* cps = 777.00, nrm = 32, interval = 454.00 */ +/* 107 */ 0xa6551368, /* cps = 810.00, nrm = 32, interval = 436.00 */ +/* 108 */ 0xa6971345, /* cps = 843.00, nrm = 32, interval = 418.50 */ +/* 109 */ 0xa6df1323, /* cps = 879.00, nrm = 32, interval = 401.50 */ +/* 110 */ 0xa7291303, /* cps = 916.00, nrm = 32, interval = 385.50 */ +/* 111 */ 0xa77512e4, /* cps = 954.00, nrm = 32, interval = 370.00 */ +/* 112 */ 0xa7c512c6, /* cps = 994.00, nrm = 32, interval = 355.00 */ +/* 113 */ 0xa80d12a9, /* cps = 1036.00, nrm = 32, interval = 340.50 */ +/* 114 */ 0xa839128e, /* cps = 1080.00, nrm = 32, interval = 327.00 */ +/* 115 */ 0xa8651274, /* cps = 1124.00, nrm = 32, interval = 314.00 */ +/* 116 */ 0xa895125a, /* cps = 1172.00, nrm = 32, interval = 301.00 */ +/* 117 */ 0xa8c71242, /* cps = 1222.00, nrm = 32, interval = 289.00 */ +/* 118 */ 0xa8f9122b, /* cps = 1272.00, nrm = 32, interval = 277.50 */ +/* 119 */ 0xa92f1214, /* cps = 1326.00, nrm = 32, interval = 266.00 */ +/* 120 */ 0xa9670ffe, /* cps = 1382.00, nrm = 32, interval = 255.50 */ +/* 121 */ 0xa9a10fd5, /* cps = 1440.00, nrm = 32, interval = 245.25 */ +/* 122 */ 0xa9db0fae, /* cps = 1498.00, nrm = 32, interval = 235.50 */ +/* 123 */ 0xaa1b0f88, /* cps = 1562.00, nrm = 32, interval = 226.00 */ +/* 124 */ 0xaa5d0f63, /* cps = 1628.00, nrm = 32, interval = 216.75 */ +/* 125 */ 0xaaa10f41, /* cps = 1696.00, nrm = 32, interval = 208.25 */ +/* 126 */ 0xaae90f1f, /* cps = 1768.00, nrm = 32, interval = 199.75 */ +/* 127 */ 0xab330eff, /* cps = 1842.00, nrm = 32, interval = 191.75 */ +/* 128 */ 0xab7f0ee0, /* cps = 1918.00, nrm = 32, interval = 184.00 */ +/* 129 */ 0xabd10ec2, /* cps = 2000.00, nrm = 32, interval = 176.50 */ +/* 130 */ 0xac110ea6, /* cps = 2080.00, nrm = 32, interval = 169.50 */ +/* 131 */ 0xac3d0e8b, /* cps = 2168.00, nrm = 32, interval = 162.75 */ +/* 132 */ 0xac6d0e70, /* cps = 2264.00, nrm = 32, interval = 156.00 */ +/* 133 */ 0xac9b0e57, /* cps = 2356.00, nrm = 32, interval = 149.75 */ +/* 134 */ 0xaccd0e3f, /* cps = 2456.00, nrm = 32, interval = 143.75 */ +/* 135 */ 0xacff0e28, /* cps = 2556.00, nrm = 32, interval = 138.00 */ +/* 136 */ 0xad350e12, /* cps = 2664.00, nrm = 32, interval = 132.50 */ +/* 137 */ 0xad6d0bf9, /* cps = 2776.00, nrm = 32, interval = 127.12 */ +/* 138 */ 0xada70bd0, /* cps = 2892.00, nrm = 32, interval = 122.00 */ +/* 139 */ 0xade30ba9, /* cps = 3012.00, nrm = 32, interval = 117.12 */ +/* 140 */ 0xae230b83, /* cps = 3140.00, nrm = 32, interval = 112.38 */ +/* 141 */ 0xae650b5f, /* cps = 3272.00, nrm = 32, interval = 107.88 */ +/* 142 */ 0xaeab0b3c, /* cps = 3412.00, nrm = 32, interval = 103.50 */ +/* 143 */ 0xaef10b1b, /* cps = 3552.00, nrm = 32, interval = 99.38 */ +/* 144 */ 0xaf3b0afb, /* cps = 3700.00, nrm = 32, interval = 95.38 */ +/* 145 */ 0xaf8b0adc, /* cps = 3860.00, nrm = 32, interval = 91.50 */ +/* 146 */ 0xafd90abf, /* cps = 4016.00, nrm = 32, interval = 87.88 */ +/* 147 */ 0xb0170aa3, /* cps = 4184.00, nrm = 32, interval = 84.38 */ +/* 148 */ 0xb0430a87, /* cps = 4360.00, nrm = 32, interval = 80.88 */ +/* 149 */ 0xb0710a6d, /* cps = 4544.00, nrm = 32, interval = 77.62 */ +/* 150 */ 0xb0a10a54, /* cps = 4736.00, nrm = 32, interval = 74.50 */ +/* 151 */ 0xb0d30a3c, /* cps = 4936.00, nrm = 32, interval = 71.50 */ +/* 152 */ 0xb1070a25, /* cps = 5144.00, nrm = 32, interval = 68.62 */ +/* 153 */ 0xb13d0a0f, /* cps = 5360.00, nrm = 32, interval = 65.88 */ +/* 154 */ 0xb17507f4, /* cps = 5584.00, nrm = 32, interval = 63.25 */ +/* 155 */ 0xb1af07cb, /* cps = 5816.00, nrm = 32, interval = 60.69 */ +/* 156 */ 0xb1eb07a4, /* cps = 6056.00, nrm = 32, interval = 58.25 */ +/* 157 */ 0xb22b077f, /* cps = 6312.00, nrm = 32, interval = 55.94 */ +/* 158 */ 0xb26d075b, /* cps = 6576.00, nrm = 32, interval = 53.69 */ +/* 159 */ 0xb2b30738, /* cps = 6856.00, nrm = 32, interval = 51.50 */ +/* 160 */ 0xb2fb0717, /* cps = 7144.00, nrm = 32, interval = 49.44 */ +/* 161 */ 0xb34506f7, /* cps = 7440.00, nrm = 32, interval = 47.44 */ +/* 162 */ 0xb39306d9, /* cps = 7752.00, nrm = 32, interval = 45.56 */ +/* 163 */ 0xb3e506bb, /* cps = 8080.00, nrm = 32, interval = 43.69 */ +/* 164 */ 0xb41d069f, /* cps = 8416.00, nrm = 32, interval = 41.94 */ +/* 165 */ 0xb4490684, /* cps = 8768.00, nrm = 32, interval = 40.25 */ +/* 166 */ 0xb477066a, /* cps = 9136.00, nrm = 32, interval = 38.62 */ +/* 167 */ 0xb4a70651, /* cps = 9520.00, nrm = 32, interval = 37.06 */ +/* 168 */ 0xb4d90639, /* cps = 9920.00, nrm = 32, interval = 35.56 */ +/* 169 */ 0xb50d0622, /* cps = 10336.00, nrm = 32, interval = 34.12 */ +/* 170 */ 0xb545060c, /* cps = 10784.00, nrm = 32, interval = 32.75 */ +/* 171 */ 0xb57b03ef, /* cps = 11216.00, nrm = 32, interval = 31.47 */ +/* 172 */ 0xb5b503c7, /* cps = 11680.00, nrm = 32, interval = 30.22 */ +/* 173 */ 0xb5f303a0, /* cps = 12176.00, nrm = 32, interval = 29.00 */ +/* 174 */ 0xb633037a, /* cps = 12688.00, nrm = 32, interval = 27.81 */ +/* 175 */ 0xb6750357, /* cps = 13216.00, nrm = 32, interval = 26.72 */ +/* 176 */ 0xb6bb0334, /* cps = 13776.00, nrm = 32, interval = 25.62 */ +/* 177 */ 0xb7030313, /* cps = 14352.00, nrm = 32, interval = 24.59 */ +/* 178 */ 0xb74f02f3, /* cps = 14960.00, nrm = 32, interval = 23.59 */ +/* 179 */ 0xb79d02d5, /* cps = 15584.00, nrm = 32, interval = 22.66 */ +/* 180 */ 0xb7ed02b8, /* cps = 16224.00, nrm = 32, interval = 21.75 */ +/* 181 */ 0xb821029c, /* cps = 16896.00, nrm = 32, interval = 20.88 */ +/* 182 */ 0xb84f0281, /* cps = 17632.00, nrm = 32, interval = 20.03 */ +/* 183 */ 0xb87d0267, /* cps = 18368.00, nrm = 32, interval = 19.22 */ +/* 184 */ 0xb8ad024e, /* cps = 19136.00, nrm = 32, interval = 18.44 */ +/* 185 */ 0xb8dd0237, /* cps = 19904.00, nrm = 32, interval = 17.72 */ +/* 186 */ 0xb9130220, /* cps = 20768.00, nrm = 32, interval = 17.00 */ +/* 187 */ 0xb949020a, /* cps = 21632.00, nrm = 32, interval = 16.31 */ +/* 188 */ 0xb98301f5, /* cps = 22560.00, nrm = 32, interval = 15.66 */ +/* 189 */ 0xb9bd01e1, /* cps = 23488.00, nrm = 32, interval = 15.03 */ +/* 190 */ 0xb9fd01cd, /* cps = 24512.00, nrm = 32, interval = 14.41 */ +/* 191 */ 0xba3b01bb, /* cps = 25504.00, nrm = 32, interval = 13.84 */ +/* 192 */ 0xba7f01a9, /* cps = 26592.00, nrm = 32, interval = 13.28 */ +/* 193 */ 0xbac30198, /* cps = 27680.00, nrm = 32, interval = 12.75 */ +/* 194 */ 0xbb0f0187, /* cps = 28896.00, nrm = 32, interval = 12.22 */ +/* 195 */ 0xbb570178, /* cps = 30048.00, nrm = 32, interval = 11.75 */ +/* 196 */ 0xbbab0168, /* cps = 31392.00, nrm = 32, interval = 11.25 */ +/* 197 */ 0xbbf9015a, /* cps = 32640.00, nrm = 32, interval = 10.81 */ +/* 198 */ 0xbc27014c, /* cps = 33984.00, nrm = 32, interval = 10.38 */ +/* 199 */ 0xbc53013f, /* cps = 35392.00, nrm = 32, interval = 9.97 */ +/* 200 */ 0xbc830132, /* cps = 36928.00, nrm = 32, interval = 9.56 */ +/* 201 */ 0xbcb50125, /* cps = 38528.00, nrm = 32, interval = 9.16 */ +/* 202 */ 0xbce5011a, /* cps = 40064.00, nrm = 32, interval = 8.81 */ +/* 203 */ 0xbd1d010e, /* cps = 41856.00, nrm = 32, interval = 8.44 */ +/* 204 */ 0xbd530103, /* cps = 43584.00, nrm = 32, interval = 8.09 */ +/* 205 */ 0xbd8b00f9, /* cps = 45376.00, nrm = 32, interval = 7.78 */ +/* 206 */ 0xbdc500ef, /* cps = 47232.00, nrm = 32, interval = 7.47 */ +/* 207 */ 0xbe0700e5, /* cps = 49344.00, nrm = 32, interval = 7.16 */ +/* 208 */ 0xbe4500dc, /* cps = 51328.00, nrm = 32, interval = 6.88 */ +/* 209 */ 0xbe8900d3, /* cps = 53504.00, nrm = 32, interval = 6.59 */ +/* 210 */ 0xbecb00cb, /* cps = 55616.00, nrm = 32, interval = 6.34 */ +/* 211 */ 0xbf1d00c2, /* cps = 58240.00, nrm = 32, interval = 6.06 */ +/* 212 */ 0xbf6100bb, /* cps = 60416.00, nrm = 32, interval = 5.84 */ +/* 213 */ 0xbfb500b3, /* cps = 63104.00, nrm = 32, interval = 5.59 */ +/* 214 */ 0xc00300ac, /* cps = 65664.00, nrm = 32, interval = 5.38 */ +/* 215 */ 0xc02f00a5, /* cps = 68480.00, nrm = 32, interval = 5.16 */ +/* 216 */ 0xc05d009e, /* cps = 71424.00, nrm = 32, interval = 4.94 */ +/* 217 */ 0xc0890098, /* cps = 74240.00, nrm = 32, interval = 4.75 */ +/* 218 */ 0xc0b90092, /* cps = 77312.00, nrm = 32, interval = 4.56 */ +/* 219 */ 0xc0ed008c, /* cps = 80640.00, nrm = 32, interval = 4.38 */ +/* 220 */ 0xc1250086, /* cps = 84224.00, nrm = 32, interval = 4.19 */ +/* 221 */ 0xc1590081, /* cps = 87552.00, nrm = 32, interval = 4.03 */ +/* 222 */ 0xc191007c, /* cps = 91136.00, nrm = 32, interval = 3.88 */ +/* 223 */ 0xc1cd0077, /* cps = 94976.00, nrm = 32, interval = 3.72 */ +/* 224 */ 0xc20d0072, /* cps = 99072.00, nrm = 32, interval = 3.56 */ +/* 225 */ 0xc255006d, /* cps = 103680.00, nrm = 32, interval = 3.41 */ +/* 226 */ 0xc2910069, /* cps = 107520.00, nrm = 32, interval = 3.28 */ +/* 227 */ 0xc2d50065, /* cps = 111872.00, nrm = 32, interval = 3.16 */ +/* 228 */ 0xc32f0060, /* cps = 117632.00, nrm = 32, interval = 3.00 */ +/* 229 */ 0xc36b005d, /* cps = 121472.00, nrm = 32, interval = 2.91 */ +/* 230 */ 0xc3c10059, /* cps = 126976.00, nrm = 32, interval = 2.78 */ +/* 231 */ 0xc40f0055, /* cps = 132864.00, nrm = 32, interval = 2.66 */ +/* 232 */ 0xc4350052, /* cps = 137728.00, nrm = 32, interval = 2.56 */ +/* 233 */ 0xc46d004e, /* cps = 144896.00, nrm = 32, interval = 2.44 */ +/* 234 */ 0xc499004b, /* cps = 150528.00, nrm = 32, interval = 2.34 */ +/* 235 */ 0xc4cb0048, /* cps = 156928.00, nrm = 32, interval = 2.25 */ +/* 236 */ 0xc4ff0045, /* cps = 163584.00, nrm = 32, interval = 2.16 */ +/* 237 */ 0xc5250043, /* cps = 168448.00, nrm = 32, interval = 2.09 */ +/* 238 */ 0xc5630040, /* cps = 176384.00, nrm = 32, interval = 2.00 */ +/* 239 */ 0xc5a7003d, /* cps = 185088.00, nrm = 32, interval = 1.91 */ +/* 240 */ 0xc5d9003b, /* cps = 191488.00, nrm = 32, interval = 1.84 */ +/* 241 */ 0xc6290038, /* cps = 201728.00, nrm = 32, interval = 1.75 */ +/* 242 */ 0xc6630036, /* cps = 209152.00, nrm = 32, interval = 1.69 */ +/* 243 */ 0xc6a30034, /* cps = 217344.00, nrm = 32, interval = 1.62 */ +/* 244 */ 0xc6e70032, /* cps = 226048.00, nrm = 32, interval = 1.56 */ +/* 245 */ 0xc72f0030, /* cps = 235264.00, nrm = 32, interval = 1.50 */ +/* 246 */ 0xc77f002e, /* cps = 245504.00, nrm = 32, interval = 1.44 */ +/* 247 */ 0xc7d7002c, /* cps = 256768.00, nrm = 32, interval = 1.38 */ +/* 248 */ 0xc81b002a, /* cps = 268800.00, nrm = 32, interval = 1.31 */ +/* 249 */ 0xc84f0028, /* cps = 282112.00, nrm = 32, interval = 1.25 */ +/* 250 */ 0xc86d0027, /* cps = 289792.00, nrm = 32, interval = 1.22 */ +/* 251 */ 0xc8a90025, /* cps = 305152.00, nrm = 32, interval = 1.16 */ +/* 252 */ 0xc8cb0024, /* cps = 313856.00, nrm = 32, interval = 1.12 */ +/* 253 */ 0xc9130022, /* cps = 332288.00, nrm = 32, interval = 1.06 */ +/* 254 */ 0xc9390021, /* cps = 342016.00, nrm = 32, interval = 1.03 */ +/* 255 */ 0xc9630020, /* cps = 352768.00, nrm = 32, interval = 1.00 */ +}; + +static unsigned char rate_to_log[] = +{ +/* 1.00 => 0 */ 0x00, /* => 10.02 */ +/* 1.06 => 0 */ 0x00, /* => 10.02 */ +/* 1.12 => 0 */ 0x00, /* => 10.02 */ +/* 1.19 => 0 */ 0x00, /* => 10.02 */ +/* 1.25 => 0 */ 0x00, /* => 10.02 */ +/* 1.31 => 0 */ 0x00, /* => 10.02 */ +/* 1.38 => 0 */ 0x00, /* => 10.02 */ +/* 1.44 => 0 */ 0x00, /* => 10.02 */ +/* 1.50 => 0 */ 0x00, /* => 10.02 */ +/* 1.56 => 0 */ 0x00, /* => 10.02 */ +/* 1.62 => 0 */ 0x00, /* => 10.02 */ +/* 1.69 => 0 */ 0x00, /* => 10.02 */ +/* 1.75 => 0 */ 0x00, /* => 10.02 */ +/* 1.81 => 0 */ 0x00, /* => 10.02 */ +/* 1.88 => 0 */ 0x00, /* => 10.02 */ +/* 1.94 => 0 */ 0x00, /* => 10.02 */ +/* 2.00 => 0 */ 0x00, /* => 10.02 */ +/* 2.12 => 0 */ 0x00, /* => 10.02 */ +/* 2.25 => 0 */ 0x00, /* => 10.02 */ +/* 2.38 => 0 */ 0x00, /* => 10.02 */ +/* 2.50 => 0 */ 0x00, /* => 10.02 */ +/* 2.62 => 0 */ 0x00, /* => 10.02 */ +/* 2.75 => 0 */ 0x00, /* => 10.02 */ +/* 2.88 => 0 */ 0x00, /* => 10.02 */ +/* 3.00 => 0 */ 0x00, /* => 10.02 */ +/* 3.12 => 0 */ 0x00, /* => 10.02 */ +/* 3.25 => 0 */ 0x00, /* => 10.02 */ +/* 3.38 => 0 */ 0x00, /* => 10.02 */ +/* 3.50 => 0 */ 0x00, /* => 10.02 */ +/* 3.62 => 0 */ 0x00, /* => 10.02 */ +/* 3.75 => 0 */ 0x00, /* => 10.02 */ +/* 3.88 => 0 */ 0x00, /* => 10.02 */ +/* 4.00 => 0 */ 0x00, /* => 10.02 */ +/* 4.25 => 0 */ 0x00, /* => 10.02 */ +/* 4.50 => 0 */ 0x00, /* => 10.02 */ +/* 4.75 => 0 */ 0x00, /* => 10.02 */ +/* 5.00 => 0 */ 0x00, /* => 10.02 */ +/* 5.25 => 0 */ 0x00, /* => 10.02 */ +/* 5.50 => 0 */ 0x00, /* => 10.02 */ +/* 5.75 => 0 */ 0x00, /* => 10.02 */ +/* 6.00 => 0 */ 0x00, /* => 10.02 */ +/* 6.25 => 0 */ 0x00, /* => 10.02 */ +/* 6.50 => 0 */ 0x00, /* => 10.02 */ +/* 6.75 => 0 */ 0x00, /* => 10.02 */ +/* 7.00 => 0 */ 0x00, /* => 10.02 */ +/* 7.25 => 0 */ 0x00, /* => 10.02 */ +/* 7.50 => 0 */ 0x00, /* => 10.02 */ +/* 7.75 => 0 */ 0x00, /* => 10.02 */ +/* 8.00 => 0 */ 0x00, /* => 10.02 */ +/* 8.50 => 0 */ 0x00, /* => 10.02 */ +/* 9.00 => 0 */ 0x00, /* => 10.02 */ +/* 9.50 => 0 */ 0x00, /* => 10.02 */ +/* 10.00 => 0 */ 0x00, /* => 10.02 */ +/* 10.50 => 1 */ 0x01, /* => 10.42 */ +/* 11.00 => 2 */ 0x02, /* => 10.86 */ +/* 11.50 => 3 */ 0x03, /* => 11.31 */ +/* 12.00 => 4 */ 0x04, /* => 11.78 */ +/* 12.50 => 5 */ 0x05, /* => 12.28 */ +/* 13.00 => 6 */ 0x06, /* => 12.80 */ +/* 13.50 => 7 */ 0x07, /* => 13.33 */ +/* 14.00 => 8 */ 0x08, /* => 13.89 */ +/* 14.50 => 9 */ 0x09, /* => 14.48 */ +/* 15.00 => 9 */ 0x09, /* => 14.48 */ +/* 15.50 => 10 */ 0x0a, /* => 15.08 */ +/* 16.00 => 11 */ 0x0b, /* => 15.72 */ +/* 17.00 => 12 */ 0x0c, /* => 16.38 */ +/* 18.00 => 14 */ 0x0e, /* => 17.75 */ +/* 19.00 => 15 */ 0x0f, /* => 18.50 */ +/* 20.00 => 16 */ 0x10, /* => 19.28 */ +/* 21.00 => 18 */ 0x12, /* => 20.94 */ +/* 22.00 => 19 */ 0x13, /* => 21.81 */ +/* 23.00 => 20 */ 0x14, /* => 22.75 */ +/* 24.00 => 21 */ 0x15, /* => 23.69 */ +/* 25.00 => 22 */ 0x16, /* => 24.69 */ +/* 26.00 => 23 */ 0x17, /* => 25.72 */ +/* 27.00 => 24 */ 0x18, /* => 26.81 */ +/* 28.00 => 25 */ 0x19, /* => 27.94 */ +/* 29.00 => 25 */ 0x19, /* => 27.94 */ +/* 30.00 => 26 */ 0x1a, /* => 29.09 */ +/* 31.00 => 27 */ 0x1b, /* => 30.31 */ +/* 32.00 => 28 */ 0x1c, /* => 31.56 */ +/* 34.00 => 29 */ 0x1d, /* => 32.94 */ +/* 36.00 => 31 */ 0x1f, /* => 35.69 */ +/* 38.00 => 32 */ 0x20, /* => 37.19 */ +/* 40.00 => 33 */ 0x21, /* => 38.75 */ +/* 42.00 => 34 */ 0x22, /* => 40.38 */ +/* 44.00 => 36 */ 0x24, /* => 43.88 */ +/* 46.00 => 37 */ 0x25, /* => 45.69 */ +/* 48.00 => 38 */ 0x26, /* => 47.62 */ +/* 50.00 => 39 */ 0x27, /* => 49.62 */ +/* 52.00 => 40 */ 0x28, /* => 51.69 */ +/* 54.00 => 41 */ 0x29, /* => 53.88 */ +/* 56.00 => 41 */ 0x29, /* => 53.88 */ +/* 58.00 => 42 */ 0x2a, /* => 56.12 */ +/* 60.00 => 43 */ 0x2b, /* => 58.44 */ +/* 62.00 => 44 */ 0x2c, /* => 60.94 */ +/* 64.00 => 45 */ 0x2d, /* => 63.50 */ +/* 68.00 => 46 */ 0x2e, /* => 66.12 */ +/* 72.00 => 48 */ 0x30, /* => 71.88 */ +/* 76.00 => 49 */ 0x31, /* => 74.75 */ +/* 80.00 => 50 */ 0x32, /* => 78.00 */ +/* 84.00 => 51 */ 0x33, /* => 81.25 */ +/* 88.00 => 52 */ 0x34, /* => 84.62 */ +/* 92.00 => 54 */ 0x36, /* => 91.88 */ +/* 96.00 => 55 */ 0x37, /* => 95.75 */ +/* 100.00 => 56 */ 0x38, /* => 99.75 */ +/* 104.00 => 56 */ 0x38, /* => 99.75 */ +/* 108.00 => 57 */ 0x39, /* => 104.00 */ +/* 112.00 => 58 */ 0x3a, /* => 108.25 */ +/* 116.00 => 59 */ 0x3b, /* => 112.88 */ +/* 120.00 => 60 */ 0x3c, /* => 117.50 */ +/* 124.00 => 61 */ 0x3d, /* => 122.38 */ +/* 128.00 => 62 */ 0x3e, /* => 127.50 */ +/* 136.00 => 63 */ 0x3f, /* => 132.75 */ +/* 144.00 => 64 */ 0x40, /* => 138.50 */ +/* 152.00 => 66 */ 0x42, /* => 150.25 */ +/* 160.00 => 67 */ 0x43, /* => 156.75 */ +/* 168.00 => 68 */ 0x44, /* => 163.50 */ +/* 176.00 => 69 */ 0x45, /* => 170.00 */ +/* 184.00 => 70 */ 0x46, /* => 177.25 */ +/* 192.00 => 71 */ 0x47, /* => 184.50 */ +/* 200.00 => 72 */ 0x48, /* => 192.25 */ +/* 208.00 => 73 */ 0x49, /* => 200.25 */ +/* 216.00 => 74 */ 0x4a, /* => 208.75 */ +/* 224.00 => 75 */ 0x4b, /* => 217.75 */ +/* 232.00 => 76 */ 0x4c, /* => 226.75 */ +/* 240.00 => 77 */ 0x4d, /* => 236.25 */ +/* 248.00 => 78 */ 0x4e, /* => 246.25 */ +/* 256.00 => 78 */ 0x4e, /* => 246.25 */ +/* 272.00 => 80 */ 0x50, /* => 267.50 */ +/* 288.00 => 81 */ 0x51, /* => 278.50 */ +/* 304.00 => 83 */ 0x53, /* => 302.00 */ +/* 320.00 => 84 */ 0x54, /* => 315.00 */ +/* 336.00 => 85 */ 0x55, /* => 328.00 */ +/* 352.00 => 86 */ 0x56, /* => 342.00 */ +/* 368.00 => 87 */ 0x57, /* => 356.00 */ +/* 384.00 => 88 */ 0x58, /* => 371.00 */ +/* 400.00 => 89 */ 0x59, /* => 386.50 */ +/* 416.00 => 90 */ 0x5a, /* => 403.00 */ +/* 432.00 => 91 */ 0x5b, /* => 419.50 */ +/* 448.00 => 92 */ 0x5c, /* => 437.50 */ +/* 464.00 => 93 */ 0x5d, /* => 455.50 */ +/* 480.00 => 94 */ 0x5e, /* => 475.00 */ +/* 496.00 => 95 */ 0x5f, /* => 495.00 */ +/* 512.00 => 95 */ 0x5f, /* => 495.00 */ +/* 544.00 => 97 */ 0x61, /* => 537.00 */ +/* 576.00 => 98 */ 0x62, /* => 559.00 */ +/* 608.00 => 100 */ 0x64, /* => 607.00 */ +/* 640.00 => 101 */ 0x65, /* => 632.00 */ +/* 672.00 => 102 */ 0x66, /* => 660.00 */ +/* 704.00 => 103 */ 0x67, /* => 687.00 */ +/* 736.00 => 104 */ 0x68, /* => 716.00 */ +/* 768.00 => 105 */ 0x69, /* => 746.00 */ +/* 800.00 => 106 */ 0x6a, /* => 777.00 */ +/* 832.00 => 107 */ 0x6b, /* => 810.00 */ +/* 864.00 => 108 */ 0x6c, /* => 843.00 */ +/* 896.00 => 109 */ 0x6d, /* => 879.00 */ +/* 928.00 => 110 */ 0x6e, /* => 916.00 */ +/* 960.00 => 111 */ 0x6f, /* => 954.00 */ +/* 992.00 => 111 */ 0x6f, /* => 954.00 */ +/* 1024.00 => 112 */ 0x70, /* => 994.00 */ +/* 1088.00 => 114 */ 0x72, /* => 1080.00 */ +/* 1152.00 => 115 */ 0x73, /* => 1124.00 */ +/* 1216.00 => 116 */ 0x74, /* => 1172.00 */ +/* 1280.00 => 118 */ 0x76, /* => 1272.00 */ +/* 1344.00 => 119 */ 0x77, /* => 1326.00 */ +/* 1408.00 => 120 */ 0x78, /* => 1382.00 */ +/* 1472.00 => 121 */ 0x79, /* => 1440.00 */ +/* 1536.00 => 122 */ 0x7a, /* => 1498.00 */ +/* 1600.00 => 123 */ 0x7b, /* => 1562.00 */ +/* 1664.00 => 124 */ 0x7c, /* => 1628.00 */ +/* 1728.00 => 125 */ 0x7d, /* => 1696.00 */ +/* 1792.00 => 126 */ 0x7e, /* => 1768.00 */ +/* 1856.00 => 127 */ 0x7f, /* => 1842.00 */ +/* 1920.00 => 128 */ 0x80, /* => 1918.00 */ +/* 1984.00 => 128 */ 0x80, /* => 1918.00 */ +/* 2048.00 => 129 */ 0x81, /* => 2000.00 */ +/* 2176.00 => 131 */ 0x83, /* => 2168.00 */ +/* 2304.00 => 132 */ 0x84, /* => 2264.00 */ +/* 2432.00 => 133 */ 0x85, /* => 2356.00 */ +/* 2560.00 => 135 */ 0x87, /* => 2556.00 */ +/* 2688.00 => 136 */ 0x88, /* => 2664.00 */ +/* 2816.00 => 137 */ 0x89, /* => 2776.00 */ +/* 2944.00 => 138 */ 0x8a, /* => 2892.00 */ +/* 3072.00 => 139 */ 0x8b, /* => 3012.00 */ +/* 3200.00 => 140 */ 0x8c, /* => 3140.00 */ +/* 3328.00 => 141 */ 0x8d, /* => 3272.00 */ +/* 3456.00 => 142 */ 0x8e, /* => 3412.00 */ +/* 3584.00 => 143 */ 0x8f, /* => 3552.00 */ +/* 3712.00 => 144 */ 0x90, /* => 3700.00 */ +/* 3840.00 => 144 */ 0x90, /* => 3700.00 */ +/* 3968.00 => 145 */ 0x91, /* => 3860.00 */ +/* 4096.00 => 146 */ 0x92, /* => 4016.00 */ +/* 4352.00 => 147 */ 0x93, /* => 4184.00 */ +/* 4608.00 => 149 */ 0x95, /* => 4544.00 */ +/* 4864.00 => 150 */ 0x96, /* => 4736.00 */ +/* 5120.00 => 151 */ 0x97, /* => 4936.00 */ +/* 5376.00 => 153 */ 0x99, /* => 5360.00 */ +/* 5632.00 => 154 */ 0x9a, /* => 5584.00 */ +/* 5888.00 => 155 */ 0x9b, /* => 5816.00 */ +/* 6144.00 => 156 */ 0x9c, /* => 6056.00 */ +/* 6400.00 => 157 */ 0x9d, /* => 6312.00 */ +/* 6656.00 => 158 */ 0x9e, /* => 6576.00 */ +/* 6912.00 => 159 */ 0x9f, /* => 6856.00 */ +/* 7168.00 => 160 */ 0xa0, /* => 7144.00 */ +/* 7424.00 => 160 */ 0xa0, /* => 7144.00 */ +/* 7680.00 => 161 */ 0xa1, /* => 7440.00 */ +/* 7936.00 => 162 */ 0xa2, /* => 7752.00 */ +/* 8192.00 => 163 */ 0xa3, /* => 8080.00 */ +/* 8704.00 => 164 */ 0xa4, /* => 8416.00 */ +/* 9216.00 => 166 */ 0xa6, /* => 9136.00 */ +/* 9728.00 => 167 */ 0xa7, /* => 9520.00 */ +/* 10240.00 => 168 */ 0xa8, /* => 9920.00 */ +/* 10752.00 => 169 */ 0xa9, /* => 10336.00 */ +/* 11264.00 => 171 */ 0xab, /* => 11216.00 */ +/* 11776.00 => 172 */ 0xac, /* => 11680.00 */ +/* 12288.00 => 173 */ 0xad, /* => 12176.00 */ +/* 12800.00 => 174 */ 0xae, /* => 12688.00 */ +/* 13312.00 => 175 */ 0xaf, /* => 13216.00 */ +/* 13824.00 => 176 */ 0xb0, /* => 13776.00 */ +/* 14336.00 => 176 */ 0xb0, /* => 13776.00 */ +/* 14848.00 => 177 */ 0xb1, /* => 14352.00 */ +/* 15360.00 => 178 */ 0xb2, /* => 14960.00 */ +/* 15872.00 => 179 */ 0xb3, /* => 15584.00 */ +/* 16384.00 => 180 */ 0xb4, /* => 16224.00 */ +/* 17408.00 => 181 */ 0xb5, /* => 16896.00 */ +/* 18432.00 => 183 */ 0xb7, /* => 18368.00 */ +/* 19456.00 => 184 */ 0xb8, /* => 19136.00 */ +/* 20480.00 => 185 */ 0xb9, /* => 19904.00 */ +/* 21504.00 => 186 */ 0xba, /* => 20768.00 */ +/* 22528.00 => 187 */ 0xbb, /* => 21632.00 */ +/* 23552.00 => 189 */ 0xbd, /* => 23488.00 */ +/* 24576.00 => 190 */ 0xbe, /* => 24512.00 */ +/* 25600.00 => 191 */ 0xbf, /* => 25504.00 */ +/* 26624.00 => 192 */ 0xc0, /* => 26592.00 */ +/* 27648.00 => 192 */ 0xc0, /* => 26592.00 */ +/* 28672.00 => 193 */ 0xc1, /* => 27680.00 */ +/* 29696.00 => 194 */ 0xc2, /* => 28896.00 */ +/* 30720.00 => 195 */ 0xc3, /* => 30048.00 */ +/* 31744.00 => 196 */ 0xc4, /* => 31392.00 */ +/* 32768.00 => 197 */ 0xc5, /* => 32640.00 */ +/* 34816.00 => 198 */ 0xc6, /* => 33984.00 */ +/* 36864.00 => 199 */ 0xc7, /* => 35392.00 */ +/* 38912.00 => 201 */ 0xc9, /* => 38528.00 */ +/* 40960.00 => 202 */ 0xca, /* => 40064.00 */ +/* 43008.00 => 203 */ 0xcb, /* => 41856.00 */ +/* 45056.00 => 204 */ 0xcc, /* => 43584.00 */ +/* 47104.00 => 205 */ 0xcd, /* => 45376.00 */ +/* 49152.00 => 206 */ 0xce, /* => 47232.00 */ +/* 51200.00 => 207 */ 0xcf, /* => 49344.00 */ +/* 53248.00 => 208 */ 0xd0, /* => 51328.00 */ +/* 55296.00 => 209 */ 0xd1, /* => 53504.00 */ +/* 57344.00 => 210 */ 0xd2, /* => 55616.00 */ +/* 59392.00 => 211 */ 0xd3, /* => 58240.00 */ +/* 61440.00 => 212 */ 0xd4, /* => 60416.00 */ +/* 63488.00 => 213 */ 0xd5, /* => 63104.00 */ +/* 65536.00 => 213 */ 0xd5, /* => 63104.00 */ +/* 69632.00 => 215 */ 0xd7, /* => 68480.00 */ +/* 73728.00 => 216 */ 0xd8, /* => 71424.00 */ +/* 77824.00 => 218 */ 0xda, /* => 77312.00 */ +/* 81920.00 => 219 */ 0xdb, /* => 80640.00 */ +/* 86016.00 => 220 */ 0xdc, /* => 84224.00 */ +/* 90112.00 => 221 */ 0xdd, /* => 87552.00 */ +/* 94208.00 => 222 */ 0xde, /* => 91136.00 */ +/* 98304.00 => 223 */ 0xdf, /* => 94976.00 */ +/* 102400.00 => 224 */ 0xe0, /* => 99072.00 */ +/* 106496.00 => 225 */ 0xe1, /* => 103680.00 */ +/* 110592.00 => 226 */ 0xe2, /* => 107520.00 */ +/* 114688.00 => 227 */ 0xe3, /* => 111872.00 */ +/* 118784.00 => 228 */ 0xe4, /* => 117632.00 */ +/* 122880.00 => 229 */ 0xe5, /* => 121472.00 */ +/* 126976.00 => 229 */ 0xe5, /* => 121472.00 */ +/* 131072.00 => 230 */ 0xe6, /* => 126976.00 */ +/* 139264.00 => 232 */ 0xe8, /* => 137728.00 */ +/* 147456.00 => 233 */ 0xe9, /* => 144896.00 */ +/* 155648.00 => 234 */ 0xea, /* => 150528.00 */ +/* 163840.00 => 236 */ 0xec, /* => 163584.00 */ +/* 172032.00 => 237 */ 0xed, /* => 168448.00 */ +/* 180224.00 => 238 */ 0xee, /* => 176384.00 */ +/* 188416.00 => 239 */ 0xef, /* => 185088.00 */ +/* 196608.00 => 240 */ 0xf0, /* => 191488.00 */ +/* 204800.00 => 241 */ 0xf1, /* => 201728.00 */ +/* 212992.00 => 242 */ 0xf2, /* => 209152.00 */ +/* 221184.00 => 243 */ 0xf3, /* => 217344.00 */ +/* 229376.00 => 244 */ 0xf4, /* => 226048.00 */ +/* 237568.00 => 245 */ 0xf5, /* => 235264.00 */ +/* 245760.00 => 246 */ 0xf6, /* => 245504.00 */ +/* 253952.00 => 246 */ 0xf6, /* => 245504.00 */ +/* 262144.00 => 247 */ 0xf7, /* => 256768.00 */ +/* 278528.00 => 248 */ 0xf8, /* => 268800.00 */ +/* 294912.00 => 250 */ 0xfa, /* => 289792.00 */ +/* 311296.00 => 251 */ 0xfb, /* => 305152.00 */ +/* 327680.00 => 252 */ 0xfc, /* => 313856.00 */ +/* 344064.00 => 254 */ 0xfe, /* => 342016.00 */ +/* 360448.00 => 255 */ 0xff, /* => 352768.00 */ +/* 376832.00 => 255 */ 0xff, /* => 352768.00 */ +/* 393216.00 => 255 */ 0xff, /* => 352768.00 */ +/* 409600.00 => 255 */ 0xff, /* => 352768.00 */ +/* 425984.00 => 255 */ 0xff, /* => 352768.00 */ +/* 442368.00 => 255 */ 0xff, /* => 352768.00 */ +/* 458752.00 => 255 */ 0xff, /* => 352768.00 */ +/* 475136.00 => 255 */ 0xff, /* => 352768.00 */ +/* 491520.00 => 255 */ 0xff, /* => 352768.00 */ +/* 507904.00 => 255 */ 0xff, /* => 352768.00 */ +/* 524288.00 => 255 */ 0xff, /* => 352768.00 */ +/* 557056.00 => 255 */ 0xff, /* => 352768.00 */ +/* 589824.00 => 255 */ 0xff, /* => 352768.00 */ +/* 622592.00 => 255 */ 0xff, /* => 352768.00 */ +/* 655360.00 => 255 */ 0xff, /* => 352768.00 */ +/* 688128.00 => 255 */ 0xff, /* => 352768.00 */ +/* 720896.00 => 255 */ 0xff, /* => 352768.00 */ +/* 753664.00 => 255 */ 0xff, /* => 352768.00 */ +/* 786432.00 => 255 */ 0xff, /* => 352768.00 */ +/* 819200.00 => 255 */ 0xff, /* => 352768.00 */ +/* 851968.00 => 255 */ 0xff, /* => 352768.00 */ +/* 884736.00 => 255 */ 0xff, /* => 352768.00 */ +/* 917504.00 => 255 */ 0xff, /* => 352768.00 */ +/* 950272.00 => 255 */ 0xff, /* => 352768.00 */ +/* 983040.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1015808.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1048576.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1114112.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1179648.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1245184.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1310720.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1376256.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1441792.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1507328.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1572864.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1638400.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1703936.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1769472.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1835008.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1900544.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1966080.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2031616.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2097152.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2228224.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2359296.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2490368.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2621440.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2752512.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2883584.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3014656.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3145728.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3276800.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3407872.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3538944.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3670016.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3801088.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3932160.00 => 255 */ 0xff, /* => 352768.00 */ +/* 4063232.00 => 255 */ 0xff, /* => 352768.00 */ +/* 4194304.00 => 255 */ 0xff, /* => 352768.00 */ +/* 4456448.00 => 255 */ 0xff, /* => 352768.00 */ +/* 4718592.00 => 255 */ 0xff, /* => 352768.00 */ +/* 4980736.00 => 255 */ 0xff, /* => 352768.00 */ +/* 5242880.00 => 255 */ 0xff, /* => 352768.00 */ +/* 5505024.00 => 255 */ 0xff, /* => 352768.00 */ +/* 5767168.00 => 255 */ 0xff, /* => 352768.00 */ +/* 6029312.00 => 255 */ 0xff, /* => 352768.00 */ +/* 6291456.00 => 255 */ 0xff, /* => 352768.00 */ +/* 6553600.00 => 255 */ 0xff, /* => 352768.00 */ +/* 6815744.00 => 255 */ 0xff, /* => 352768.00 */ +/* 7077888.00 => 255 */ 0xff, /* => 352768.00 */ +/* 7340032.00 => 255 */ 0xff, /* => 352768.00 */ +/* 7602176.00 => 255 */ 0xff, /* => 352768.00 */ +/* 7864320.00 => 255 */ 0xff, /* => 352768.00 */ +/* 8126464.00 => 255 */ 0xff, /* => 352768.00 */ +/* 8388608.00 => 255 */ 0xff, /* => 352768.00 */ +/* 8912896.00 => 255 */ 0xff, /* => 352768.00 */ +/* 9437184.00 => 255 */ 0xff, /* => 352768.00 */ +/* 9961472.00 => 255 */ 0xff, /* => 352768.00 */ +/* 10485760.00 => 255 */ 0xff, /* => 352768.00 */ +/* 11010048.00 => 255 */ 0xff, /* => 352768.00 */ +/* 11534336.00 => 255 */ 0xff, /* => 352768.00 */ +/* 12058624.00 => 255 */ 0xff, /* => 352768.00 */ +/* 12582912.00 => 255 */ 0xff, /* => 352768.00 */ +/* 13107200.00 => 255 */ 0xff, /* => 352768.00 */ +/* 13631488.00 => 255 */ 0xff, /* => 352768.00 */ +/* 14155776.00 => 255 */ 0xff, /* => 352768.00 */ +/* 14680064.00 => 255 */ 0xff, /* => 352768.00 */ +/* 15204352.00 => 255 */ 0xff, /* => 352768.00 */ +/* 15728640.00 => 255 */ 0xff, /* => 352768.00 */ +/* 16252928.00 => 255 */ 0xff, /* => 352768.00 */ +/* 16777216.00 => 255 */ 0xff, /* => 352768.00 */ +/* 17825792.00 => 255 */ 0xff, /* => 352768.00 */ +/* 18874368.00 => 255 */ 0xff, /* => 352768.00 */ +/* 19922944.00 => 255 */ 0xff, /* => 352768.00 */ +/* 20971520.00 => 255 */ 0xff, /* => 352768.00 */ +/* 22020096.00 => 255 */ 0xff, /* => 352768.00 */ +/* 23068672.00 => 255 */ 0xff, /* => 352768.00 */ +/* 24117248.00 => 255 */ 0xff, /* => 352768.00 */ +/* 25165824.00 => 255 */ 0xff, /* => 352768.00 */ +/* 26214400.00 => 255 */ 0xff, /* => 352768.00 */ +/* 27262976.00 => 255 */ 0xff, /* => 352768.00 */ +/* 28311552.00 => 255 */ 0xff, /* => 352768.00 */ +/* 29360128.00 => 255 */ 0xff, /* => 352768.00 */ +/* 30408704.00 => 255 */ 0xff, /* => 352768.00 */ +/* 31457280.00 => 255 */ 0xff, /* => 352768.00 */ +/* 32505856.00 => 255 */ 0xff, /* => 352768.00 */ +/* 33554432.00 => 255 */ 0xff, /* => 352768.00 */ +/* 35651584.00 => 255 */ 0xff, /* => 352768.00 */ +/* 37748736.00 => 255 */ 0xff, /* => 352768.00 */ +/* 39845888.00 => 255 */ 0xff, /* => 352768.00 */ +/* 41943040.00 => 255 */ 0xff, /* => 352768.00 */ +/* 44040192.00 => 255 */ 0xff, /* => 352768.00 */ +/* 46137344.00 => 255 */ 0xff, /* => 352768.00 */ +/* 48234496.00 => 255 */ 0xff, /* => 352768.00 */ +/* 50331648.00 => 255 */ 0xff, /* => 352768.00 */ +/* 52428800.00 => 255 */ 0xff, /* => 352768.00 */ +/* 54525952.00 => 255 */ 0xff, /* => 352768.00 */ +/* 56623104.00 => 255 */ 0xff, /* => 352768.00 */ +/* 58720256.00 => 255 */ 0xff, /* => 352768.00 */ +/* 60817408.00 => 255 */ 0xff, /* => 352768.00 */ +/* 62914560.00 => 255 */ 0xff, /* => 352768.00 */ +/* 65011712.00 => 255 */ 0xff, /* => 352768.00 */ +/* 67108864.00 => 255 */ 0xff, /* => 352768.00 */ +/* 71303168.00 => 255 */ 0xff, /* => 352768.00 */ +/* 75497472.00 => 255 */ 0xff, /* => 352768.00 */ +/* 79691776.00 => 255 */ 0xff, /* => 352768.00 */ +/* 83886080.00 => 255 */ 0xff, /* => 352768.00 */ +/* 88080384.00 => 255 */ 0xff, /* => 352768.00 */ +/* 92274688.00 => 255 */ 0xff, /* => 352768.00 */ +/* 96468992.00 => 255 */ 0xff, /* => 352768.00 */ +/* 100663296.00 => 255 */ 0xff, /* => 352768.00 */ +/* 104857600.00 => 255 */ 0xff, /* => 352768.00 */ +/* 109051904.00 => 255 */ 0xff, /* => 352768.00 */ +/* 113246208.00 => 255 */ 0xff, /* => 352768.00 */ +/* 117440512.00 => 255 */ 0xff, /* => 352768.00 */ +/* 121634816.00 => 255 */ 0xff, /* => 352768.00 */ +/* 125829120.00 => 255 */ 0xff, /* => 352768.00 */ +/* 130023424.00 => 255 */ 0xff, /* => 352768.00 */ +/* 134217728.00 => 255 */ 0xff, /* => 352768.00 */ +/* 142606336.00 => 255 */ 0xff, /* => 352768.00 */ +/* 150994944.00 => 255 */ 0xff, /* => 352768.00 */ +/* 159383552.00 => 255 */ 0xff, /* => 352768.00 */ +/* 167772160.00 => 255 */ 0xff, /* => 352768.00 */ +/* 176160768.00 => 255 */ 0xff, /* => 352768.00 */ +/* 184549376.00 => 255 */ 0xff, /* => 352768.00 */ +/* 192937984.00 => 255 */ 0xff, /* => 352768.00 */ +/* 201326592.00 => 255 */ 0xff, /* => 352768.00 */ +/* 209715200.00 => 255 */ 0xff, /* => 352768.00 */ +/* 218103808.00 => 255 */ 0xff, /* => 352768.00 */ +/* 226492416.00 => 255 */ 0xff, /* => 352768.00 */ +/* 234881024.00 => 255 */ 0xff, /* => 352768.00 */ +/* 243269632.00 => 255 */ 0xff, /* => 352768.00 */ +/* 251658240.00 => 255 */ 0xff, /* => 352768.00 */ +/* 260046848.00 => 255 */ 0xff, /* => 352768.00 */ +/* 268435456.00 => 255 */ 0xff, /* => 352768.00 */ +/* 285212672.00 => 255 */ 0xff, /* => 352768.00 */ +/* 301989888.00 => 255 */ 0xff, /* => 352768.00 */ +/* 318767104.00 => 255 */ 0xff, /* => 352768.00 */ +/* 335544320.00 => 255 */ 0xff, /* => 352768.00 */ +/* 352321536.00 => 255 */ 0xff, /* => 352768.00 */ +/* 369098752.00 => 255 */ 0xff, /* => 352768.00 */ +/* 385875968.00 => 255 */ 0xff, /* => 352768.00 */ +/* 402653184.00 => 255 */ 0xff, /* => 352768.00 */ +/* 419430400.00 => 255 */ 0xff, /* => 352768.00 */ +/* 436207616.00 => 255 */ 0xff, /* => 352768.00 */ +/* 452984832.00 => 255 */ 0xff, /* => 352768.00 */ +/* 469762048.00 => 255 */ 0xff, /* => 352768.00 */ +/* 486539264.00 => 255 */ 0xff, /* => 352768.00 */ +/* 503316480.00 => 255 */ 0xff, /* => 352768.00 */ +/* 520093696.00 => 255 */ 0xff, /* => 352768.00 */ +/* 536870912.00 => 255 */ 0xff, /* => 352768.00 */ +/* 570425344.00 => 255 */ 0xff, /* => 352768.00 */ +/* 603979776.00 => 255 */ 0xff, /* => 352768.00 */ +/* 637534208.00 => 255 */ 0xff, /* => 352768.00 */ +/* 671088640.00 => 255 */ 0xff, /* => 352768.00 */ +/* 704643072.00 => 255 */ 0xff, /* => 352768.00 */ +/* 738197504.00 => 255 */ 0xff, /* => 352768.00 */ +/* 771751936.00 => 255 */ 0xff, /* => 352768.00 */ +/* 805306368.00 => 255 */ 0xff, /* => 352768.00 */ +/* 838860800.00 => 255 */ 0xff, /* => 352768.00 */ +/* 872415232.00 => 255 */ 0xff, /* => 352768.00 */ +/* 905969664.00 => 255 */ 0xff, /* => 352768.00 */ +/* 939524096.00 => 255 */ 0xff, /* => 352768.00 */ +/* 973078528.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1006632960.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1040187392.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1073741824.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1140850688.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1207959552.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1275068416.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1342177280.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1409286144.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1476395008.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1543503872.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1610612736.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1677721600.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1744830464.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1811939328.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1879048192.00 => 255 */ 0xff, /* => 352768.00 */ +/* 1946157056.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2013265920.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2080374784.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2147483648.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2281701376.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2415919104.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2550136832.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2684354560.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2818572288.00 => 255 */ 0xff, /* => 352768.00 */ +/* 2952790016.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3087007744.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3221225472.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3355443200.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3489660928.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3623878656.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3758096384.00 => 255 */ 0xff, /* => 352768.00 */ +/* 3892314112.00 => 255 */ 0xff, /* => 352768.00 */ +/* 4026531840.00 => 255 */ 0xff, /* => 352768.00 */ +/* 4160749568.00 => 255 */ 0xff, /* => 352768.00 */ +}; diff -u --recursive --new-file v2.4.14/linux/drivers/block/acsi.c linux/drivers/block/acsi.c --- v2.4.14/linux/drivers/block/acsi.c Mon Nov 5 15:55:29 2001 +++ linux/drivers/block/acsi.c Fri Nov 9 13:58:03 2001 @@ -1134,14 +1134,8 @@ put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id ); return 0; - case BLKGETSIZE: /* Return device size */ - return put_user(acsi_part[MINOR(inode->i_rdev)].nr_sects, - (unsigned long *) arg); - - case BLKGETSIZE64: /* Return device size */ - return put_user((u64)acsi_part[MINOR(inode->i_rdev)].nr_sects << 9, - (u64 *) arg); - + case BLKGETSIZE: + case BLKGETSIZE64: case BLKROSET: case BLKROGET: case BLKFLSBUF: diff -u --recursive --new-file v2.4.14/linux/drivers/block/cciss.c linux/drivers/block/cciss.c --- v2.4.14/linux/drivers/block/cciss.c Mon Nov 5 15:55:29 2001 +++ linux/drivers/block/cciss.c Fri Nov 9 14:28:46 2001 @@ -1307,6 +1307,8 @@ if (( c = cmd_alloc(h, 1)) == NULL) goto startio; + blkdev_dequeue_request(creq); + spin_unlock_irq(&io_request_lock); c->cmd_type = CMD_RWREQ; @@ -1386,12 +1388,6 @@ spin_lock_irq(&io_request_lock); - blkdev_dequeue_request(creq); - - /* - * ehh, we can't really end the request here since it's not - * even started yet. for now it shouldn't hurt though - */ addQ(&(h->reqQ),c); h->Qdepth++; if(h->Qdepth > h->maxQsinceinit) @@ -1928,7 +1924,7 @@ /* Initialize the pdev driver private data. have it point to hba[i]. */ - pdev->driver_data = hba[i]; + pci_set_drvdata(pdev, hba[i]); /* command and error info recs zeroed out before they are used */ memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32)); @@ -1987,12 +1983,12 @@ ctlr_info_t *tmp_ptr; int i; - if (pdev->driver_data == NULL) + if (pci_get_drvdata(pdev) == NULL) { printk( KERN_ERR "cciss: Unable to remove device \n"); return; } - tmp_ptr = (ctlr_info_t *) pdev->driver_data; + tmp_ptr = pci_get_drvdata(pdev); i = tmp_ptr->ctlr; if (hba[i] == NULL) { @@ -2003,7 +1999,7 @@ /* Turn board interrupts off */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); free_irq(hba[i]->intr, hba[i]); - pdev->driver_data = NULL; + pci_set_drvdata(pdev, NULL); iounmap((void*)hba[i]->vaddr); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); remove_proc_entry(hba[i]->devname, proc_cciss); diff -u --recursive --new-file v2.4.14/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- v2.4.14/linux/drivers/block/cpqarray.c Mon Nov 5 15:55:29 2001 +++ linux/drivers/block/cpqarray.c Fri Nov 9 14:28:46 2001 @@ -942,6 +942,8 @@ if ((c = cmd_alloc(h,1)) == NULL) goto startio; + blkdev_dequeue_request(creq); + spin_unlock_irq(&io_request_lock); bh = creq->bh; @@ -987,13 +989,10 @@ DBGPX( printk("Submitting %d sectors in %d segments\n", sect, seg); ); c->req.hdr.sg_cnt = seg; c->req.hdr.blk_cnt = creq->nr_sectors; - - spin_lock_irq(&io_request_lock); - - blkdev_dequeue_request(creq); - c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE; c->type = CMD_RWREQ; + + spin_lock_irq(&io_request_lock); /* Put the request on the tail of the request queue */ addQ(&h->reqQ, c); diff -u --recursive --new-file v2.4.14/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.4.14/linux/drivers/block/loop.c Mon Nov 5 15:55:29 2001 +++ linux/drivers/block/loop.c Fri Nov 9 14:25:04 2001 @@ -186,6 +186,8 @@ data = bh->b_data; while (len > 0) { int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize; + int transfer_result; + size = PAGE_CACHE_SIZE - offset; if (size > len) size = len; @@ -197,28 +199,31 @@ goto unlock; kaddr = page_address(page); flush_dcache_page(page); - if (lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV)) - goto write_fail; + transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV); + if (transfer_result) { + /* + * The transfer failed, but we still write the data to + * keep prepare/commit calls balanced. + */ + printk(KERN_ERR "loop: transfer error block %ld\n", index); + memset(kaddr + offset, 0, size); + } if (aops->commit_write(file, page, offset, offset+size)) goto unlock; + if (transfer_result) + goto unlock; data += size; len -= size; offset = 0; index++; pos += size; UnlockPage(page); - deactivate_page(page); page_cache_release(page); } return 0; -write_fail: - printk(KERN_ERR "loop: transfer error block %ld\n", index); - ClearPageUptodate(page); - kunmap(page); unlock: UnlockPage(page); - deactivate_page(page); page_cache_release(page); fail: return -1; diff -u --recursive --new-file v2.4.14/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c --- v2.4.14/linux/drivers/block/paride/pd.c Mon Nov 5 15:55:29 2001 +++ linux/drivers/block/paride/pd.c Fri Nov 9 13:58:03 2001 @@ -475,18 +475,12 @@ } put_user(pd_hd[dev].start_sect,(long *)&geo->start); return 0; - case BLKGETSIZE: - if (!arg) return -EINVAL; - err = verify_area(VERIFY_WRITE,(unsigned long *) arg,sizeof(unsigned long)); - if (err) return (err); - put_user(pd_hd[dev].nr_sects,(unsigned long *) arg); - return (0); - case BLKGETSIZE64: - return put_user((u64)pd_hd[dev].nr_sects << 9, (u64 *)arg); case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return pd_revalidate(inode->i_rdev); + case BLKGETSIZE: + case BLKGETSIZE64: case BLKROSET: case BLKROGET: case BLKRASET: diff -u --recursive --new-file v2.4.14/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c --- v2.4.14/linux/drivers/block/ps2esdi.c Mon Nov 5 15:55:29 2001 +++ linux/drivers/block/ps2esdi.c Fri Nov 9 14:01:21 2001 @@ -47,6 +47,7 @@ #include <linux/mca.h> #include <linux/init.h> #include <linux/ioport.h> +#include <linux/module.h> #include <asm/system.h> #include <asm/io.h> @@ -1106,24 +1107,13 @@ } break; - case BLKGETSIZE: - if (arg) { - if ((err = verify_area(VERIFY_WRITE, (unsigned long *) arg, sizeof(unsigned long)))) - return (err); - put_user(ps2esdi[MINOR(inode->i_rdev)].nr_sects, (unsigned long *) arg); - - return (0); - } - break; - - case BLKGETSIZE64: - return put_user((u64)ps2esdi[MINOR(inode->i_rdev)].nr_sects << 9, (u64 *) arg); - case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return (ps2esdi_reread_partitions(inode->i_rdev)); + case BLKGETSIZE: + case BLKGETSIZE64: case BLKROSET: case BLKROGET: case BLKRASET: diff -u --recursive --new-file v2.4.14/linux/drivers/block/rd.c linux/drivers/block/rd.c --- v2.4.14/linux/drivers/block/rd.c Mon Nov 5 15:55:29 2001 +++ linux/drivers/block/rd.c Fri Nov 9 14:15:00 2001 @@ -809,9 +809,6 @@ static void __init rd_load_disk(int n) { -#ifdef CONFIG_BLK_DEV_INITRD - extern kdev_t real_root_dev; -#endif if (rd_doload == 0) return; diff -u --recursive --new-file v2.4.14/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.4.14/linux/drivers/block/xd.c Mon Nov 5 15:55:29 2001 +++ linux/drivers/block/xd.c Fri Nov 9 14:01:21 2001 @@ -332,11 +332,6 @@ g.start = xd_struct[MINOR(inode->i_rdev)].start_sect; return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } - case BLKGETSIZE: - if (!arg) return -EINVAL; - return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(unsigned long *) arg); - case BLKGETSIZE64: - return put_user((u64)xd_struct[MINOR(inode->i_rdev)].nr_sects << 9, (u64 *)arg); case HDIO_SET_DMA: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (xdc_busy) return -EBUSY; @@ -355,6 +350,8 @@ return -EACCES; return xd_reread_partitions(inode->i_rdev); + case BLKGETSIZE: + case BLKGETSIZE64: case BLKFLSBUF: case BLKROSET: case BLKROGET: diff -u --recursive --new-file v2.4.14/linux/drivers/char/acpi_serial.c linux/drivers/char/acpi_serial.c --- v2.4.14/linux/drivers/char/acpi_serial.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/acpi_serial.c Fri Nov 9 14:01:21 2001 @@ -0,0 +1,194 @@ +/* + * linux/drivers/char/acpi_serial.c + * + * Copyright (C) 2000 Hewlett-Packard Co. + * Copyright (C) 2000 Khalid Aziz <khalid_aziz@hp.com> + * + * Detect and initialize the headless console serial port defined in + * SPCR table and debug serial port defined in DBGP table + * + */ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/pm.h> +#include <linux/acpi.h> +#include <linux/init.h> +#include <linux/serial.h> +#include <asm/serial.h> +#include <asm/io.h> +#include <linux/acpi_serial.h> +/*#include <asm/acpi-ext.h>*/ + +#undef SERIAL_DEBUG_ACPI + +/* + * Query ACPI tables for a debug and a headless console serial + * port. If found, add them to rs_table[]. A pointer to either SPCR + * or DBGP table is passed as parameter. This function should be called + * before serial_console_init() is called to make sure the SPCR serial + * console will be available for use. IA-64 kernel calls this function + * from within acpi.c when it encounters SPCR or DBGP tables as it parses + * the ACPI 2.0 tables during bootup. + * + */ +void __init setup_serial_acpi(void *tablep) +{ + acpi_ser_t *acpi_ser_p; + struct serial_struct serial_req; + unsigned long iobase; + int global_sys_irq; + +#ifdef SERIAL_DEBUG_ACPI + printk("Entering setup_serial_acpi()\n"); +#endif + + /* Now get the table */ + if (tablep == NULL) { + return; + } + + acpi_ser_p = (acpi_ser_t *)tablep; + + /* + * Perform a sanity check on the table. Table should have a + * signature of "SPCR" or "DBGP" and it should be atleast 52 bytes + * long. + */ + if ((strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, + ACPI_SIG_LEN) != 0) && + (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, + ACPI_SIG_LEN) != 0)) { + return; + } + if (acpi_ser_p->length < 52) { + return; + } + + iobase = (((u64) acpi_ser_p->base_addr.addrh) << 32) | acpi_ser_p->base_addr.addrl; + global_sys_irq = (acpi_ser_p->global_int[3] << 24) | + (acpi_ser_p->global_int[2] << 16) | + (acpi_ser_p->global_int[1] << 8) | + acpi_ser_p->global_int[0]; + +#ifdef SERIAL_DEBUG_ACPI + printk("setup_serial_acpi(): table pointer = 0x%p\n", acpi_ser_p); + printk(" sig = '%c%c%c%c'\n", + acpi_ser_p->signature[0], + acpi_ser_p->signature[1], + acpi_ser_p->signature[2], + acpi_ser_p->signature[3]); + printk(" length = %d\n", acpi_ser_p->length); + printk(" Rev = %d\n", acpi_ser_p->rev); + printk(" Interface type = %d\n", acpi_ser_p->intfc_type); + printk(" Base address = 0x%lX\n", iobase); + printk(" IRQ = %d\n", acpi_ser_p->irq); + printk(" Global System Int = %d\n", global_sys_irq); + printk(" Baud rate = "); + switch (acpi_ser_p->baud) { + case ACPI_SERIAL_BAUD_9600: + printk("9600\n"); + break; + + case ACPI_SERIAL_BAUD_19200: + printk("19200\n"); + break; + + case ACPI_SERIAL_BAUD_57600: + printk("57600\n"); + break; + + case ACPI_SERIAL_BAUD_115200: + printk("115200\n"); + break; + + default: + printk("Huh (%d)\n", acpi_ser_p->baud); + break; + + } + if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) { + printk(" PCI serial port:\n"); + printk(" Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n", + acpi_ser_p->pci_bus, acpi_ser_p->pci_dev, + acpi_ser_p->pci_vendor_id, acpi_ser_p->pci_dev_id); + } +#endif + + /* + * Now build a serial_req structure to update the entry in + * rs_table for the headless console port. + */ + switch (acpi_ser_p->intfc_type) { + case ACPI_SERIAL_INTFC_16550: + serial_req.type = PORT_16550; + serial_req.baud_base = BASE_BAUD; + break; + + case ACPI_SERIAL_INTFC_16450: + serial_req.type = PORT_16450; + serial_req.baud_base = BASE_BAUD; + break; + + default: + serial_req.type = PORT_UNKNOWN; + break; + } + if (strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, + ACPI_SIG_LEN) == 0) { + serial_req.line = ACPI_SERIAL_CONSOLE_PORT; + } + else if (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, + ACPI_SIG_LEN) == 0) { + serial_req.line = ACPI_SERIAL_DEBUG_PORT; + } + /* + * Check if this is an I/O mapped address or a memory mapped address + */ + if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_MEM_SPACE) { + serial_req.port = 0; + serial_req.port_high = 0; + serial_req.iomem_base = (void *)ioremap(iobase, 64); + serial_req.io_type = SERIAL_IO_MEM; + } + else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_IO_SPACE) { + serial_req.port = (unsigned long) iobase & 0xffffffff; + serial_req.port_high = (unsigned long)(((u64)iobase) >> 32); + serial_req.iomem_base = NULL; + serial_req.io_type = SERIAL_IO_PORT; + } + else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) { + printk("WARNING: No support for PCI serial console\n"); + return; + } + + /* + * If the table does not have IRQ information, use 0 for IRQ. + * This will force rs_init() to probe for IRQ. + */ + if (acpi_ser_p->length < 53) { + serial_req.irq = 0; + } + else { + if (acpi_ser_p->int_type & + (ACPI_SERIAL_INT_APIC | ACPI_SERIAL_INT_SAPIC)) { + serial_req.irq = global_sys_irq; + } + else if (acpi_ser_p->int_type & ACPI_SERIAL_INT_PCAT) { + serial_req.irq = acpi_ser_p->irq; + } + } + + serial_req.flags = ASYNC_SKIP_TEST | ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ; + serial_req.xmit_fifo_size = serial_req.custom_divisor = 0; + serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0; + serial_req.iomem_reg_shift = 0; + if (early_serial_setup(&serial_req) < 0) { + printk("early_serial_setup() for ACPI serial console port failed\n"); + return; + } + +#ifdef SERIAL_DEBUG_ACPI + printk("Leaving setup_serial_acpi()\n"); +#endif +} diff -u --recursive --new-file v2.4.14/linux/drivers/char/agp/agp.h linux/drivers/char/agp/agp.h --- v2.4.14/linux/drivers/char/agp/agp.h Tue Oct 9 17:06:51 2001 +++ linux/drivers/char/agp/agp.h Fri Nov 9 14:01:21 2001 @@ -170,12 +170,27 @@ #ifndef PCI_DEVICE_ID_INTEL_810_0 #define PCI_DEVICE_ID_INTEL_810_0 0x7120 #endif +#ifndef PCI_DEVICE_ID_INTEL_830_M_0 +#define PCI_DEVICE_ID_INTEL_830_M_0 0x3575 +#endif +#ifndef PCI_DEVICE_ID_INTEL_830_M_1 +#define PCI_DEVICE_ID_INTEL_830_M_1 0x3577 +#endif +#ifndef PCI_DEVICE_ID_INTEL_820_0 +#define PCI_DEVICE_ID_INTEL_820_0 0x2500 +#endif #ifndef PCI_DEVICE_ID_INTEL_840_0 #define PCI_DEVICE_ID_INTEL_840_0 0x1a21 #endif +#ifndef PCI_DEVICE_ID_INTEL_845_0 +#define PCI_DEVICE_ID_INTEL_845_0 0x1a30 +#endif #ifndef PCI_DEVICE_ID_INTEL_850_0 #define PCI_DEVICE_ID_INTEL_850_0 0x2530 #endif +#ifndef PCI_DEVICE_ID_INTEL_860_0 +#define PCI_DEVICE_ID_INTEL_860_0 0x2532 +#endif #ifndef PCI_DEVICE_ID_INTEL_810_DC100_0 #define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122 #endif @@ -200,12 +215,6 @@ #ifndef PCI_DEVICE_ID_INTEL_815_1 #define PCI_DEVICE_ID_INTEL_815_1 0x1132 #endif -#ifndef PCI_DEVICE_ID_INTEL_830_M_0 -#define PCI_DEVICE_ID_INTEL_830_M_0 0x3575 -#endif -#ifndef PCI_DEVICE_ID_INTEL_830_M_1 -#define PCI_DEVICE_ID_INTEL_830_M_1 0x3577 -#endif #ifndef PCI_DEVICE_ID_INTEL_82443GX_1 #define PCI_DEVICE_ID_INTEL_82443GX_1 0x71a1 #endif @@ -251,14 +260,42 @@ #define INTEL_NBXCFG 0x50 #define INTEL_ERRSTS 0x91 +/* intel i830 registers */ +#define I830_GMCH_CTRL 0x52 +#define I830_GMCH_ENABLED 0x4 +#define I830_GMCH_MEM_MASK 0x1 +#define I830_GMCH_MEM_64M 0x1 +#define I830_GMCH_MEM_128M 0 +#define I830_GMCH_GMS_MASK 0x70 +#define I830_GMCH_GMS_DISABLED 0x00 +#define I830_GMCH_GMS_LOCAL 0x10 +#define I830_GMCH_GMS_STOLEN_512 0x20 +#define I830_GMCH_GMS_STOLEN_1024 0x30 +#define I830_GMCH_GMS_STOLEN_8192 0x40 +#define I830_RDRAM_CHANNEL_TYPE 0x03010 +#define I830_RDRAM_ND(x) (((x) & 0x20) >> 5) +#define I830_RDRAM_DDT(x) (((x) & 0x18) >> 3) + +/* intel i820 registers */ +#define INTEL_I820_RDCR 0x51 +#define INTEL_I820_ERRSTS 0xc8 + /* intel i840 registers */ #define INTEL_I840_MCHCFG 0x50 -#define INTEL_I840_ERRSTS 0xc8 +#define INTEL_I840_ERRSTS 0xc8 + +/* intel i845 registers */ +#define INTEL_I845_AGPM 0x51 +#define INTEL_I845_ERRSTS 0xc8 /* intel i850 registers */ #define INTEL_I850_MCHCFG 0x50 #define INTEL_I850_ERRSTS 0xc8 +/* intel i860 registers */ +#define INTEL_I860_MCHCFG 0x50 +#define INTEL_I860_ERRSTS 0xc8 + /* intel i810 registers */ #define I810_GMADDR 0x10 #define I810_MMADDR 0x14 @@ -277,21 +314,7 @@ #define I810_DRAM_ROW_0 0x00000001 #define I810_DRAM_ROW_0_SDRAM 0x00000001 -/* intel i830 registers */ -#define I830_GMCH_CTRL 0x52 -#define I830_GMCH_ENABLED 0x4 -#define I830_GMCH_MEM_MASK 0x1 -#define I830_GMCH_MEM_64M 0x1 -#define I830_GMCH_MEM_128M 0 -#define I830_GMCH_GMS_MASK 0x70 -#define I830_GMCH_GMS_DISABLED 0x00 -#define I830_GMCH_GMS_LOCAL 0x10 -#define I830_GMCH_GMS_STOLEN_512 0x20 -#define I830_GMCH_GMS_STOLEN_1024 0x30 -#define I830_GMCH_GMS_STOLEN_8192 0x40 -#define I830_RDRAM_CHANNEL_TYPE 0x03010 -#define I830_RDRAM_ND(x) (((x) & 0x20) >> 5) -#define I830_RDRAM_DDT(x) (((x) & 0x18) >> 3) + /* VIA register */ #define VIA_APBASE 0x10 diff -u --recursive --new-file v2.4.14/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c --- v2.4.14/linux/drivers/char/agp/agpgart_be.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/char/agp/agpgart_be.c Fri Nov 9 14:01:21 2001 @@ -387,8 +387,8 @@ /* * Driver routines - start * Currently this module supports the following chipsets: - * i810, i815, 440lx, 440bx, 440gx, i840, i850, via vp3, via mvp3, - * via kx133, via kt133, amd irongate, amd 761, amd 762, ALi M1541, + * i810, i815, 440lx, 440bx, 440gx, i830, i840, i845, i850, i860, via vp3, + * via mvp3, via kx133, via kt133, amd irongate, amd 761, amd 762, ALi M1541, * and generic support for the SiS chipsets. */ @@ -645,6 +645,7 @@ static void agp_generic_resume(void) { + return; } static int agp_generic_free_gatt_table(void) @@ -1398,6 +1399,10 @@ } #endif /* CONFIG_AGP_I810 */ + + #ifdef CONFIG_AGP_INTEL + +#endif /* CONFIG_AGP_I810 */ #ifdef CONFIG_AGP_INTEL @@ -1422,12 +1427,45 @@ return 0; } + +static int intel_8xx_fetch_size(void) +{ + int i; + u8 temp; + aper_size_info_8 *values; + + pci_read_config_byte(agp_bridge.dev, INTEL_APSIZE, &temp); + values = A_SIZE_8(agp_bridge.aperture_sizes); + + for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { + if (temp == values[i].size_value) { + agp_bridge.previous_size = + agp_bridge.current_size = (void *) (values + i); + agp_bridge.aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + static void intel_tlbflush(agp_memory * mem) { pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2200); pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); } + +static void intel_8xx_tlbflush(agp_memory * mem) +{ + u32 temp; + pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp & ~(1 << 7)); + pci_read_config_dword(agp_bridge.dev, INTEL_AGPCTRL, &temp); + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, temp & (1 << 7)); +} + + static void intel_cleanup(void) { u16 temp; @@ -1440,6 +1478,20 @@ previous_size->size_value); } + +static void intel_8xx_cleanup(void) +{ + u16 temp; + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp); + pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9)); + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + previous_size->size_value); +} + + static int intel_configure(void) { u32 temp; @@ -1472,17 +1524,70 @@ return 0; } +static void intel_820_tlbflush(agp_memory * mem) +{ + return; +} + +static void intel_820_cleanup(void) +{ + u8 temp; + aper_size_info_8 *previous_size; + + previous_size = A_SIZE_8(agp_bridge.previous_size); + pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp); + pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR, + temp & ~(1 << 1)); + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + previous_size->size_value); +} + + +static int intel_820_configure(void) +{ + u32 temp; + u8 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* global enable aperture access */ + /* This flag is not accessed through MCHCFG register as in */ + /* i850 chipset. */ + pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp2); + pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR, + temp2 | (1 << 1)); + /* clear any possible AGP-related error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I820_ERRSTS, 0x001c); + return 0; +} + static int intel_840_configure(void) { u32 temp; u16 temp2; - aper_size_info_16 *current_size; + aper_size_info_8 *current_size; - current_size = A_SIZE_16(agp_bridge.current_size); + current_size = A_SIZE_8(agp_bridge.current_size); /* aperture size */ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - (char)current_size->size_value); + current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); @@ -1504,17 +1609,49 @@ return 0; } +static int intel_845_configure(void) +{ + u32 temp; + u8 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* agpm */ + pci_read_config_byte(agp_bridge.dev, INTEL_I845_AGPM, &temp2); + pci_write_config_byte(agp_bridge.dev, INTEL_I845_AGPM, + temp2 | (1 << 1)); + /* clear any possible error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I845_ERRSTS, 0x001c); + return 0; +} + static int intel_850_configure(void) { u32 temp; u16 temp2; - aper_size_info_16 *current_size; + aper_size_info_8 *current_size; - current_size = A_SIZE_16(agp_bridge.current_size); + current_size = A_SIZE_8(agp_bridge.current_size); /* aperture size */ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, - (char)current_size->size_value); + current_size->size_value); /* address to map to */ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); @@ -1536,6 +1673,38 @@ return 0; } +static int intel_860_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_8 *current_size; + + current_size = A_SIZE_8(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* mcgcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, + temp2 | (1 << 9)); + /* clear any possible AGP-related error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I860_ERRSTS, 0xf700); + return 0; +} + static unsigned long intel_mask_memory(unsigned long addr, int type) { /* Memory type is ignored */ @@ -1554,6 +1723,17 @@ {0x00000017, 0} }; +static aper_size_info_8 intel_8xx_sizes[7] = +{ + {256, 65536, 6, 0}, + {128, 32768, 5, 32}, + {64, 16384, 4, 48}, + {32, 8192, 3, 56}, + {16, 4096, 2, 60}, + {8, 2048, 1, 62}, + {4, 1024, 0, 63} +}; + static aper_size_info_16 intel_generic_sizes[7] = { {256, 65536, 6, 0}, @@ -1598,19 +1778,84 @@ (void) pdev; /* unused */ } + +static int __init intel_820_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_820_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_cleanup; + agp_bridge.tlb_flush = intel_820_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + + return 0; + + (void) pdev; /* unused */ +} + + static int __init intel_840_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_generic_sizes; - agp_bridge.size_type = U16_APER_SIZE; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; agp_bridge.dev_private_data = NULL; agp_bridge.needs_scratch_page = FALSE; agp_bridge.configure = intel_840_configure; - agp_bridge.fetch_size = intel_fetch_size; - agp_bridge.cleanup = intel_cleanup; - agp_bridge.tlb_flush = intel_tlbflush; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + +static int __init intel_845_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_845_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; agp_bridge.mask_memory = intel_mask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; @@ -1635,15 +1880,15 @@ { agp_bridge.masks = intel_generic_masks; agp_bridge.num_of_masks = 1; - agp_bridge.aperture_sizes = (void *) intel_generic_sizes; - agp_bridge.size_type = U16_APER_SIZE; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 7; agp_bridge.dev_private_data = NULL; agp_bridge.needs_scratch_page = FALSE; agp_bridge.configure = intel_850_configure; - agp_bridge.fetch_size = intel_fetch_size; - agp_bridge.cleanup = intel_cleanup; - agp_bridge.tlb_flush = intel_tlbflush; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; agp_bridge.mask_memory = intel_mask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; @@ -1664,6 +1909,39 @@ (void) pdev; /* unused */ } +static int __init intel_860_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_8xx_sizes; + agp_bridge.size_type = U8_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_860_configure; + agp_bridge.fetch_size = intel_8xx_fetch_size; + agp_bridge.cleanup = intel_8xx_cleanup; + agp_bridge.tlb_flush = intel_8xx_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + agp_bridge.agp_alloc_page = agp_generic_alloc_page; + agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; + agp_bridge.cant_use_aperture = 0; + + return 0; + + (void) pdev; /* unused */ +} + #endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_VIA @@ -3103,6 +3381,8 @@ agp_bridge.free_by_type = agp_generic_free_by_type; agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page; + agp_bridge.suspend = agp_generic_suspend; + agp_bridge.resume = agp_generic_resume; agp_bridge.cant_use_aperture = 0; pci_read_config_dword(agp_bridge.dev, @@ -3215,6 +3495,12 @@ "AMD", "Irongate", amd_irongate_setup }, + { PCI_DEVICE_ID_AMD_762_0, + PCI_VENDOR_ID_AMD, + AMD_IRONGATE, + "AMD", + "AMD 760MP", + amd_irongate_setup }, { PCI_DEVICE_ID_AMD_761_0, PCI_VENDOR_ID_AMD, AMD_761, @@ -3260,6 +3546,12 @@ "Intel", "i815", intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_820_0, + PCI_VENDOR_ID_INTEL, + INTEL_I820, + "Intel", + "i820", + intel_820_setup }, { PCI_DEVICE_ID_INTEL_830_M_0, PCI_VENDOR_ID_INTEL, INTEL_I830_M, @@ -3272,12 +3564,24 @@ "Intel", "i840", intel_840_setup }, + { PCI_DEVICE_ID_INTEL_845_0, + PCI_VENDOR_ID_INTEL, + INTEL_I845, + "Intel", + "i845", + intel_845_setup }, { PCI_DEVICE_ID_INTEL_850_0, PCI_VENDOR_ID_INTEL, INTEL_I850, "Intel", "i850", intel_850_setup }, + { PCI_DEVICE_ID_INTEL_860_0, + PCI_VENDOR_ID_INTEL, + INTEL_I860, + "Intel", + "i860", + intel_860_setup }, { 0, PCI_VENDOR_ID_INTEL, INTEL_GENERIC, @@ -3288,6 +3592,36 @@ #endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_SIS + { PCI_DEVICE_ID_SI_740, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "740", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_650, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "650", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_645, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "645", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_735, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "735", + sis_generic_setup }, + { PCI_DEVICE_ID_SI_730, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "730", + sis_generic_setup }, { PCI_DEVICE_ID_SI_630, PCI_VENDOR_ID_SI, SIS_GENERIC, @@ -3312,11 +3646,11 @@ "SiS", "530", sis_generic_setup }, - { PCI_DEVICE_ID_SI_735, + { PCI_DEVICE_ID_SI_550, PCI_VENDOR_ID_SI, SIS_GENERIC, "SiS", - "735", + "550", sis_generic_setup }, { 0, PCI_VENDOR_ID_SI, @@ -3530,13 +3864,13 @@ PCI_DEVICE_ID_INTEL_815_1, NULL); if (i810_dev == NULL) { - printk(KERN_ERR PFX "Detected an " + printk(KERN_ERR PFX "agpgart: Detected an " "Intel i815, but could not find the" " secondary device. Assuming a " "non-integrated video card.\n"); break; } - printk(KERN_INFO PFX "Detected an Intel i815 " + printk(KERN_INFO PFX "agpgart: Detected an Intel i815 " "Chipset.\n"); agp_bridge.type = INTEL_I810; return intel_i810_setup(i810_dev); diff -u --recursive --new-file v2.4.14/linux/drivers/char/drm/drm_agpsupport.h linux/drivers/char/drm/drm_agpsupport.h --- v2.4.14/linux/drivers/char/drm/drm_agpsupport.h Thu Oct 18 13:48:13 2001 +++ linux/drivers/char/drm/drm_agpsupport.h Fri Nov 9 15:00:19 2001 @@ -273,7 +273,9 @@ #if LINUX_VERSION_CODE >= 0x020400 case INTEL_I815: head->chipset = "Intel i815"; break; + case INTEL_I820: head->chipset = "Intel i820"; break; case INTEL_I840: head->chipset = "Intel i840"; break; + case INTEL_I845: head->chipset = "Intel i845"; break; case INTEL_I850: head->chipset = "Intel i850"; break; #endif diff -u --recursive --new-file v2.4.14/linux/drivers/char/drm/drm_vm.h linux/drivers/char/drm/drm_vm.h --- v2.4.14/linux/drivers/char/drm/drm_vm.h Mon Nov 5 15:55:29 2001 +++ linux/drivers/char/drm/drm_vm.h Fri Nov 9 15:00:19 2001 @@ -423,7 +423,7 @@ unlock_kernel(); vma->vm_ops = &DRM(vm_dma_ops); - vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + vma->vm_flags |= VM_RESERVED; /* Don't swap */ #if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ /* In Linux 2.2.3 and above, this is @@ -558,7 +558,7 @@ #endif /* Don't let this area swap. Change when DRM_KERNEL advisory is supported. */ - vma->vm_flags |= VM_LOCKED; + vma->vm_flags |= VM_RESERVED; break; case _DRM_SCATTER_GATHER: vma->vm_ops = &DRM(vm_sg_ops); @@ -567,12 +567,12 @@ #else vma->vm_pte = (unsigned long)map; #endif - vma->vm_flags |= VM_LOCKED; + vma->vm_flags |= VM_RESERVED; break; default: return -EINVAL; /* This should never happen. */ } - vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + vma->vm_flags |= VM_RESERVED; /* Don't swap */ #if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ /* In Linux 2.2.3 and above, this is diff -u --recursive --new-file v2.4.14/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.4.14/linux/drivers/char/esp.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/char/esp.c Fri Nov 9 14:01:21 2001 @@ -2123,7 +2123,7 @@ if (info->blocked_open) { if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); @@ -2156,7 +2156,7 @@ while ((serial_in(info, UART_ESI_STAT1) != 0x03) || (serial_in(info, UART_ESI_STAT2) != 0xff)) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(char_time); if (signal_pending(current)) @@ -2170,7 +2170,7 @@ } restore_flags(flags); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); } /* @@ -2203,6 +2203,7 @@ DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; + unsigned long flags; /* * If the device is in the middle of being closed, then block @@ -2274,12 +2275,14 @@ printk("block_til_ready before block: ttys%d, count = %d\n", info->line, info->count); #endif + save_flags(flags); cli(); if (!tty_hung_up_p(filp)) info->count--; - sti(); + restore_flags(flags); info->blocked_open++; while (1) { + save_flags(flags); cli(); if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && (tty->termios->c_cflag & CBAUD)) { @@ -2293,7 +2296,7 @@ serial_out(info, UART_ESI_CMD2, scratch | UART_MCR_DTR | UART_MCR_RTS); } - sti(); + restore_flags(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { @@ -2326,7 +2329,7 @@ #endif schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; diff -u --recursive --new-file v2.4.14/linux/drivers/char/hp_keyb.c linux/drivers/char/hp_keyb.c --- v2.4.14/linux/drivers/char/hp_keyb.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/hp_keyb.c Fri Nov 9 14:01:21 2001 @@ -0,0 +1,519 @@ +/* + * linux/drivers/char/hp_keyb.c + * helper-functions for the keyboard/psaux driver for HP-PARISC workstations + * + * based on pc_keyb.c by Geert Uytterhoeven & Martin Mares + * + * 2000/10/26 Debacker Xavier <debackex@esiee.fr> + * Marteau Thomas <marteaut@esiee.fr> + * Djoudi Malek <djoudim@esiee.fr> + * - fixed some keysym defines + * + * 2001/04/28 Debacker Xavier <debackex@esiee.fr> + * - scancode translation rewritten in handle_at_scancode() + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/ptrace.h> +#include <linux/signal.h> +#include <linux/timer.h> +#include <linux/random.h> +#include <linux/ctype.h> +#include <linux/kbd_ll.h> +#include <linux/init.h> + +#include <asm/bitops.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/system.h> + +#define KBD_REPORT_ERR +#define KBD_REPORT_UNKN + +#define KBD_ESCAPEE0 0xe0 /* in */ +#define KBD_ESCAPEE1 0xe1 /* in */ + +#define ESCE0(x) (0xe000|(x)) +#define ESCE1(x) (0xe100|(x)) + +#define KBD_BAT 0xaa /* in */ +#define KBD_SETLEDS 0xed /* out */ +#define KBD_ECHO 0xee /* in/out */ +#define KBD_BREAK 0xf0 /* in */ +#define KBD_TYPRATEDLY 0xf3 /* out */ +#define KBD_SCANENABLE 0xf4 /* out */ +#define KBD_DEFDISABLE 0xf5 /* out */ +#define KBD_DEFAULT 0xf6 /* out */ +#define KBD_ACK 0xfa /* in */ +#define KBD_DIAGFAIL 0xfd /* in */ +#define KBD_RESEND 0xfe /* in/out */ +#define KBD_RESET 0xff /* out */ + +#define CODE_BREAK 1 +#define CODE_ESCAPEE0 2 +#define CODE_ESCAPEE1 4 +#define CODE_ESCAPE12 8 + +#define K_NONE 0x7f +#define K_ESC 0x01 +#define K_F1 0x3b +#define K_F2 0x3c +#define K_F3 0x3d +#define K_F4 0x3e +#define K_F5 0x3f +#define K_F6 0x40 +#define K_F7 0x41 +#define K_F8 0x42 +#define K_F9 0x43 +#define K_F10 0x44 +#define K_F11 0x57 +#define K_F12 0x58 +#define K_PRNT 0x54 +#define K_SCRL 0x46 +#define K_BRK 0x77 +#define K_AGR 0x29 +#define K_1 0x02 +#define K_2 0x03 +#define K_3 0x04 +#define K_4 0x05 +#define K_5 0x06 +#define K_6 0x07 +#define K_7 0x08 +#define K_8 0x09 +#define K_9 0x0a +#define K_0 0x0b +#define K_MINS 0x0c +#define K_EQLS 0x0d +#define K_BKSP 0x0e +#define K_INS 0x6e +#define K_HOME 0x66 +#define K_PGUP 0x68 +#define K_NUML 0x45 +#define KP_SLH 0x62 +#define KP_STR 0x37 +#define KP_MNS 0x4a +#define K_TAB 0x0f +#define K_Q 0x10 +#define K_W 0x11 +#define K_E 0x12 +#define K_R 0x13 +#define K_T 0x14 +#define K_Y 0x15 +#define K_U 0x16 +#define K_I 0x17 +#define K_O 0x18 +#define K_P 0x19 +#define K_LSBK 0x1a +#define K_RSBK 0x1b +#define K_ENTR 0x1c +#define K_DEL 111 +#define K_END 0x6b +#define K_PGDN 0x6d +#define KP_7 0x47 +#define KP_8 0x48 +#define KP_9 0x49 +#define KP_PLS 0x4e +#define K_CAPS 0x3a +#define K_A 0x1e +#define K_S 0x1f +#define K_D 0x20 +#define K_F 0x21 +#define K_G 0x22 +#define K_H 0x23 +#define K_J 0x24 +#define K_K 0x25 +#define K_L 0x26 +#define K_SEMI 0x27 +#define K_SQOT 0x28 +#define K_HASH K_NONE +#define KP_4 0x4b +#define KP_5 0x4c +#define KP_6 0x4d +#define K_LSFT 0x2a +#define K_BSLH 0x2b +#define K_Z 0x2c +#define K_X 0x2d +#define K_C 0x2e +#define K_V 0x2f +#define K_B 0x30 +#define K_N 0x31 +#define K_M 0x32 +#define K_COMA 0x33 +#define K_DOT 0x34 +#define K_FSLH 0x35 +#define K_RSFT 0x36 +#define K_UP 0x67 +#define KP_1 0x4f +#define KP_2 0x50 +#define KP_3 0x51 +#define KP_ENT 0x60 +#define K_LCTL 0x1d +#define K_LALT 0x38 +#define K_SPCE 0x39 +#define K_RALT 0x64 +#define K_RCTL 0x61 +#define K_LEFT 0x69 +#define K_DOWN 0x6c +#define K_RGHT 0x6a +#define KP_0 0x52 +#define KP_DOT 0x53 + +static unsigned char keycode_translate[256] = +{ +/* 00 */ K_NONE, K_F9 , K_NONE, K_F5 , K_F3 , K_F1 , K_F2 , K_F12 , +/* 08 */ K_NONE, K_F10 , K_F8 , K_F6 , K_F4 , K_TAB , K_AGR , K_NONE, +/* 10 */ K_NONE, K_LALT, K_LSFT, K_NONE, K_LCTL, K_Q , K_1 , K_NONE, +/* 18 */ K_NONE, K_NONE, K_Z , K_S , K_A , K_W , K_2 , K_NONE, +/* 20 */ K_NONE, K_C , K_X , K_D , K_E , K_4 , K_3 , K_NONE, +/* 28 */ K_NONE, K_SPCE, K_V , K_F , K_T , K_R , K_5 , K_NONE, +/* 30 */ K_NONE, K_N , K_B , K_H , K_G , K_Y , K_6 , K_NONE, +/* 38 */ K_NONE, K_NONE, K_M , K_J , K_U , K_7 , K_8 , K_NONE, +/* 40 */ K_NONE, K_COMA, K_K , K_I , K_O , K_0 , K_9 , K_NONE, +/* 48 */ K_NONE, K_DOT , K_FSLH, K_L , K_SEMI, K_P , K_MINS, K_NONE, +/* 50 */ K_NONE, K_NONE, K_SQOT, K_NONE, K_LSBK, K_EQLS, K_NONE, K_NONE, +/* 58 */ K_CAPS, K_RSFT, K_ENTR, K_RSBK, K_NONE, K_BSLH, K_NONE, K_NONE, +/* 60 */ K_NONE, K_HASH, K_NONE, K_NONE, K_NONE, K_NONE, K_BKSP, K_NONE, +/* 68 */ K_NONE, KP_1 , K_NONE, KP_4 , KP_7 , K_NONE, K_NONE, K_NONE, +/* 70 */ KP_0 , KP_DOT, KP_2 , KP_5 , KP_6 , KP_8 , K_ESC , K_NUML, +/* 78 */ K_F11 , KP_PLS, KP_3 , KP_MNS, KP_STR, KP_9 , K_SCRL, K_PRNT, +/* 80 */ K_NONE, K_NONE, K_NONE, K_F7 , K_NONE, K_NONE, K_NONE, K_NONE, +/* 88 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* 90 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* 98 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* a0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* a8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* b0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* b8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* c0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* c8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* d0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* d8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* e0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* e8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* f0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, +/* f8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, KBD_RESEND, K_NONE +}; + +/* ----- the following code stolen from pc_keyb.c */ + + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char hp_ps2kbd_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ +#endif + +/* + * Translation of escaped scancodes to keycodes. + * This is now user-settable. + * The keycodes 1-88,96-111,119 are fairly standard, and + * should probably not be changed - changing might confuse X. + * X also interprets scancode 0x5d (KEY_Begin). + * + * For 1-88 keycode equals scancode. + */ + +#define E0_KPENTER 96 +#define E0_RCTRL 97 +#define E0_KPSLASH 98 +#define E0_PRSCR 99 +#define E0_RALT 100 +#define E0_BREAK 101 /* (control-pause) */ +#define E0_HOME 102 +#define E0_UP 103 +#define E0_PGUP 104 +#define E0_LEFT 105 +#define E0_RIGHT 106 +#define E0_END 107 +#define E0_DOWN 108 +#define E0_PGDN 109 +#define E0_INS 110 +#define E0_DEL 111 + +#define E1_PAUSE 119 + +/* + * The keycodes below are randomly located in 89-95,112-118,120-127. + * They could be thrown away (and all occurrences below replaced by 0), + * but that would force many users to use the `setkeycodes' utility, where + * they needed not before. It does not matter that there are duplicates, as + * long as no duplication occurs for any single keyboard. + */ +#define SC_LIM 89 /* 0x59 == 89 */ + +#define FOCUS_PF1 85 /* actual code! */ +#define FOCUS_PF2 89 +#define FOCUS_PF3 90 +#define FOCUS_PF4 91 +#define FOCUS_PF5 92 +#define FOCUS_PF6 93 +#define FOCUS_PF7 94 +#define FOCUS_PF8 95 +#define FOCUS_PF9 120 +#define FOCUS_PF10 121 +#define FOCUS_PF11 122 +#define FOCUS_PF12 123 + +#define JAP_86 124 +/* tfj@olivia.ping.dk: + * The four keys are located over the numeric keypad, and are + * labelled A1-A4. It's an rc930 keyboard, from + * Regnecentralen/RC International, Now ICL. + * Scancodes: 59, 5a, 5b, 5c. + */ +#define RGN1 124 +#define RGN2 125 +#define RGN3 126 +#define RGN4 127 + +static unsigned char high_keys[128 - SC_LIM] = { + RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ + 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ + FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ + FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ +}; + +/* BTC */ +#define E0_MACRO 112 +/* LK450 */ +#define E0_F13 113 +#define E0_F14 114 +#define E0_HELP 115 +#define E0_DO 116 +#define E0_F17 117 +#define E0_KPMINPLUS 118 +/* + * My OmniKey generates e0 4c for the "OMNI" key and the + * right alt key does nada. [kkoller@nyx10.cs.du.edu] + */ +#define E0_OK 124 +/* + * New microsoft keyboard is rumoured to have + * e0 5b (left window button), e0 5c (right window button), + * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] + * [or: Windows_L, Windows_R, TaskMan] + */ +#define E0_MSLW 125 +#define E0_MSRW 126 +#define E0_MSTM 127 + +static unsigned char e0_keys[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ + E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ + E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ + E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ + E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) +{ + if (scancode < SC_LIM || scancode > 255 || keycode > 127) + return -EINVAL; + if (scancode < 128) + high_keys[scancode - SC_LIM] = keycode; + else + e0_keys[scancode - 128] = keycode; + return 0; +} + +int pckbd_getkeycode(unsigned int scancode) +{ + return + (scancode < SC_LIM || scancode > 255) ? -EINVAL : + (scancode < 128) ? high_keys[scancode - SC_LIM] : + e0_keys[scancode - 128]; +} + +int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + static int prev_scancode; + + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + + /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; + return 0; + } + scancode &= 0x7f; + + if (prev_scancode) { + /* + * usually it will be 0xe0, but a Pause key generates + * e1 1d 45 e1 9d c5 when pressed, and nothing when released + */ + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + *keycode = E1_PAUSE; + prev_scancode = 0; + } else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); +#endif + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + /* + * The keyboard maintains its own internal caps lock and + * num lock statuses. In caps lock mode E0 AA precedes make + * code and E0 2A follows break code. In num lock mode, + * E0 2A precedes make code and E0 AA follows break code. + * We do our own book-keeping, so we will just ignore these. + */ + /* + * For my keyboard there is no caps lock mode, but there are + * both Shift-L and Shift-R modes. The former mode generates + * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. + * So, we should also ignore the latter. - aeb@cwi.nl + */ + if (scancode == 0x2a || scancode == 0x36) + return 0; + + if (e0_keys[scancode]) + *keycode = e0_keys[scancode]; + else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", + scancode); +#endif + return 0; + } + } + } else if (scancode >= SC_LIM) { + /* This happens with the FOCUS 9000 keyboard + Its keys PF1..PF12 are reported to generate + 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f + Moreover, unless repeated, they do not generate + key-down events, so we have to zero up_flag below */ + /* Also, Japanese 86/106 keyboards are reported to + generate 0x73 and 0x7d for \ - and \ | respectively. */ + /* Also, some Brazilian keyboard is reported to produce + 0x73 and 0x7e for \ ? and KP-dot, respectively. */ + + *keycode = high_keys[scancode - SC_LIM]; + + if (!*keycode) { + if (!raw_mode) { +#ifdef KBD_REPORT_UNKN + printk(KERN_INFO "keyboard: unrecognized scancode (%02x)" + " - ignored\n", scancode); +#endif + } + return 0; + } + } else + *keycode = scancode; + + return 1; +} + +/* ----- end of stolen part ------ */ + + +void kbd_reset_setup(void) +{ +} + +void handle_at_scancode(int keyval) +{ + static int brk; + static int esc0; + static int esc1; + int scancode = 0; + + switch (keyval) { + case KBD_BREAK : + /* sets the "release_key" bit when a key is + released. HP keyboard send f0 followed by + the keycode while AT keyboard send the keycode + with this bit set. */ + brk = 0x80; + return; + case KBD_ESCAPEE0 : + /* 2chars sequence, commonly used to differenciate + the two ALT keys and the two ENTER keys and so + on... */ + esc0 = 2; /* e0-xx are 2 chars */ + scancode = keyval; + break; + case KBD_ESCAPEE1 : + /* 3chars sequence, only used by the Pause key. */ + esc1 = 3; /* e1-xx-xx are 3 chars */ + scancode = keyval; + break; +#if 0 + case KBD_RESEND : + /* dunno what to do when it happens. RFC */ + printk(KERN_INFO "keyboard: KBD_RESEND received.\n"); + return; +#endif + case 0x14 : + /* translate e1-14-77-e1-f0-14-f0-77 to + e1-1d-45-e1-9d-c5 (the Pause key) */ + if (esc1==2) scancode = brk | 0x1d; + break; + case 0x77 : + if (esc1==1) scancode = brk | 0x45; + break; + case 0x12 : + /* an extended key is e0-12-e0-xx e0-f0-xx-e0-f0-12 + on HP, while it is e0-2a-e0-xx e0-(xx|80)-f0-aa + on AT. */ + if (esc0==1) scancode = brk | 0x2a; + break; + } + + + /* translates HP scancodes to AT scancodes */ + if (!scancode) scancode = brk | keycode_translate[keyval]; + + + if (!scancode) printk(KERN_INFO "keyboard: unexpected key code %02x\n",keyval); + + /* now behave like an AT keyboard */ + handle_scancode(scancode,!(scancode&0x80)); + + if (esc0) esc0--; + if (esc1) esc1--; + + /* release key bit must be unset for the next key */ + brk = 0; +} + diff -u --recursive --new-file v2.4.14/linux/drivers/char/hp_psaux.c linux/drivers/char/hp_psaux.c --- v2.4.14/linux/drivers/char/hp_psaux.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/hp_psaux.c Fri Nov 9 14:01:21 2001 @@ -0,0 +1,551 @@ +/* + * LASI PS/2 keyboard/psaux driver for HP-PARISC workstations + * + * (c) Copyright 1999 The Puffin Group Inc. + * by Alex deVries <adevries@thepuffingroup.com> + * Copyright 1999, 2000 Philipp Rumpf <prumpf@tux.org> + * + * 2000/10/26 Debacker Xavier (debackex@esiee.fr) + * Marteau Thomas (marteaut@esiee.fr) + * Djoudi Malek (djoudim@esiee.fr) + * fixed leds control + * implemented the psaux and controlled the mouse scancode based on pc_keyb.c + */ + +#include <linux/config.h> + +#include <asm/hardware.h> +#include <asm/keyboard.h> +#include <asm/gsc.h> + +#include <linux/types.h> +#include <linux/ptrace.h> /* interrupt.h wants struct pt_regs defined */ +#include <linux/interrupt.h> +#include <linux/sched.h> /* for request_irq/free_irq */ +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/wait.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/pc_keyb.h> +#include <linux/kbd_kern.h> + +/* mouse includes */ +#include <linux/miscdevice.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/spinlock.h> +#include <linux/smp_lock.h> +#include <asm/uaccess.h> +#include <linux/poll.h> + +/* HP specific LASI PS/2 keyboard and psaux constants */ +#define AUX_REPLY_ACK 0xFA /* Command byte ACK. */ +#define AUX_RECONNECT 0xAA /* scancode when ps2 device is plugged (back) in */ + +#define LASI_PSAUX_OFFSET 0x0100 /* offset from keyboard to psaux port */ + +#define LASI_ID 0x00 /* ID and reset port offsets */ +#define LASI_RESET 0x00 +#define LASI_RCVDATA 0x04 /* receive and transmit port offsets */ +#define LASI_XMTDATA 0x04 +#define LASI_CONTROL 0x08 /* see: control register bits */ +#define LASI_STATUS 0x0C /* see: status register bits */ + +/* control register bits */ +#define LASI_CTRL_ENBL 0x01 /* enable interface */ +#define LASI_CTRL_LPBXR 0x02 /* loopback operation */ +#define LASI_CTRL_DIAG 0x20 /* directly control clock/data line */ +#define LASI_CTRL_DATDIR 0x40 /* data line direct control */ +#define LASI_CTRL_CLKDIR 0x80 /* clock line direct control */ + +/* status register bits */ +#define LASI_STAT_RBNE 0x01 +#define LASI_STAT_TBNE 0x02 +#define LASI_STAT_TERR 0x04 +#define LASI_STAT_PERR 0x08 +#define LASI_STAT_CMPINTR 0x10 +#define LASI_STAT_DATSHD 0x40 +#define LASI_STAT_CLKSHD 0x80 + +static void *lasikbd_hpa; +static void *lasips2_hpa; + + +static inline u8 read_input(void *hpa) +{ + return gsc_readb(hpa+LASI_RCVDATA); +} + +static inline u8 read_control(void *hpa) +{ + return gsc_readb(hpa+LASI_CONTROL); +} + +static inline void write_control(u8 val, void *hpa) +{ + gsc_writeb(val, hpa+LASI_CONTROL); +} + +static inline u8 read_status(void *hpa) +{ + return gsc_readb(hpa+LASI_STATUS); +} + +static int write_output(u8 val, void *hpa) +{ + int wait = 0; + + while (read_status(hpa) & LASI_STAT_TBNE) { + wait++; + if (wait>10000) { + /* printk(KERN_WARNING "Lasi PS/2 transmit buffer timeout\n"); */ + return 0; + } + } + + if (wait) + printk(KERN_DEBUG "Lasi PS/2 wait %d\n", wait); + + gsc_writeb(val, hpa+LASI_XMTDATA); + + return 1; +} + +/* This function is the PA-RISC adaptation of i386 source */ + +static inline int aux_write_ack(u8 val) +{ + return write_output(val, lasikbd_hpa+LASI_PSAUX_OFFSET); +} + +static void lasikbd_leds(unsigned char leds) +{ + write_output(KBD_CMD_SET_LEDS, lasikbd_hpa); + write_output(leds, lasikbd_hpa); + write_output(KBD_CMD_ENABLE, lasikbd_hpa); +} + +#if 0 +/* this might become useful again at some point. not now -prumpf */ +int lasi_ps2_test(void *hpa) +{ + u8 control,c; + int i, ret = 0; + + control = read_control(hpa); + write_control(control | LASI_CTRL_LPBXR | LASI_CTRL_ENBL, hpa); + + for (i=0; i<256; i++) { + write_output(i, hpa); + + while (!(read_status(hpa) & LASI_STAT_RBNE)) + /* just wait */; + + c = read_input(hpa); + if (c != i) + ret--; + } + + write_control(control, hpa); + + return ret; +} +#endif + +static int __init lasi_ps2_reset(void *hpa, int id) +{ + u8 control; + int ret = 1; + + /* reset the interface */ + gsc_writeb(0xff, hpa+LASI_RESET); + gsc_writeb(0x0 , hpa+LASI_RESET); + + /* enable it */ + control = read_control(hpa); + write_control(control | LASI_CTRL_ENBL, hpa); + + /* initializes the leds at the default state */ + if (id==0) { + write_output(KBD_CMD_SET_LEDS, hpa); + write_output(0, hpa); + ret = write_output(KBD_CMD_ENABLE, hpa); + } + + return ret; +} + +static int inited; + +static void lasi_ps2_init_hw(void) +{ + ++inited; +} + + +/* Greatly inspired by pc_keyb.c */ + +/* + * Wait for keyboard controller input buffer to drain. + * + * Don't use 'jiffies' so that we don't depend on + * interrupts.. + * + * Quote from PS/2 System Reference Manual: + * + * "Address hex 0060 and address hex 0064 should be written only when + * the input-buffer-full bit and output-buffer-full bit in the + * Controller Status register are set 0." + */ +#ifdef CONFIG_PSMOUSE + +static struct aux_queue *queue; +static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; +static unsigned char mouse_reply_expected; +static int aux_count; + +static int fasync_aux(int fd, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper(fd, filp, on, &queue->fasync); + if (retval < 0) + return retval; + + return 0; +} + + + +static inline void handle_mouse_scancode(unsigned char scancode) +{ + if (mouse_reply_expected) { + if (scancode == AUX_REPLY_ACK) { + mouse_reply_expected--; + return; + } + mouse_reply_expected = 0; + } + else if (scancode == AUX_RECONNECT) { + queue->head = queue->tail = 0; /* Flush input queue */ + return; + } + + add_mouse_randomness(scancode); + if (aux_count) { + int head = queue->head; + + queue->buf[head] = scancode; + head = (head + 1) & (AUX_BUF_SIZE-1); + + if (head != queue->tail) { + queue->head = head; + kill_fasync(&queue->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&queue->proc_list); + } + } +} + +static inline int queue_empty(void) +{ + return queue->head == queue->tail; +} + +static unsigned char get_from_queue(void) +{ + unsigned char result; + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + + return result; +} + + +/* + * Write to the aux device. + */ + +static ssize_t write_aux(struct file * file, const char * buffer, + size_t count, loff_t *ppos) +{ + ssize_t retval = 0; + + if (count) { + ssize_t written = 0; + + if (count > 32) + count = 32; /* Limit to 32 bytes. */ + do { + char c; + get_user(c, buffer++); + written++; + } while (--count); + retval = -EIO; + if (written) { + retval = written; + file->f_dentry->d_inode->i_mtime = CURRENT_TIME; + } + } + + return retval; +} + + + +static ssize_t read_aux(struct file * file, char * buffer, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + ssize_t i = count; + unsigned char c; + + if (queue_empty()) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&queue->proc_list, &wait); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&queue->proc_list, &wait); + } + while (i > 0 && !queue_empty()) { + c = get_from_queue(); + put_user(c, buffer++); + i--; + } + if (count-i) { + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + return count-i; + } + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + + +static int open_aux(struct inode * inode, struct file * file) +{ + if (aux_count++) + return 0; + + queue->head = queue->tail = 0; /* Flush input queue */ + aux_count = 1; + aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ + + return 0; +} + + +/* No kernel lock held - fine */ +static unsigned int aux_poll(struct file *file, poll_table * wait) +{ + + poll_wait(file, &queue->proc_list, wait); + if (!queue_empty()) + return POLLIN | POLLRDNORM; + return 0; +} + + +static int release_aux(struct inode * inode, struct file * file) +{ + lock_kernel(); + fasync_aux(-1, file, 0); + if (--aux_count) { + unlock_kernel(); + return 0; + } + unlock_kernel(); + return 0; +} + +static struct file_operations psaux_fops = { + read: read_aux, + write: write_aux, + poll: aux_poll, + open: open_aux, + release: release_aux, + fasync: fasync_aux, +}; + +static struct miscdevice psaux_mouse = { + minor: PSMOUSE_MINOR, + name: "psaux", + fops: &psaux_fops, +}; + +#endif /* CONFIG_PSMOUSE */ + + +/* This function is looking at the PS2 controller and empty the two buffers */ + +static u8 handle_lasikbd_event(void *hpa) +{ + u8 status_keyb,status_mouse,scancode,id; + extern void handle_at_scancode(int); /* in drivers/char/keyb_at.c */ + + /* Mask to get the base address of the PS/2 controller */ + id = gsc_readb(hpa+LASI_ID) & 0x0f; + + if (id==1) + hpa -= LASI_PSAUX_OFFSET; + lasikbd_hpa = hpa; + + + status_keyb = read_status(hpa); + status_mouse = read_status(hpa+LASI_PSAUX_OFFSET); + + while ((status_keyb|status_mouse) & LASI_STAT_RBNE){ + + while (status_keyb & LASI_STAT_RBNE) { + + scancode = read_input(hpa); + + /* XXX don't know if this is a valid fix, but filtering + * 0xfa avoids 'unknown scancode' errors on, eg, capslock + * on some keyboards. + */ + if (inited && scancode != 0xfa) + handle_at_scancode(scancode); + + status_keyb =read_status(hpa); + } + +#ifdef CONFIG_PSMOUSE + while (status_mouse & LASI_STAT_RBNE) { + scancode = read_input(hpa+LASI_PSAUX_OFFSET); + handle_mouse_scancode(scancode); + status_mouse = read_status(hpa+LASI_PSAUX_OFFSET); + } + status_mouse = read_status(hpa+LASI_PSAUX_OFFSET); +#endif /* CONFIG_PSMOUSE */ + status_keyb = read_status(hpa); + } + + tasklet_schedule(&keyboard_tasklet); + return (status_keyb|status_mouse); +} + + + + +extern struct pt_regs *kbd_pt_regs; + +static void lasikbd_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + lasips2_hpa = dev; /* save "hpa" for lasikbd_leds() */ + kbd_pt_regs = regs; + handle_lasikbd_event(lasips2_hpa); +} + + +extern int pckbd_translate(unsigned char, unsigned char *, char); + +static struct kbd_ops gsc_ps2_kbd_ops = { + translate: pckbd_translate, + init_hw: lasi_ps2_init_hw, + leds: lasikbd_leds, +#ifdef CONFIG_MAGIC_SYSRQ + sysrq_key: 0x54, + sysrq_xlate: hp_ps2kbd_sysrq_xlate, +#endif +}; + +static int __init +lasi_ps2_register(struct hp_device *d, struct pa_iodc_driver *dri) +{ + void *hpa = (void *) d->hpa; + unsigned int irq; + char *name; + int device_found; + u8 id; + + id = gsc_readb(hpa+LASI_ID) & 0x0f; + + switch (id) { + case 0: + name = "keyboard"; + lasikbd_hpa = hpa; + break; + case 1: + name = "psaux"; + break; + default: + printk(KERN_WARNING "%s: Unknown PS/2 port (id=%d) - ignored.\n", + __FUNCTION__, id ); + return 0; + } + + /* reset the PS/2 port */ + device_found = lasi_ps2_reset(hpa,id); + + /* allocate the irq and memory region for that device */ + if (!(irq = busdevice_alloc_irq(d))) + return -ENODEV; + + if (request_irq(irq, lasikbd_interrupt, 0, name, hpa)) + return -ENODEV; + + if (!request_mem_region((unsigned long)hpa, LASI_STATUS + 4, name)) + return -ENODEV; + + switch (id) { + case 0: + register_kbd_ops(&gsc_ps2_kbd_ops); + break; + case 1: +#ifdef CONFIG_PSMOUSE + queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + return -ENOMEM; + + memset(queue, 0, sizeof(*queue)); + queue->head = queue->tail = 0; + init_waitqueue_head(&queue->proc_list); + + misc_register(&psaux_mouse); + + aux_write_ack(AUX_ENABLE_DEV); + /* try it a second time, this will give status if the device is + * available */ + device_found = aux_write_ack(AUX_ENABLE_DEV); + break; +#else + /* return without printing any unnecessary and misleading info */ + return 0; +#endif + } /* of case */ + + printk(KERN_INFO "PS/2 %s controller at 0x%08lx (irq %d) found, " + "%sdevice attached.\n", + name, (unsigned long)hpa, irq, + device_found ? "":"no "); + + return 0; +} + + +static struct pa_iodc_driver lasi_psaux_drivers_for[] __initdata = { + {HPHW_FIO, 0x0, 0,0x00084, 0, 0, + DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION, + "Lasi psaux", "generic", (void *) lasi_ps2_register}, + { 0, } +}; + +static int __init gsc_ps2_init(void) +{ + return pdc_register_driver(lasi_psaux_drivers_for); +} + +module_init(gsc_ps2_init); + diff -u --recursive --new-file v2.4.14/linux/drivers/char/isicom.c linux/drivers/char/isicom.c --- v2.4.14/linux/drivers/char/isicom.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/char/isicom.c Fri Nov 9 14:01:21 2001 @@ -60,24 +60,27 @@ #include <linux/isicom.h> -static int device_id[] = { 0x2028, - 0x2051, - 0x2052, - 0x2053, - 0x2054, - 0x2055, - 0x2056, - 0x2057, - 0x2058 - }; +static struct pci_device_id isicom_pci_tbl[] = { + { VENDOR_ID, 0x2028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { VENDOR_ID, 0x2058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, isicom_pci_tbl); -static int isicom_refcount = 0; +static int isicom_refcount; static int prev_card = 3; /* start servicing isi_card[0] */ -static struct isi_board * irq_to_board[16] = { NULL, }; +static struct isi_board * irq_to_board[16]; static struct tty_driver isicom_normal, isicom_callout; -static struct tty_struct * isicom_table[PORT_COUNT] = { NULL, }; -static struct termios * isicom_termios[PORT_COUNT] = { NULL, }; -static struct termios * isicom_termios_locked[PORT_COUNT] = { NULL, }; +static struct tty_struct * isicom_table[PORT_COUNT]; +static struct termios * isicom_termios[PORT_COUNT]; +static struct termios * isicom_termios_locked[PORT_COUNT]; static struct isi_board isi_card[BOARD_COUNT]; static struct isi_port isi_ports[PORT_COUNT]; @@ -997,7 +1000,7 @@ } schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); if (!tty_hung_up_p(filp)) port->count++; @@ -1202,7 +1205,7 @@ port->tty = 0; if (port->blocked_open) { if (port->close_delay) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: scheduling until time out.\n"); #endif @@ -1974,7 +1977,7 @@ for (idx=0; idx < DEVID_COUNT; idx++) { dev = NULL; for (;;){ - if (!(dev = pci_find_device(VENDOR_ID, device_id[idx], dev))) + if (!(dev = pci_find_device(VENDOR_ID, isicom_pci_tbl[idx].device, dev))) break; if (card >= BOARD_COUNT) break; @@ -1988,7 +1991,7 @@ * space. */ pciirq = dev->irq; - printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]); + printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", isicom_pci_tbl[idx].device); /* * allot the first empty slot in the array */ @@ -2035,7 +2038,7 @@ void cleanup_module(void) { re_schedule = 0; - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); remove_bh(ISICOM_BH); diff -u --recursive --new-file v2.4.14/linux/drivers/char/joystick/cs461x.c linux/drivers/char/joystick/cs461x.c --- v2.4.14/linux/drivers/char/joystick/cs461x.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/char/joystick/cs461x.c Fri Nov 9 13:41:42 2001 @@ -158,7 +158,7 @@ static int cs461x_free(struct pci_dev *pdev) { - struct gameport *port = (struct gameport *)pdev->driver_data; + struct gameport *port = pci_get_drvdata(pdev); if(port){ gameport_unregister_port(port); kfree(port); @@ -284,7 +284,7 @@ } memset(port, 0, sizeof(struct gameport)); - pdev->driver_data = port; + pci_set_drvdata(pdev, port); port->open = cs461x_gameport_open; port->read = cs461x_gameport_read; diff -u --recursive --new-file v2.4.14/linux/drivers/char/joystick/emu10k1-gp.c linux/drivers/char/joystick/emu10k1-gp.c --- v2.4.14/linux/drivers/char/joystick/emu10k1-gp.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/char/joystick/emu10k1-gp.c Fri Nov 9 13:41:42 2001 @@ -86,7 +86,7 @@ port->gameport.io = ioport; port->size = iolen; port->dev = pdev; - pdev->driver_data = port; + pci_set_drvdata(pdev, port); gameport_register_port(&port->gameport); @@ -98,7 +98,7 @@ static void __devexit emu_remove(struct pci_dev *pdev) { - struct emu *port = (struct emu *)pdev->driver_data; + struct emu *port = pci_get_drvdata(pdev); gameport_unregister_port(&port->gameport); release_region(port->gameport.io, port->size); kfree(port); diff -u --recursive --new-file v2.4.14/linux/drivers/char/joystick/pcigame.c linux/drivers/char/joystick/pcigame.c --- v2.4.14/linux/drivers/char/joystick/pcigame.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/char/joystick/pcigame.c Fri Nov 9 13:41:42 2001 @@ -133,7 +133,7 @@ pcigame->data = pcigame_data + id->driver_data; pcigame->dev = dev; - dev->driver_data = pcigame; + pci_set_drvdata(dev, pcigame); pcigame->gameport.private = pcigame; pcigame->gameport.fuzz = 64; @@ -163,7 +163,7 @@ static void __devexit pcigame_remove(struct pci_dev *dev) { - struct pcigame *pcigame = dev->driver_data; + struct pcigame *pcigame = pci_get_drvdata(dev); gameport_unregister_port(&pcigame->gameport); iounmap(pcigame->base); kfree(pcigame); diff -u --recursive --new-file v2.4.14/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.4.14/linux/drivers/char/pc_keyb.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/char/pc_keyb.c Fri Nov 9 14:01:21 2001 @@ -34,6 +34,7 @@ #include <linux/vt_kern.h> #include <linux/smp_lock.h> #include <linux/kd.h> +#include <linux/pm.h> #include <asm/keyboard.h> #include <asm/bitops.h> @@ -397,29 +398,32 @@ return 0200; } -void pckbd_pm_resume(void) +int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data) { #if defined CONFIG_PSMOUSE unsigned long flags; - if (queue) { /* Aux port detected */ - if (aux_count == 0) { /* Mouse not in use */ - spin_lock_irqsave(&kbd_controller_lock, flags); - /* - * Dell Lat. C600 A06 enables mouse after resume. - * When user touches the pad, it posts IRQ 12 - * (which we do not process), thus holding keyboard. - */ - kbd_write_command(KBD_CCMD_MOUSE_DISABLE); - /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */ - kb_wait(); - kbd_write_command(KBD_CCMD_WRITE_MODE); - kb_wait(); - kbd_write_output(AUX_INTS_OFF); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - } + if (rqst == PM_RESUME) { + if (queue) { /* Aux port detected */ + if (aux_count == 0) { /* Mouse not in use */ + spin_lock_irqsave(&kbd_controller_lock, flags); + /* + * Dell Lat. C600 A06 enables mouse after resume. + * When user touches the pad, it posts IRQ 12 + * (which we do not process), thus holding keyboard. + */ + kbd_write_command(KBD_CCMD_MOUSE_DISABLE); + /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */ + kb_wait(); + kbd_write_command(KBD_CCMD_WRITE_MODE); + kb_wait(); + kbd_write_output(AUX_INTS_OFF); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + } + } } -#endif +#endif + return 0; } diff -u --recursive --new-file v2.4.14/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.4.14/linux/drivers/char/random.c Mon Nov 5 15:55:29 2001 +++ linux/drivers/char/random.c Fri Nov 9 14:01:21 2001 @@ -406,10 +406,6 @@ * *****************************************************************/ -#ifndef MIN -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif - /* * Unfortunately, while the GCC optimizer for the i386 understands how * to optimize a static rotate left of x bits, it doesn't know how to @@ -1360,7 +1356,7 @@ #endif /* Copy data to destination buffer */ - i = MIN(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2); + i = min(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2); if (flags & EXTRACT_ENTROPY_USER) { i -= copy_to_user(buf, (__u8 const *)tmp, i); if (!i) { @@ -1587,7 +1583,7 @@ size_t c = count; while (c > 0) { - bytes = MIN(c, sizeof(buf)); + bytes = min(c, sizeof(buf)); bytes -= copy_from_user(&buf, p, bytes); if (!bytes) { diff -u --recursive --new-file v2.4.14/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.4.14/linux/drivers/char/rtc.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/char/rtc.c Fri Nov 9 14:01:21 2001 @@ -712,8 +712,10 @@ uip_watchdog = jiffies; if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) + while (jiffies - uip_watchdog < 2*HZ/100) { barrier(); + cpu_relax(); + } spin_lock_irq(&rtc_lock); year = CMOS_READ(RTC_YEAR); @@ -946,8 +948,10 @@ */ if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) + while (jiffies - uip_watchdog < 2*HZ/100) { barrier(); + cpu_relax(); + } /* * Only the values that we read from the RTC are set. We leave diff -u --recursive --new-file v2.4.14/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.4.14/linux/drivers/char/serial.c Mon Nov 5 15:55:29 2001 +++ linux/drivers/char/serial.c Fri Nov 9 14:12:55 2001 @@ -85,6 +85,11 @@ * SERIAL_PARANOIA_CHECK * Check the magic number for the async_structure where * ever possible. + * + * CONFIG_SERIAL_ACPI + * Enable support for serial console port and serial + * debug port as defined by the SPCR and DBGP tables in + * ACPI 2.0. */ #include <linux/config.h> @@ -113,6 +118,10 @@ #endif #endif +#ifdef CONFIG_SERIAL_ACPI +#define ENABLE_SERIAL_ACPI +#endif + #if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE)) #ifndef ENABLE_SERIAL_PNP #define ENABLE_SERIAL_PNP @@ -1766,13 +1775,11 @@ if (I_IGNPAR(info->tty)) info->ignore_status_mask |= UART_LSR_OE; } -#if 0 /* breaks serial console during boot stage */ /* * !!! ignore all characters if CREAD is not set */ if ((cflag & CREAD) == 0) info->ignore_status_mask |= UART_LSR_DR; -#endif save_flags(flags); cli(); if (uart_config[info->state->type].flags & UART_STARTECH) { serial_outp(info, UART_LCR, 0xBF); @@ -2243,7 +2250,7 @@ ((CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) > 0) && !info->tty->stopped && !info->tty->hw_stopped)) - result &= TIOCSER_TEMT; + result &= ~TIOCSER_TEMT; if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; @@ -2355,7 +2362,7 @@ autoconfig(info->state); if ((info->state->flags & ASYNC_AUTO_IRQ) && - (info->state->port != 0) && + (info->state->port != 0 || info->state->iomem_base != 0) && (info->state->type != PORT_UNKNOWN)) { irq = detect_uart_irq(info->state); if (irq > 0) @@ -3384,6 +3391,10 @@ " ISAPNP" #define SERIAL_OPT #endif +#ifdef ENABLE_SERIAL_ACPI + " SERIAL_ACPI" +#define SERIAL_OPT +#endif #ifdef SERIAL_OPT " enabled\n"; #else @@ -5475,13 +5486,22 @@ continue; if ( (state->flags & ASYNC_BOOT_AUTOCONF) && (state->flags & ASYNC_AUTO_IRQ) - && (state->port != 0)) + && (state->port != 0 || state->iomem_base != 0)) state->irq = detect_uart_irq(state); - printk(KERN_INFO "ttyS%02d%s at 0x%04lx (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); + if (state->io_type == SERIAL_IO_MEM) { + printk(KERN_INFO"ttyS%02d%s at 0x%px (irq = %d) is a %s\n", + state->line + SERIAL_DEV_OFFSET, + (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", + state->iomem_base, state->irq, + uart_config[state->type].name); + } + else { + printk(KERN_INFO "ttyS%02d%s at 0x%04lx (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); + } tty_register_devfs(&serial_driver, 0, serial_driver.minor_start + state->line); tty_register_devfs(&callout_driver, 0, diff -u --recursive --new-file v2.4.14/linux/drivers/char/serial_tx3912.c linux/drivers/char/serial_tx3912.c --- v2.4.14/linux/drivers/char/serial_tx3912.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/char/serial_tx3912.c Fri Nov 9 14:01:21 2001 @@ -20,7 +20,7 @@ #include <linux/console.h> #include <linux/fs.h> #include <linux/mm.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/pm.h> diff -u --recursive --new-file v2.4.14/linux/drivers/char/specialix.c linux/drivers/char/specialix.c --- v2.4.14/linux/drivers/char/specialix.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/char/specialix.c Fri Nov 9 14:01:21 2001 @@ -969,7 +969,10 @@ if (bp->flags & SX_BOARD_ACTIVE) return 0; - error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp); + if (bp->flags & SX_BOARD_IS_PCI) + error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT | SA_SHIRQ, "specialix IO8+", bp); + else + error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp); if (error) return error; diff -u --recursive --new-file v2.4.14/linux/drivers/char/sx.c linux/drivers/char/sx.c --- v2.4.14/linux/drivers/char/sx.c Sun Sep 23 11:40:57 2001 +++ linux/drivers/char/sx.c Fri Nov 9 14:01:21 2001 @@ -257,6 +257,11 @@ #define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000 #endif +static struct pci_device_id sx_pci_tbl[] = { + { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, sx_pci_tbl); /* Configurable options: (Don't be too sure that it'll work if you toggle them) */ diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/Config.in linux/drivers/hotplug/Config.in --- v2.4.14/linux/drivers/hotplug/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/Config.in Fri Nov 9 14:01:21 2001 @@ -0,0 +1,12 @@ +# +# PCI Hotplug support +# +mainmenu_option next_comment +comment 'PCI Hotplug Support' + +dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_DDFS $CONFIG_EXPERIMENTAL + +dep_tristate ' Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI +dep_mbool ' Save configuration into NVRAM on Compaq servers' CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM $CONFIG_HOTPLUG_PCI_COMPAQ + +endmenu diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/Makefile linux/drivers/hotplug/Makefile --- v2.4.14/linux/drivers/hotplug/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/Makefile Fri Nov 9 14:01:21 2001 @@ -0,0 +1,34 @@ +# +# Makefile for the Linux kernel pci hotplug controller drivers. +# + +O_TARGET := vmlinux-obj.o + +list-multi := cpqphp.o pci_hotplug.o + +export-objs := pci_hotplug_core.o pci_hotplug_util.o + +obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o +obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o + +pci_hotplug-objs := pci_hotplug_core.o \ + pci_hotplug_util.o + +cpqphp-objs := cpqphp_core.o \ + cpqphp_ctrl.o \ + cpqphp_proc.o \ + cpqphp_pci.o + +ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y) + cpqphp-objs += cpqphp_nvram.o +endif + + +include $(TOPDIR)/Rules.make + +pci_hotplug.o: $(pci_hotplug-objs) + $(LD) -r -o $@ $(pci_hotplug-objs) + +cpqphp.o: $(cpqphp-objs) + $(LD) -r -o $@ $(cpqphp-objs) + diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/cpqphp.h linux/drivers/hotplug/cpqphp.h --- v2.4.14/linux/drivers/hotplug/cpqphp.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/cpqphp.h Fri Nov 9 14:01:21 2001 @@ -0,0 +1,751 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <greg@kroah.com> + * + */ +#ifndef _CPQPHP_H +#define _CPQPHP_H + +#include "pci_hotplug.h" +#include <asm/io.h> /* for read? and write? functions */ + + +#if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE) + #define MY_NAME "cpqphp.o" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (cpqhp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + + +struct smbios_system_slot { + u8 type; + u8 length; + u16 handle; + u8 name_string_num; + u8 slot_type; + u8 slot_width; + u8 slot_current_usage; + u8 slot_length; + u16 slot_number; + u8 properties1; + u8 properties2; +} __attribute__ ((packed)); + +/* offsets to the smbios generic type based on the above structure layout */ +enum smbios_system_slot_offsets { + SMBIOS_SLOT_GENERIC_TYPE = offsetof(struct smbios_system_slot, type), + SMBIOS_SLOT_GENERIC_LENGTH = offsetof(struct smbios_system_slot, length), + SMBIOS_SLOT_GENERIC_HANDLE = offsetof(struct smbios_system_slot, handle), + SMBIOS_SLOT_NAME_STRING_NUM = offsetof(struct smbios_system_slot, name_string_num), + SMBIOS_SLOT_TYPE = offsetof(struct smbios_system_slot, slot_type), + SMBIOS_SLOT_WIDTH = offsetof(struct smbios_system_slot, slot_width), + SMBIOS_SLOT_CURRENT_USAGE = offsetof(struct smbios_system_slot, slot_current_usage), + SMBIOS_SLOT_LENGTH = offsetof(struct smbios_system_slot, slot_length), + SMBIOS_SLOT_NUMBER = offsetof(struct smbios_system_slot, slot_number), + SMBIOS_SLOT_PROPERTIES1 = offsetof(struct smbios_system_slot, properties1), + SMBIOS_SLOT_PROPERTIES2 = offsetof(struct smbios_system_slot, properties2), +}; + +struct smbios_generic { + u8 type; + u8 length; + u16 handle; +} __attribute__ ((packed)); + +/* offsets to the smbios generic type based on the above structure layout */ +enum smbios_generic_offsets { + SMBIOS_GENERIC_TYPE = offsetof(struct smbios_generic, type), + SMBIOS_GENERIC_LENGTH = offsetof(struct smbios_generic, length), + SMBIOS_GENERIC_HANDLE = offsetof(struct smbios_generic, handle), +}; + +struct smbios_entry_point { + char anchor[4]; + u8 ep_checksum; + u8 ep_length; + u8 major_version; + u8 minor_version; + u16 max_size_entry; + u8 ep_rev; + u8 reserved[5]; + char int_anchor[5]; + u8 int_checksum; + u16 st_length; + u32 st_address; + u16 number_of_entrys; + u8 bcd_rev; +} __attribute__ ((packed)); + +/* offsets to the smbios entry point based on the above structure layout */ +enum smbios_entry_point_offsets { + ANCHOR = offsetof(struct smbios_entry_point, anchor[0]), + EP_CHECKSUM = offsetof(struct smbios_entry_point, ep_checksum), + EP_LENGTH = offsetof(struct smbios_entry_point, ep_length), + MAJOR_VERSION = offsetof(struct smbios_entry_point, major_version), + MINOR_VERSION = offsetof(struct smbios_entry_point, minor_version), + MAX_SIZE_ENTRY = offsetof(struct smbios_entry_point, max_size_entry), + EP_REV = offsetof(struct smbios_entry_point, ep_rev), + INT_ANCHOR = offsetof(struct smbios_entry_point, int_anchor[0]), + INT_CHECKSUM = offsetof(struct smbios_entry_point, int_checksum), + ST_LENGTH = offsetof(struct smbios_entry_point, st_length), + ST_ADDRESS = offsetof(struct smbios_entry_point, st_address), + NUMBER_OF_ENTRYS = offsetof(struct smbios_entry_point, number_of_entrys), + BCD_REV = offsetof(struct smbios_entry_point, bcd_rev), +}; + +struct ctrl_reg { /* offset */ + u8 slot_RST; /* 0x00 */ + u8 slot_enable; /* 0x01 */ + u16 misc; /* 0x02 */ + u32 led_control; /* 0x04 */ + u32 int_input_clear; /* 0x08 */ + u32 int_mask; /* 0x0a */ + u8 reserved0; /* 0x10 */ + u8 reserved1; /* 0x11 */ + u8 reserved2; /* 0x12 */ + u8 gen_output_AB; /* 0x13 */ + u32 non_int_input; /* 0x14 */ + u32 reserved3; /* 0x18 */ + u32 reserved4; /* 0x1a */ + u32 reserved5; /* 0x20 */ + u8 reserved6; /* 0x24 */ + u8 reserved7; /* 0x25 */ + u16 reserved8; /* 0x26 */ + u8 slot_mask; /* 0x28 */ + u8 reserved9; /* 0x29 */ + u8 reserved10; /* 0x2a */ + u8 reserved11; /* 0x2b */ + u8 slot_SERR; /* 0x2c */ + u8 slot_power; /* 0x2d */ +} __attribute__ ((packed)); + +/* offsets to the controller registers based on the above structure layout */ +enum ctrl_offsets { + SLOT_RST = offsetof(struct ctrl_reg, slot_RST), + SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), + MISC = offsetof(struct ctrl_reg, misc), + LED_CONTROL = offsetof(struct ctrl_reg, led_control), + INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), + INT_MASK = offsetof(struct ctrl_reg, int_mask), + CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), + CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), + CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), + GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), + NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), + CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), + CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), + CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), + CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), + CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), + CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), + SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), + CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), + CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), + CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), + SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), + SLOT_POWER = offsetof(struct ctrl_reg, slot_power), +}; + +struct hrt { + char sig0; + char sig1; + char sig2; + char sig3; + u16 unused_IRQ; + u16 PCIIRQ; + u8 number_of_entries; + u8 revision; + u16 reserved1; + u32 reserved2; +} __attribute__ ((packed)); + +/* offsets to the hotplug resource table registers based on the above structure layout */ +enum hrt_offsets { + SIG0 = offsetof(struct hrt, sig0), + SIG1 = offsetof(struct hrt, sig1), + SIG2 = offsetof(struct hrt, sig2), + SIG3 = offsetof(struct hrt, sig3), + UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), + PCIIRQ = offsetof(struct hrt, PCIIRQ), + NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), + REVISION = offsetof(struct hrt, revision), + HRT_RESERVED1 = offsetof(struct hrt, reserved1), + HRT_RESERVED2 = offsetof(struct hrt, reserved2), +}; + +struct slot_rt { + u8 dev_func; + u8 primary_bus; + u8 secondary_bus; + u8 max_bus; + u16 io_base; + u16 io_length; + u16 mem_base; + u16 mem_length; + u16 pre_mem_base; + u16 pre_mem_length; +} __attribute__ ((packed)); + +/* offsets to the hotplug slot resource table registers based on the above structure layout */ +enum slot_rt_offsets { + DEV_FUNC = offsetof(struct slot_rt, dev_func), + PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), + SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), + MAX_BUS = offsetof(struct slot_rt, max_bus), + IO_BASE = offsetof(struct slot_rt, io_base), + IO_LENGTH = offsetof(struct slot_rt, io_length), + MEM_BASE = offsetof(struct slot_rt, mem_base), + MEM_LENGTH = offsetof(struct slot_rt, mem_length), + PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), + PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), +}; + +struct pci_func { + struct pci_func *next; + u8 bus; + u8 device; + u8 function; + u8 is_a_board; + u16 status; + u8 configured; + u8 switch_save; + u8 presence_save; + u32 base_length[0x06]; + u8 base_type[0x06]; + u16 reserved2; + u32 config_space[0x20]; + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct timer_list *p_task_event; + struct pci_dev* pci_dev; +}; + +#define SLOT_MAGIC 0x67267321 +struct slot { + u32 magic; + struct slot *next; + u8 bus; + u8 device; + u8 number; + u8 is_a_board; + u8 configured; + u8 state; + u8 switch_save; + u8 presence_save; + u32 capabilities; + u16 reserved2; + struct timer_list task_event; + u8 hp_slot; + struct controller *ctrl; + void *p_sm_slot; + struct hotplug_slot *hotplug_slot; +}; + +struct pci_resource { + struct pci_resource * next; + u32 base; + u32 length; +}; + +struct event_info { + u32 event_type; + u8 hp_slot; +}; + +struct controller { + struct controller *next; + u32 ctrl_int_comp; + struct semaphore crit_sect; /* critical section semaphore */ + void *hpc_reg; /* cookie for our pci controller location */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct pci_dev *pci_dev; + struct pci_ops *pci_ops; + struct proc_dir_entry* proc_entry; + struct proc_dir_entry* proc_entry2; + struct event_info event_queue[10]; + struct slot *slot; + u8 next_event; + u8 interrupt; + u8 bus; + u8 device; + u8 function; + u8 rev; + u8 slot_device_offset; + u8 first_slot; + u8 add_support; + u8 push_flag; + u8 speed; /* 0 = 33MHz, 1 = 66MHz */ + u8 speed_capability; /* 0 = 33MHz, 1 = 66MHz */ + u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */ + u8 slot_switch_type; /* 0 = no switch, 1 = switch present */ + u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */ + u8 alternate_base_address; /* 0 = not supported, 1 = supported */ + u8 pci_config_space; /* Index/data access to working registers 0 = not supported, 1 = supported */ + u8 pcix_speed_capability; /* PCI-X */ + u8 pcix_support; /* PCI-X */ + u16 vendor_id; + char proc_name[20]; + char proc_name2[20]; + struct tq_struct int_task_event; + wait_queue_head_t queue; /* sleep & wake process */ +}; + +#define CTRL_SPEED_33MHz 0 +#define CTRL_SPEED_66MHz 1 + +struct irq_mapping { + u8 barber_pole; + u8 valid_INT; + u8 interrupt[4]; +}; + +struct resource_lists { + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct irq_mapping *irqs; +}; + +#define ROM_PHY_ADDR 0x0F0000 +#define ROM_PHY_LEN 0x00ffff + +#define PCI_HPC_ID 0xA0F7 +#define PCI_SUB_HPC_ID 0xA2F7 +#define PCI_SUB_HPC_ID2 0xA2F8 +#define PCI_SUB_HPC_ID3 0xA2F9 +#define PCI_SUB_HPC_ID_INTC 0xA2FA + +#define INT_BUTTON_IGNORE 0 +#define INT_PRESENCE_ON 1 +#define INT_PRESENCE_OFF 2 +#define INT_SWITCH_CLOSE 3 +#define INT_SWITCH_OPEN 4 +#define INT_POWER_FAULT 5 +#define INT_POWER_FAULT_CLEAR 6 +#define INT_BUTTON_PRESS 7 +#define INT_BUTTON_RELEASE 8 +#define INT_BUTTON_CANCEL 9 + +#define STATIC_STATE 0 +#define BLINKINGON_STATE 1 +#define BLINKINGOFF_STATE 2 +#define POWERON_STATE 3 +#define POWEROFF_STATE 4 + +#define PCISLOT_INTERLOCK_CLOSED 0x00000001 +#define PCISLOT_ADAPTER_PRESENT 0x00000002 +#define PCISLOT_POWERED 0x00000004 +#define PCISLOT_66_MHZ_OPERATION 0x00000008 +#define PCISLOT_64_BIT_OPERATION 0x00000010 +#define PCISLOT_REPLACE_SUPPORTED 0x00000020 +#define PCISLOT_ADD_SUPPORTED 0x00000040 +#define PCISLOT_INTERLOCK_SUPPORTED 0x00000080 +#define PCISLOT_66_MHZ_SUPPORTED 0x00000100 +#define PCISLOT_64_BIT_SUPPORTED 0x00000200 + + + +#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 + + +#define INTERLOCK_OPEN 0x00000002 +#define ADD_NOT_SUPPORTED 0x00000003 +#define CARD_FUNCTIONING 0x00000005 +#define ADAPTER_NOT_SAME 0x00000006 +#define NO_ADAPTER_PRESENT 0x00000009 +#define NOT_ENOUGH_RESOURCES 0x0000000B +#define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C +#define POWER_FAILURE 0x0000000E + +#define REMOVE_NOT_SUPPORTED 0x00000003 + + +/* + * error Messages + */ +#define msg_initialization_err "Initialization failure, error=%d\n" +#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" +#define msg_HPC_non_compaq_or_intel "The PCI hot plug controller is not supported by this driver.\n" +#define msg_HPC_not_supported "this system is not supported by this version of cpqphpd. Upgrade to a newer version of cpqphpd\n" +#define msg_unable_to_save "unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" +#define msg_button_on "PCI slot #%d - powering on due to button press.\n" +#define msg_button_off "PCI slot #%d - powering off due to button press.\n" +#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" +#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" + + +/* Proc functions for the hotplug controller info */ +#ifdef CONFIG_PROC_FS +extern int cpqhp_proc_init_ctrl (void); +extern int cpqhp_proc_destroy_ctrl (void); +extern int cpqhp_proc_create_ctrl (struct controller *ctrl); +extern int cpqhp_proc_remove_ctrl (struct controller *ctrl); +#else +static inline int cpqhp_proc_init_ctrl (void) +{ + return 0; +} +static inline int cpqhp_proc_destroy_ctrl (void) +{ + return 0; +} +static inline int cpqhp_proc_create_ctrl (struct controller *ctrl) +{ + return 0; +} +static inline int cpqhp_proc_remove_ctrl (struct controller *ctrl) +{ + return 0; +} +#endif + + +/* controller functions */ +extern void cpqhp_pushbutton_thread (unsigned long event_pointer); +extern void cpqhp_ctrl_intr (int IRQ, struct controller *ctrl_input, struct pt_regs *regs); +extern int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start); +extern int cpqhp_event_start_thread (void); +extern void cpqhp_event_stop_thread (void); +extern struct pci_func *cpqhp_slot_create (unsigned char busnumber); +extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index); +extern int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func); +extern int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func); +extern int cpqhp_hardware_test (struct controller *ctrl, int test_num); + +/* resource functions */ +extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); + +/* pci functions */ +extern int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); +extern int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot); +extern int cpqhp_save_config (struct controller *ctrl, int busnumber, int is_hot_plug); +extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); +extern int cpqhp_valid_replace (struct controller *ctrl, struct pci_func * func); +extern void cpqhp_destroy_board_resources (struct pci_func * func); +extern int cpqhp_return_board_resources (struct pci_func * func, struct resource_lists * resources); +extern void cpqhp_destroy_resource_list (struct resource_lists * resources); +extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func); +extern int cpqhp_unconfigure_device (struct pci_func* func); + + +/* Global variables */ +extern int cpqhp_debug; +extern struct controller *cpqhp_ctrl_list; +extern struct pci_func *cpqhp_slot_list[256]; + +/* these can be gotten rid of, but for debugging they are purty */ +extern u8 cpqhp_nic_irq; +extern u8 cpqhp_disk_irq; + + + +/* inline functions */ + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL\n", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check (slot, function)) + return NULL; + return slot; +} + +/* + * return_resource + * + * Puts node back in the resource list pointed to by head + * + */ +static inline void return_resource (struct pci_resource **head, struct pci_resource *node) +{ + if (!node || !head) + return; + node->next = *head; + *head = node; +} + +static inline void set_SOGO (struct controller *ctrl) +{ + u16 misc; + + misc = readw(ctrl->hpc_reg + MISC); + misc = (misc | 0x0001) & 0xFFFB; + writew(misc, ctrl->hpc_reg + MISC); +} + + +static inline void amber_LED_on (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control |= (0x01010000L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void amber_LED_off (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x01010000L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline int read_amber_LED (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= (0x01010000L << slot); + + return led_control ? 1 : 0; +} + + +static inline void green_LED_on (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control |= 0x0101L << slot; + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + +static inline void green_LED_off (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x0101L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void green_LED_blink (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control |= (0x0001L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void slot_disable (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable &= ~(0x01 << slot); + writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); +} + + +static inline void slot_enable (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable |= (0x01 << slot); + writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); +} + + +static inline u8 is_slot_enabled (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable &= (0x01 << slot); + return slot_enable ? 1 : 0; +} + + +static inline u8 read_slot_enable (struct controller *ctrl) +{ + return readb(ctrl->hpc_reg + SLOT_ENABLE); +} + + +static inline u8 get_controller_speed (struct controller *ctrl) +{ + u16 misc; + + misc = readw(ctrl->hpc_reg + MISC); + return (misc & 0x0800) ? 1 : 0; +} + + +static inline void enable_slot_power (struct controller *ctrl, u8 slot) +{ + u8 slot_power; + + slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + slot_power |= (0x01 << slot); + writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); +} + +static inline void disable_slot_power (struct controller *ctrl, u8 slot) +{ + u8 slot_power; + + slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + slot_power &= ~(0x01 << slot); + writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); +} + + +static inline int cpq_get_attention_status (struct controller *ctrl, struct slot *slot) +{ + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + + return read_amber_LED (ctrl, hp_slot); +} + + +static inline int get_slot_enabled (struct controller *ctrl, struct slot *slot) +{ + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + + return is_slot_enabled (ctrl, hp_slot); +} + + +static inline int cpq_get_latch_status (struct controller *ctrl, struct slot *slot) +{ + u32 status; + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + dbg(__FUNCTION__": slot->device = %d, ctrl->slot_device_offset = %d \n", slot->device, ctrl->slot_device_offset); + + status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)); + + return(status == 0) ? 1 : 0; +} + + +static inline int get_presence_status (struct controller *ctrl, struct slot *slot) +{ + int presence_save = 0; + u8 hp_slot; + u32 tempdword; + + if (slot == NULL) + return 0; + + hp_slot = slot->device - ctrl->slot_device_offset; + + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02; + + return presence_save; +} + +#define SLOT_NAME_SIZE 10 + +static inline void make_slot_name (char *buffer, int buffer_size, struct slot *slot) +{ + snprintf (buffer, buffer_size, "%d", slot->number); +} + + +static inline int wait_for_ctrl_irq (struct controller *ctrl) +{ + DECLARE_WAITQUEUE(wait, current); + int retval = 0; + + dbg(__FUNCTION__" - start\n"); + add_wait_queue(&ctrl->queue, &wait); + set_current_state(TASK_INTERRUPTIBLE); + /* Sleep for up to 1 second to wait for the LED to change. */ + schedule_timeout(1*HZ); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ctrl->queue, &wait); + if (signal_pending(current)) + retval = -EINTR; + + dbg(__FUNCTION__" - end\n"); + return retval; +} + +#endif + diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/cpqphp_core.c linux/drivers/hotplug/cpqphp_core.c --- v2.4.14/linux/drivers/hotplug/cpqphp_core.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/cpqphp_core.c Fri Nov 9 14:01:21 2001 @@ -0,0 +1,1439 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/miscdevice.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include "cpqphp.h" +#include "cpqphp_nvram.h" +#include "../../arch/i386/kernel/pci-i386.h" /* horrible hack showing how processor dependant we are... */ + + +/* Global variables */ +int cpqhp_debug; +struct controller *cpqhp_ctrl_list; /* = NULL */ +struct pci_func *cpqhp_slot_list[256]; + +/* local variables */ +static void *smbios_table; +static void *smbios_start; +static void *cpqhp_rom_start; +static u8 power_mode; +static int debug; + +#define DRIVER_VERSION "0.9.6" +#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>" +#define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_PARM(power_mode, "b"); +MODULE_PARM_DESC(power_mode, "Power mode enabled or not"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +#define CPQHPC_MODULE_MINOR 208 + +static int one_time_init (void); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int process_SI (struct hotplug_slot *slot); +static int process_SS (struct hotplug_slot *slot); +static int hardware_test (struct hotplug_slot *slot, u32 value); +static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); +static int get_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); + +static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { + owner: THIS_MODULE, + set_attention_status: set_attention_status, + enable_slot: process_SI, + disable_slot: process_SS, + hardware_test: hardware_test, + get_power_status: get_power_status, + get_attention_status: get_attention_status, + get_latch_status: get_latch_status, + get_adapter_status: get_adapter_status, +}; + + +static inline int is_slot64bit (struct slot *slot) +{ + if (!slot || !slot->p_sm_slot) + return 0; + + if (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) + return 1; + + return 0; +} + +static inline int is_slot66mhz (struct slot *slot) +{ + if (!slot || !slot->p_sm_slot) + return 0; + + if (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E) + return 1; + + return 0; +} + +/** + * detect_SMBIOS_pointer - find the system Management BIOS Table in the specified region of memory. + * + * @begin: begin pointer for region to be scanned. + * @end: end pointer for region to be scanned. + * + * Returns pointer to the head of the SMBIOS tables (or NULL) + * + */ +static void * detect_SMBIOS_pointer(void *begin, void *end) +{ + void *fp; + void *endp; + u8 temp1, temp2, temp3, temp4; + int status = 0; + + endp = (end - sizeof(u32) + 1); + + for (fp = begin; fp <= endp; fp += 16) { + temp1 = readb(fp); + temp2 = readb(fp+1); + temp3 = readb(fp+2); + temp4 = readb(fp+3); + if (temp1 == '_' && + temp2 == 'S' && + temp3 == 'M' && + temp4 == '_') { + status = 1; + break; + } + } + + if (!status) + fp = NULL; + + dbg("Discovered SMBIOS Entry point at %p\n", fp); + + return fp; +} + +/** + * init_SERR - Initializes the per slot SERR generation. + * + * For unexpected switch opens + * + */ +static int init_SERR(struct controller * ctrl) +{ + u32 tempdword; + u32 number_of_slots; + u8 physical_slot; + + if (!ctrl) + return 1; + + tempdword = ctrl->first_slot; + + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + // Loop through slots + while (number_of_slots) { + physical_slot = tempdword; + writeb(0, ctrl->hpc_reg + SLOT_SERR); + tempdword++; + number_of_slots--; + } + + return 0; +} + + +/* nice debugging output */ +static int pci_print_IRQ_route (void) +{ + struct irq_routing_table *routing_table; + int len; + int loop; + + u8 tbus, tdevice, tslot; + + routing_table = pcibios_get_irq_routing_table(); + if (routing_table == NULL) { + err("No BIOS Routing Table??? Not good\n"); + return -ENOMEM; + } + + len = (routing_table->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + kfree(routing_table); + return -1; + } + + dbg("bus dev func slot\n"); + + for (loop = 0; loop < len; ++loop) { + tbus = routing_table->slots[loop].bus; + tdevice = routing_table->slots[loop].devfn; + tslot = routing_table->slots[loop].slot; + dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); + + } + kfree(routing_table); + return 0; +} + + +/* + * get_subsequent_smbios_entry + * + * Gets the first entry if previous == NULL + * Otherwise, returns the next entry + * Uses global SMBIOS Table pointer + * + * @curr: %NULL or pointer to previously returned structure + * + * returns a pointer to an SMBIOS structure or NULL if none found + */ +static void * get_subsequent_smbios_entry(void *smbios_start, void *smbios_table, void *curr) +{ + u8 bail = 0; + u8 previous_byte = 1; + void *p_temp; + void *p_max; + + if (!smbios_table || !curr) + return(NULL); + + // set p_max to the end of the table + p_max = smbios_start + readw(smbios_table + ST_LENGTH); + + p_temp = curr; + p_temp += readb(curr + SMBIOS_GENERIC_LENGTH); + + while ((p_temp < p_max) && !bail) { + // Look for the double NULL terminator + // The first condition is the previous byte and the second is the curr + if (!previous_byte && !(readb(p_temp))) { + bail = 1; + } + + previous_byte = readb(p_temp); + p_temp++; + } + + if (p_temp < p_max) { + return p_temp; + } else { + return NULL; + } +} + + +/** + * get_SMBIOS_entry + * + * @type:SMBIOS structure type to be returned + * @previous: %NULL or pointer to previously returned structure + * + * Gets the first entry of the specified type if previous == NULL + * Otherwise, returns the next entry of the given type. + * Uses global SMBIOS Table pointer + * Uses get_subsequent_smbios_entry + * + * returns a pointer to an SMBIOS structure or %NULL if none found + */ +static void *get_SMBIOS_entry (void *smbios_start, void *smbios_table, u8 type, void * previous) +{ + if (!smbios_table) + return NULL; + + if (!previous) { + previous = smbios_start; + } else { + previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); + } + + while (previous) { + if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { + previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); + } else { + break; + } + } + + return previous; +} + + +static int ctrl_slot_setup (struct controller * ctrl, void *smbios_start, void *smbios_table) +{ + struct slot *new_slot; + u8 number_of_slots; + u8 slot_device; + u8 slot_number; + u8 ctrl_slot; + u32 tempdword; + void *slot_entry= NULL; + int result; + + dbg(__FUNCTION__"\n"); + + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + slot_number = ctrl->first_slot; + + while (number_of_slots) { + new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL); + if (!new_slot) + return -ENOMEM; + + memset(new_slot, 0, sizeof(struct slot)); + new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!new_slot->hotplug_slot) { + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); + + new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!new_slot->hotplug_slot->info) { + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); + new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); + if (!new_slot->hotplug_slot->name) { + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + + new_slot->magic = SLOT_MAGIC; + new_slot->ctrl = ctrl; + new_slot->bus = ctrl->bus; + new_slot->device = slot_device; + new_slot->number = slot_number; + dbg("slot->number = %d\n",new_slot->number); + + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); + + while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != new_slot->number)) { + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); + } + + new_slot->p_sm_slot = slot_entry; + + init_timer(&new_slot->task_event); + new_slot->task_event.expires = jiffies + 5 * HZ; + new_slot->task_event.function = cpqhp_pushbutton_thread; + + //FIXME: these capabilities aren't used but if they are + // they need to be correctly implemented + new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; + new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; + + if (is_slot64bit(new_slot)) + new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; + if (is_slot66mhz(new_slot)) + new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; + if (ctrl->speed == 1) + new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION; + + ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); + + // Check presence + new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; + // Check the switch state + new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; + // Check the slot enable + new_slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; + + /* register this slot with the hotplug pci core */ + new_slot->hotplug_slot->private = new_slot; + make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); + new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops; + + new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot); + new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot); + new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot); + new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot); + + dbg ("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n", + new_slot->bus, new_slot->device, new_slot->number, ctrl->slot_device_offset, slot_number); + result = pci_hp_register (new_slot->hotplug_slot); + if (result) { + err ("pci_hp_register failed with error %d\n", result); + return result; + } + + new_slot->next = ctrl->slot; + ctrl->slot = new_slot; + + number_of_slots--; + slot_device++; + slot_number++; + } + + return(0); +} + + +static int ctrl_slot_cleanup (struct controller * ctrl) +{ + struct slot *old_slot, *next_slot; + + old_slot = ctrl->slot; + ctrl->slot = NULL; + + while (old_slot) { + next_slot = old_slot->next; + pci_hp_deregister (old_slot->hotplug_slot); + kfree(old_slot->hotplug_slot); + kfree(old_slot); + old_slot = next_slot; + } + + //Free IRQ associated with hot plug device + free_irq(ctrl->interrupt, ctrl); + //Unmap the memory + iounmap(ctrl->hpc_reg); + //Finally reclaim PCI mem + release_mem_region(pci_resource_start(ctrl->pci_dev, 0), + pci_resource_len(ctrl->pci_dev, 0)); + + return(0); +} + + +//============================================================================ +// function: get_slot_mapping +// +// Description: Attempts to determine a logical slot mapping for a PCI +// device. Won't work for more than one PCI-PCI bridge +// in a slot. +// +// Input: u8 bus_num - bus number of PCI device +// u8 dev_num - device number of PCI device +// u8 *slot - Pointer to u8 where slot number will +// be returned +// +// Output: SUCCESS or FAILURE +//============================================================================= +static int get_slot_mapping (struct pci_ops *ops, u8 bus_num, u8 dev_num, u8 *slot) +{ + struct irq_routing_table *PCIIRQRoutingInfoLength; + u32 work; + long len; + long loop; + + u8 tbus, tdevice, tslot, bridgeSlot; + + dbg(__FUNCTION__" %p, %d, %d, %p\n", ops, bus_num, dev_num, slot); + + bridgeSlot = 0xFF; + + PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); + + len = (PCIIRQRoutingInfoLength->size - + sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + return -1; + } + + + for (loop = 0; loop < len; ++loop) { + tbus = PCIIRQRoutingInfoLength->slots[loop].bus; + tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3; + tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + + if ((tbus == bus_num) && (tdevice == dev_num)) { + *slot = tslot; + + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + return 0; + } else { + // Didn't get a match on the target PCI device. Check if the + // current IRQ table entry is a PCI-to-PCI bridge device. If so, + // and it's secondary bus matches the bus number for the target + // device, I need to save the bridge's slot number. If I can't + // find an entry for the target device, I will have to assume it's + // on the other side of the bridge, and assign it the bridge's slot. + pci_read_config_dword_nodev (ops, tbus, tdevice, 0, PCI_REVISION_ID, &work); + + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_read_config_dword_nodev (ops, tbus, tdevice, 0, PCI_PRIMARY_BUS, &work); + // See if bridge's secondary bus matches target bus. + if (((work >> 8) & 0x000000FF) == (long) bus_num) { + bridgeSlot = tslot; + } + } + } + + } + + + // If we got here, we didn't find an entry in the IRQ mapping table + // for the target PCI device. If we did determine that the target + // device is on the other side of a PCI-to-PCI bridge, return the + // slot number for the bridge. + if (bridgeSlot != 0xFF) { + *slot = bridgeSlot; + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + return 0; + } + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + // Couldn't find an entry in the routing table for this PCI device + return -1; +} + + +/** + * cpqhp_set_attention_status - Turns the Amber LED for a slot on or off + * + */ +static int cpqhp_set_attention_status (struct controller *ctrl, struct pci_func *func, u32 status) +{ + u8 hp_slot; + + hp_slot = func->device - ctrl->slot_device_offset; + + if (func == NULL) + return(1); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + if (status == 1) { + amber_LED_on (ctrl, hp_slot); + } else if (status == 0) { + amber_LED_off (ctrl, hp_slot); + } else { + // Done with exclusive hardware access + up(&ctrl->crit_sect); + return(1); + } + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(0); +} + + +/** + * set_attention_status - Turns the Amber LED for a slot on or off + * + */ +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + return cpqhp_set_attention_status(ctrl, slot_func, status); +} + + +static int process_SI (struct hotplug_slot *hotplug_slot) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + slot_func->bus = bus; + slot_func->device = device; + slot_func->function = function; + slot_func->configured = 0; + dbg("board_added(%p, %p)\n", slot_func, ctrl); + return cpqhp_process_SI(ctrl, slot_func); +} + + +static int process_SS (struct hotplug_slot *hotplug_slot) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + dbg("In power_down_board, slot_func = %p, ctrl = %p\n", slot_func, ctrl); + return cpqhp_process_SS(ctrl, slot_func); +} + + +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + dbg(__FUNCTION__"\n"); + + if (slot == NULL) + return -ENODEV; + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + return cpqhp_hardware_test (ctrl, value); +} + + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = get_slot_enabled(ctrl, slot); + return 0; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = cpq_get_attention_status(ctrl, slot); + return 0; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = cpq_get_latch_status (ctrl, slot); + + return 0; +} + +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = get_presence_status (ctrl, slot); + + return 0; +} + +static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + u8 num_of_slots = 0; + u8 hp_slot = 0; + u8 device; + u8 rev; + u16 temp_word; + u16 vendor_id; + u16 subsystem_vid; + u16 subsystem_deviceid; + u32 rc; + struct controller *ctrl; + struct pci_func *func; + + // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery + rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); + if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { + err(msg_HPC_non_compaq_or_intel); + return -ENODEV; + } + dbg("Vendor ID: %x\n", vendor_id); + + rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + dbg("revision: %d\n", rev); + if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) { + err(msg_HPC_rev_error); + return -ENODEV; + } + + /* Check for the proper subsytem ID's + * Intel uses a different SSID programming model than Compaq. + * For Intel, each SSID bit identifies a PHP capability. + * Also Intel HPC's may have RID=0. + */ + if ((rev > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) { + // TODO: This code can be made to support non-Compaq or Intel subsystem IDs + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); + if (rc) { + err(__FUNCTION__" : pci_read_config_word failed\n"); + return rc; + } + dbg("Subsystem Vendor ID: %x\n", subsystem_vid); + if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { + err(msg_HPC_non_compaq_or_intel); + return -ENODEV; + } + + ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); + if (!ctrl) { + err(__FUNCTION__" : out of memory\n"); + return -ENOMEM; + } + memset(ctrl, 0, sizeof(struct controller)); + + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); + if (rc) { + err(__FUNCTION__" : pci_read_config_word failed\n"); + goto err_free_ctrl; + } + + info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); + + /* Set Vendor ID, so it can be accessed later from other functions */ + ctrl->vendor_id = vendor_id; + + switch (subsystem_vid) { + case PCI_VENDOR_ID_COMPAQ: + switch (subsystem_deviceid) { + case PCI_SUB_HPC_ID: + /* Original 6500/7000 implementation */ + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = CTRL_SPEED_33MHz; + ctrl->push_button = 0; // No pushbutton + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID2: + /* First Pushbutton implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = CTRL_SPEED_33MHz; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID_INTC: + /* Third party (6500/7000) */ + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = CTRL_SPEED_33MHz; + ctrl->push_button = 0; // No pushbutton + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID3: + /* First 66 Mhz implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = CTRL_SPEED_66MHz; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + default: + // TODO: Add SSIDs for CPQ systems that support PCI-X + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + break; + + case PCI_VENDOR_ID_INTEL: + /* Check for speed capability (0=33, 1=66) */ + if (subsystem_deviceid & 0x0001) { + ctrl->speed_capability = CTRL_SPEED_66MHz; + } else { + ctrl->speed_capability = CTRL_SPEED_33MHz; + } + + /* Check for push button */ + if (subsystem_deviceid & 0x0002) { + /* no push button */ + ctrl->push_button = 0; + } else { + /* push button supported */ + ctrl->push_button = 1; + } + + /* Check for slot switch type (0=mechanical, 1=not mechanical) */ + if (subsystem_deviceid & 0x0004) { + /* no switch */ + ctrl->slot_switch_type = 0; + } else { + /* switch */ + ctrl->slot_switch_type = 1; + } + + /* PHP Status (0=De-feature PHP, 1=Normal operation) */ + if (subsystem_deviceid & 0x0008) { + ctrl->defeature_PHP = 1; // PHP supported + } else { + ctrl->defeature_PHP = 0; // PHP not supported + } + + /* Alternate Base Address Register Interface (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0010) { + ctrl->alternate_base_address = 1; // supported + } else { + ctrl->alternate_base_address = 0; // not supported + } + + /* PCI Config Space Index (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0020) { + ctrl->pci_config_space = 1; // supported + } else { + ctrl->pci_config_space = 0; // not supported + } + + /* PCI-X support */ + if (subsystem_deviceid & 0x0080) { + /* PCI-X capable */ + ctrl->pcix_support = 1; + /* Frequency of operation in PCI-X mode */ + if (subsystem_deviceid & 0x0040) { + /* 133MHz PCI-X if bit 7 is 1 */ + ctrl->pcix_speed_capability = 1; + } else { + /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ + /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ + ctrl->pcix_speed_capability = 0; + } + } else { + /* Conventional PCI */ + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + } + break; + + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + + } else { + err(msg_HPC_not_supported); + return -ENODEV; + } + + // Tell the user that we found one. + info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); + + dbg ("Hotplug controller capabilities:\n"); + dbg (" speed_capability %s\n", ctrl->speed_capability == CTRL_SPEED_33MHz ? "33MHz" : "66Mhz"); + dbg (" slot_switch_type %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present"); + dbg (" defeature_PHP %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported"); + dbg (" alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported"); + dbg (" pci_config_space %s\n", ctrl->pci_config_space == 0 ? "not supported" : "supported"); + dbg (" pcix_speed_capability %s\n", ctrl->pcix_speed_capability == 0 ? "not supported" : "supported"); + dbg (" pcix_support %s\n", ctrl->pcix_support == 0 ? "not supported" : "supported"); + + ctrl->pci_dev = pdev; + ctrl->pci_ops = pdev->bus->ops; + ctrl->bus = pdev->bus->number; + ctrl->device = PCI_SLOT(pdev->devfn); + ctrl->function = PCI_FUNC(pdev->devfn); + ctrl->rev = rev; + dbg("bus device function rev: %d %d %d %d\n", ctrl->bus, ctrl->device, ctrl->function, ctrl->rev); + + init_MUTEX(&ctrl->crit_sect); + init_waitqueue_head(&ctrl->queue); + + /* initialize our threads if they haven't already been started up */ + rc = one_time_init(); + if (rc) { + goto err_free_ctrl; + } + + dbg("pdev = %p\n", pdev); + dbg("pci resource start %lx\n", pci_resource_start(pdev, 0)); + dbg("pci resource len %lx\n", pci_resource_len(pdev, 0)); + + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), MY_NAME)) { + err("cannot reserve MMIO region\n"); + rc = -ENOMEM; + goto err_free_ctrl; + } + + ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!ctrl->hpc_reg) { + err("cannot remap MMIO region %lx @ %lx\n", pci_resource_len(pdev, 0), pci_resource_start(pdev, 0)); + rc = -ENODEV; + goto err_free_mem_region; + } + + // Check for 66Mhz operation + // TODO: Add PCI-X support + ctrl->speed = get_controller_speed(ctrl); + + + //************************************************** + // + // Save configuration headers for this and + // subordinate PCI buses + // + //************************************************** + + // find the physical slot number of the first hot plug slot + + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of a slot. + // CS: this is leveraging the PCIIRQ routing code from the kernel (pci-pc.c: get_irq_routing_table) + rc = get_slot_mapping(ctrl->pci_ops, pdev->bus->number, (readb(ctrl->hpc_reg + SLOT_MASK) >> 4), &(ctrl->first_slot)); + dbg("get_slot_mapping: first_slot = %d, returned = %d\n", ctrl->first_slot, rc); + if (rc) { + err(msg_initialization_err, rc); + goto err_iounmap; + } + + // Store PCI Config Space for all devices on this bus + rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK)); + if (rc) { + err(__FUNCTION__": unable to save PCI configuration data, error %d\n", rc); + goto err_iounmap; + } + + /* + * Get IO, memory, and IRQ resources for new devices + */ + rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start); + ctrl->add_support = !rc; + if (rc) { + dbg("cpqhp_find_available_resources = 0x%x\n", rc); + err("unable to locate PCI configuration resources for hot plug add.\n"); + goto err_iounmap; + } + + /* + * Finish setting up the hot plug ctrl device + */ + ctrl->slot_device_offset = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + dbg("NumSlots %d \n", ctrl->slot_device_offset); + + ctrl->next_event = 0; + + /* Setup the slot information structures */ + rc = ctrl_slot_setup(ctrl, smbios_start, smbios_table); + if (rc) { + err(msg_initialization_err, 6); + err(__FUNCTION__": unable to save PCI configuration data, error %d\n", rc); + goto err_iounmap; + } + + /* Mask all general input interrupts */ + writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK); + + /* set up the interrupt */ + ctrl->interrupt = pdev->irq; + dbg("HPC interrupt = %d \n", ctrl->interrupt); + if (request_irq(ctrl->interrupt, + (void (*)(int, void *, struct pt_regs *)) &cpqhp_ctrl_intr, + SA_SHIRQ, MY_NAME, ctrl)) { + err("Can't get irq %d for the hotplug pci controller\n", ctrl->interrupt); + rc = -ENODEV; + goto err_iounmap; + } + + /* Enable Shift Out interrupt and clear it, also enable SERR on power fault */ + temp_word = readw(ctrl->hpc_reg + MISC); + temp_word |= 0x4006; + writew(temp_word, ctrl->hpc_reg + MISC); + + // Changed 05/05/97 to clear all interrupts at start + writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_INPUT_CLEAR); + + ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + writel(0x0L, ctrl->hpc_reg + INT_MASK); + + if (!cpqhp_ctrl_list) { + cpqhp_ctrl_list = ctrl; + ctrl->next = NULL; + } else { + ctrl->next = cpqhp_ctrl_list; + cpqhp_ctrl_list = ctrl; + } + + // turn off empty slots here unless command line option "ON" set + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + + // find first device number for the ctrl + device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + + while (num_of_slots) { + dbg("num_of_slots: %d\n", num_of_slots); + func = cpqhp_slot_find(ctrl->bus, device, 0); + if (!func) + break; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg("hp_slot: %d\n", hp_slot); + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + + if (!power_mode) { + if (!func->is_a_board) { + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + } + } + + device++; + num_of_slots--; + } + + if (!power_mode) { + set_SOGO(ctrl); + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + + rc = init_SERR(ctrl); + if (rc) { + err("init_SERR failed\n"); + up(&ctrl->crit_sect); + goto err_free_irq; + } + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + rc = cpqhp_proc_create_ctrl (ctrl); + if (rc) { + err("cpqhp_proc_create_ctrl failed\n"); + goto err_free_irq; + } + + return 0; + +err_free_irq: + free_irq(ctrl->interrupt, ctrl); +err_iounmap: + iounmap(ctrl->hpc_reg); +err_free_mem_region: + release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); +err_free_ctrl: + kfree(ctrl); + return rc; +} + + +static int one_time_init(void) +{ + int loop; + int retval = 0; + static int initialized = 0; + + if (initialized) + return 0; + + power_mode = 0; + + retval = pci_print_IRQ_route(); + if (retval) + goto error; + + dbg("Initialize + Start the notification mechanism \n"); + + retval = cpqhp_event_start_thread(); + if (retval) + goto error; + + dbg("Initialize slot lists\n"); + for (loop = 0; loop < 256; loop++) { + cpqhp_slot_list[loop] = NULL; + } + + // FIXME: We also need to hook the NMI handler eventually. + // this also needs to be worked with Christoph + // register_NMI_handler(); + + // Map rom address + cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); + if (!cpqhp_rom_start) { + err ("Could not ioremap memory region for ROM\n"); + retval = -EIO;; + goto error; + } + + /* Now, map the int15 entry point if we are on compaq specific hardware */ + compaq_nvram_init(cpqhp_rom_start); + + /* Map smbios table entry point structure */ + smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, cpqhp_rom_start + ROM_PHY_LEN); + if (!smbios_table) { + err ("Could not find the SMBIOS pointer in memory\n"); + retval = -EIO;; + goto error; + } + + smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), readw(smbios_table + ST_LENGTH)); + if (!smbios_start) { + err ("Could not ioremap memory region taken from SMBIOS values\n"); + retval = -EIO;; + goto error; + } + + retval = cpqhp_proc_init_ctrl(); + if (retval) + goto error; + + initialized = 1; + + return retval; + +error: + if (cpqhp_rom_start) + iounmap(cpqhp_rom_start); + if (smbios_start) + iounmap(smbios_start); + + return retval; +} + + +static void unload_cpqphpd(void) +{ + struct pci_func *next; + struct pci_func *TempSlot; + int loop; + u32 rc; + struct controller *ctrl; + struct controller *tctrl; + struct pci_resource *res; + struct pci_resource *tres; + + rc = compaq_nvram_store(cpqhp_rom_start); + + ctrl = cpqhp_ctrl_list; + + while (ctrl) { + cpqhp_proc_remove_ctrl (ctrl); + + if (ctrl->hpc_reg) { + u16 misc; + rc = read_slot_enable (ctrl); + + writeb(0, ctrl->hpc_reg + SLOT_SERR); + writel(0xFFFFFFC0L | ~rc, ctrl->hpc_reg + INT_MASK); + + misc = readw(ctrl->hpc_reg + MISC); + misc &= 0xFFFD; + writew(misc, ctrl->hpc_reg + MISC); + } + + ctrl_slot_cleanup(ctrl); + + res = ctrl->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + tctrl = ctrl; + ctrl = ctrl->next; + kfree(tctrl); + } + + for (loop = 0; loop < 256; loop++) { + next = cpqhp_slot_list[loop]; + while (next != NULL) { + res = next->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + TempSlot = next; + next = next->next; + kfree(TempSlot); + } + } + + remove_proc_entry("hpc", 0); + + // Stop the notification mechanism + cpqhp_event_stop_thread(); + + //unmap the rom address + if (cpqhp_rom_start) + iounmap(cpqhp_rom_start); + if (smbios_start) + iounmap(smbios_start); +} + + + +static struct pci_device_id hpcd_pci_tbl[] __devinitdata = { + { + /* handle any PCI Hotplug controller */ + class: ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), + class_mask: ~0, + + /* no matter who makes it */ + vendor: PCI_ANY_ID, + device: PCI_ANY_ID, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + + }, { /* end: all zeroes */ } +}; + +MODULE_DEVICE_TABLE(pci, hpcd_pci_tbl); + + + +static struct pci_driver cpqhpc_driver = { + name: "pci_hotplug", + id_table: hpcd_pci_tbl, + probe: cpqhpc_probe, + /* remove: cpqhpc_remove_one, */ +}; + + + +static int __init cpqhpc_init(void) +{ + int result; + + cpqhp_debug = debug; + + result = pci_module_init(&cpqhpc_driver); + dbg("pci_module_init = %d\n", result); + if (result) + return result; + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + return 0; +} + + +static void __exit cpqhpc_cleanup(void) +{ + dbg("cleaning up proc entries\n"); + cpqhp_proc_destroy_ctrl(); + + dbg("unload_cpqphpd()\n"); + unload_cpqphpd(); + + dbg("pci_unregister_driver\n"); + pci_unregister_driver(&cpqhpc_driver); +} + + +module_init(cpqhpc_init); +module_exit(cpqhpc_cleanup); + + diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/cpqphp_ctrl.c linux/drivers/hotplug/cpqphp_ctrl.c --- v2.4.14/linux/drivers/hotplug/cpqphp_ctrl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/cpqphp_ctrl.c Fri Nov 9 14:01:22 2001 @@ -0,0 +1,3047 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/smp_lock.h> +#include <linux/pci.h> +#include "cpqphp.h" + +static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); +static int configure_new_function(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); +static void interrupt_event_handler(struct controller *ctrl); + +static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ +static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ +static int event_finished; +static unsigned long pushbutton_pending; /* = 0 */ + +/* things needed for the long_delay function */ +static struct semaphore delay_sem; +static wait_queue_head_t delay_wait; + +/* delay is in jiffies to wait for */ +static void long_delay (int delay) +{ + DECLARE_WAITQUEUE(wait, current); + + /* only allow 1 customer into the delay queue at once + * yes this makes some people wait even longer, but who really cares? + * this is for _huge_ delays to make the hardware happy as the + * signals bounce around + */ + down (&delay_sem); + + init_waitqueue_head (&delay_wait); + + add_wait_queue(&delay_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(delay); + remove_wait_queue(&delay_wait, &wait); + set_current_state(TASK_RUNNING); + + up (&delay_sem); +} + + +//FIXME: The following line needs to be somewhere else... +#define WRONG_BUS_FREQUENCY 0x07 +static u8 handle_switch_change(u8 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + u16 temp_word; + struct pci_func *func; + struct event_info *taskInfo; + + if (!change) + return 0; + + // Switch Change + dbg("cpqsbd: Switch interrupt received.\n"); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x1L << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + //this is the structure that tells the worker thread + //what to do + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + //********************************* + // Switch opened + //********************************* + + func->switch_save = 0; + + taskInfo->event_type = INT_SWITCH_OPEN; + } else { + //********************************* + // Switch closed + //********************************* + + func->switch_save = 0x10; + + taskInfo->event_type = INT_SWITCH_CLOSE; + } + } + } + + return rc; +} + + +/* + * find_slot + */ +static inline struct slot *find_slot (struct controller * ctrl, u8 device) +{ + struct slot *slot; + + if (!ctrl) + return NULL; + + slot = ctrl->slot; + + while (slot && (slot->device != device)) { + slot = slot->next; + } + + return slot; +} + + +static u8 handle_presence_change(u16 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + u8 temp_byte; + u16 temp_word; + struct pci_func *func; + struct event_info *taskInfo; + struct slot *p_slot; + + if (!change) + return 0; + + //********************************* + // Presence Change + //********************************* + dbg("cpqsbd: Presence/Notify input change.\n"); + dbg(" Changed bits are 0x%4.4x\n", change ); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x0101 << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + p_slot = find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4)); + + // If the switch closed, must be a button + // If not in button mode, nevermind + if (func->switch_save && (ctrl->push_button == 1)) { + temp_word = ctrl->ctrl_int_comp >> 16; + temp_byte = (temp_word >> hp_slot) & 0x01; + temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (temp_byte != func->presence_save) { + //********************************* + // button Pressed (doesn't do anything) + //********************************* + dbg("hp_slot %d button pressed\n", hp_slot); + taskInfo->event_type = INT_BUTTON_PRESS; + } else { + //********************************* + // button Released - TAKE ACTION!!!! + //********************************* + dbg("hp_slot %d button released\n", hp_slot); + taskInfo->event_type = INT_BUTTON_RELEASE; + + // Cancel if we are still blinking + if ((p_slot->state == BLINKINGON_STATE) + || (p_slot->state == BLINKINGOFF_STATE)) { + taskInfo->event_type = INT_BUTTON_CANCEL; + dbg("hp_slot %d button cancel\n", hp_slot); + } else if ((p_slot->state == POWERON_STATE) + || (p_slot->state == POWEROFF_STATE)) { + //info(msg_button_ignore, p_slot->number); + taskInfo->event_type = INT_BUTTON_IGNORE; + dbg("hp_slot %d button ignore\n", hp_slot); + } + } + } else { + // Switch is open, assume a presence change + // Save the presence state + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if ((!(ctrl->ctrl_int_comp & (0x010000 << hp_slot))) || + (!(ctrl->ctrl_int_comp & (0x01000000 << hp_slot)))) { + //********************************* + // Present + //********************************* + taskInfo->event_type = INT_PRESENCE_ON; + } else { + //********************************* + // Not Present + //********************************* + taskInfo->event_type = INT_PRESENCE_OFF; + } + } + } + } + + return rc; +} + + +static u8 handle_power_fault(u8 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + struct pci_func *func; + struct event_info *taskInfo; + + if (!change) + return 0; + + //********************************* + // power fault + //********************************* + + info("power fault interrupt\n"); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x01 << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) { + //********************************* + // power fault Cleared + //********************************* + func->status = 0x00; + + taskInfo->event_type = INT_POWER_FAULT_CLEAR; + } else { + //********************************* + // power fault + //********************************* + taskInfo->event_type = INT_POWER_FAULT; + + if (ctrl->rev < 4) { + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + set_SOGO (ctrl); + + // this is a fatal condition, we want to crash the + // machine to protect from data corruption + // simulated_NMI shouldn't ever return + //FIXME + //simulated_NMI(hp_slot, ctrl); + + //The following code causes a software crash just in + //case simulated_NMI did return + //FIXME + //panic(msg_power_fault); + } else { + // set power fault status for this board + func->status = 0xFF; + info("power fault bit %x set\n", hp_slot); + } + } + } + } + + return rc; +} + + +/* + * sort_by_size + * + * Sorts nodes on the list by their length. + * Smallest first. + * + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + + +/* + * sort_by_max_size + * + * Sorts nodes on the list by their length. + * Largest first. + * + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + + +/* + * do_pre_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + struct pci_resource *split_node; + u32 rc; + u32 temp_dword; + dbg("do_pre_bridge_resource_split\n"); + + if (!(*head) || !(*orig_head)) + return(NULL); + + rc = cpqhp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + if ((*head)->base != (*orig_head)->base) + return(NULL); + + if ((*head)->length == (*orig_head)->length) + return(NULL); + + + // If we got here, there the bridge requires some of the resource, but + // we may be able to split some off of the front + + node = *head; + + if (node->length & (alignment -1)) { + // this one isn't an aligned length, so we'll make a new entry + // and split it up. + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + temp_dword = (node->length | (alignment-1)) + 1 - alignment; + + split_node->base = node->base; + split_node->length = temp_dword; + + node->length -= temp_dword; + node->base += split_node->length; + + // Put it in the list + *head = split_node; + split_node->next = node; + } + + if (node->length < alignment) { + return(NULL); + } + + // Now unlink it + if (*head == node) { + *head = node->next; + node->next = NULL; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + node->next = NULL; + } + + return(node); +} + + +/* + * do_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + u32 rc; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + rc = cpqhp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + node = *head; + + while (node->next) { + prevnode = node; + node = node->next; + kfree(prevnode); + } + + if (node->length < alignment) { + kfree(node); + return(NULL); + } + + if (node->base & (alignment - 1)) { + // Short circuit if adjusted size is too small + temp_dword = (node->base | (alignment-1)) + 1; + if ((node->length - (temp_dword - node->base)) < alignment) { + kfree(node); + return(NULL); + } + + node->length -= (temp_dword - node->base); + node->base = temp_dword; + } + + if (node->length & (alignment - 1)) { + // There's stuff in use after this node + kfree(node); + return(NULL); + } + + return(node); +} + + +/* + * get_io_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( cpqhp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + // For IO make sure it's not in the ISA aliasing space + if (node->base & 0x300L) + continue; + + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + + return(node); +} + + +/* + * get_max_resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + */ +static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if (cpqhp_resource_sort_and_combine(head)) + return(NULL); + + if (sort_by_max_size(head)) + return(NULL); + + for (max = *head;max; max = max->next) { + + // If not big enough we could probably just bail, + // instead we'll continue to the next. + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (max->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((max->length - (temp_dword - max->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = max->base; + split_node->length = temp_dword - max->base; + max->base = temp_dword; + max->length -= split_node->length; + + // Put it next in the list + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + // this one isn't end aligned properly at the top + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + temp_dword = ((max->base + max->length) & ~(size - 1)); + split_node->base = temp_dword; + split_node->length = max->length + max->base + - split_node->base; + max->length -= split_node->length; + + // Put it in the list + split_node->next = max->next; + max->next = split_node; + } + + // Make sure it didn't shrink too much when we aligned it + if (max->length < size) + continue; + + // Now take it out of the list + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return(max); + } + + // If we get here, we couldn't find one + return(NULL); +} + + +/* + * get_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( cpqhp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + dbg(__FUNCTION__": req_size =%x node=%p, base=%x, length=%x\n", + size, node, node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg(__FUNCTION__": not aligned\n"); + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + dbg(__FUNCTION__": too big\n"); + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + dbg(__FUNCTION__": got one!!!\n"); + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + return(node); +} + + +/* + * cpqhp_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int cpqhp_resource_sort_and_combine(struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + dbg(__FUNCTION__": head = %p, *head = %p\n", head, *head); + + if (!(*head)) + return(1); + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return(0); /* only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(*head)->base); + dbg("*head->next->base = 0x%x\n",(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } // End of out_of_order loop + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + // Combine + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return(0); +} + + +void cpqhp_ctrl_intr(int IRQ, struct controller * ctrl, struct pt_regs *regs) +{ + u8 schedule_flag = 0; + u16 misc; + u32 Diff; + u32 temp_dword; + + + misc = readw(ctrl->hpc_reg + MISC); + //********************************* + // Check to see if it was our interrupt + //********************************* + if (!(misc & 0x000C)) { + return; + } + + if (misc & 0x0004) { + //********************************* + // Serial Output interrupt Pending + //********************************* + + // Clear the interrupt + misc |= 0x0004; + writew(misc, ctrl->hpc_reg + MISC); + + // Read to clear posted writes + misc = readw(ctrl->hpc_reg + MISC); + + dbg (__FUNCTION__" - waking up\n"); + wake_up_interruptible(&ctrl->queue); + } + + if (misc & 0x0008) { + // General-interrupt-input interrupt Pending + Diff = readl(ctrl->hpc_reg + INT_INPUT_CLEAR) ^ ctrl->ctrl_int_comp; + + ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + // Clear the interrupt + writel(Diff, ctrl->hpc_reg + INT_INPUT_CLEAR); + + // Read it back to clear any posted writes + temp_dword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + if (!Diff) { + // Clear all interrupts + writel(0xFFFFFFFF, ctrl->hpc_reg + INT_INPUT_CLEAR); + } + + schedule_flag += handle_switch_change((u8)(Diff & 0xFFL), ctrl); + schedule_flag += handle_presence_change((u16)((Diff & 0xFFFF0000L) >> 16), ctrl); + schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl); + } + + if (schedule_flag) { + up(&event_semaphore); + dbg("Signal event_semaphore\n"); + mark_bh(IMMEDIATE_BH); + } + +} + + +/** + * cpqhp_slot_create - Creates a node and adds it to the proper bus. + * @busnumber - bus where new node is to be located + * + * Returns pointer to the new node or NULL if unsuccessful + */ +struct pci_func *cpqhp_slot_create(u8 busnumber) +{ + struct pci_func *new_slot; + struct pci_func *next; + + new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL); + + if (new_slot == NULL) { + // I'm not dead yet! + // You will be. + return(new_slot); + } + + memset(new_slot, 0, sizeof(struct pci_func)); + + new_slot->next = NULL; + new_slot->configured = 1; + + if (cpqhp_slot_list[busnumber] == NULL) { + cpqhp_slot_list[busnumber] = new_slot; + } else { + next = cpqhp_slot_list[busnumber]; + while (next->next != NULL) + next = next->next; + next->next = new_slot; + } + return(new_slot); +} + + +/* + * slot_remove - Removes a node from the linked list of slots. + * @old_slot: slot to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int slot_remove(struct pci_func * old_slot) +{ + struct pci_func *next; + + if (old_slot == NULL) + return(1); + + next = cpqhp_slot_list[old_slot->bus]; + + if (next == NULL) { + return(1); + } + + if (next == old_slot) { + cpqhp_slot_list[old_slot->bus] = old_slot->next; + cpqhp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } + + while ((next->next != old_slot) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == old_slot) { + next->next = old_slot->next; + cpqhp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } else + return(2); +} + + +/** + * bridge_slot_remove - Removes a node from the linked list of slots. + * @bridge: bridge to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int bridge_slot_remove(struct pci_func *bridge) +{ + u8 subordinateBus, secondaryBus; + u8 tempBus; + struct pci_func *next; + + if (bridge == NULL) + return(1); + + secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; + subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; + + for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { + next = cpqhp_slot_list[tempBus]; + + while (!slot_remove(next)) { + next = cpqhp_slot_list[tempBus]; + } + } + + next = cpqhp_slot_list[bridge->bus]; + + if (next == NULL) { + return(1); + } + + if (next == bridge) { + cpqhp_slot_list[bridge->bus] = bridge->next; + kfree(bridge); + return(0); + } + + while ((next->next != bridge) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == bridge) { + next->next = bridge->next; + kfree(bridge); + return(0); + } else + return(2); +} + + +/** + * cpqhp_slot_find - Looks for a node by bus, and device, multiple functions accessed + * @bus: bus to find + * @device: device to find + * @index: is 0 for first function found, 1 for the second... + * + * Returns pointer to the node if successful, %NULL otherwise. + */ +struct pci_func *cpqhp_slot_find(u8 bus, u8 device, u8 index) +{ + int found = -1; + struct pci_func *func; + + func = cpqhp_slot_list[bus]; + + if ((func == NULL) || ((func->device == device) && (index == 0))) + return(func); + + if (func->device == device) + found++; + + while (func->next != NULL) { + func = func->next; + + if (func->device == device) + found++; + + if (found == index) + return(func); + } + + return(NULL); +} + + +// DJZ: I don't think is_bridge will work as is. +//FIXME +static int is_bridge(struct pci_func * func) +{ + // Check the header type + if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) + return 1; + else + return 0; +} + + +/* the following routines constitute the bulk of the + hotplug controller logic + */ + + +/** + * board_replaced - Called after a board has been replaced in the system. + * + * This is only used if we don't have resources for hot add + * Turns power on for the board + * Checks to see if board is the same + * If board is same, reconfigures it + * If board isn't same, turns it back off. + * + */ +static u32 board_replaced(struct pci_func * func, struct controller * ctrl) +{ + u8 hp_slot; + u8 temp_byte; + u32 index; + u32 rc = 0; + u32 src = 8; + + hp_slot = func->device - ctrl->slot_device_offset; + + if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) { + //********************************* + // The switch is open. + //********************************* + rc = INTERLOCK_OPEN; + } else if (is_slot_enabled (ctrl, hp_slot)) { + //********************************* + // The board is already on + //********************************* + rc = CARD_FUNCTIONING; + } else { + if (ctrl->speed == 1) { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + // turn on board without attaching to the bus + enable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Change bits in slot power register to force another shift out + // NOTE: this is to work around the timer bug + temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); + writeb(0x00, ctrl->hpc_reg + SLOT_POWER); + writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) { + rc = WRONG_BUS_FREQUENCY; + } + // turn off board without attaching to the bus + disable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + } + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + slot_enable (ctrl, hp_slot); + green_LED_blink (ctrl, hp_slot); + + amber_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + // Wait for ~1 second because of hot plug spec + long_delay(1*HZ); + + // Check for a power fault + if (func->status == 0xFF) { + // power fault occurred, but it was benign + rc = POWER_FAILURE; + func->status = 0; + } else + rc = cpqhp_valid_replace(ctrl, func); + + if (!rc) { + // It must be the same board + + rc = cpqhp_configure_board(ctrl, func); + + if (rc || src) { + // If configuration fails, turn it off + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + else + return(1); + } + + func->status = 0; + func->switch_save = 0x10; + + index = 1; + while (((func = cpqhp_slot_find(func->bus, func->device, index)) != NULL) && !rc) { + rc |= cpqhp_configure_board(ctrl, func); + index++; + } + + if (rc) { + // If configuration fails, turn it off + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(rc); + } + // Done configuring so turn LED on full time + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + rc = 0; + } else { + // Something is wrong + + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } + + } + return(rc); + +} + + +/** + * board_added - Called after a board has been added to the system. + * + * Turns power on for the board + * Configures board + * + */ +static u32 board_added(struct pci_func * func, struct controller * ctrl) +{ + u8 hp_slot; + u8 temp_byte; + int index; + u32 temp_register = 0xFFFFFFFF; + u32 rc = 0; + struct pci_func *new_slot = NULL; + struct slot *p_slot; + struct resource_lists res_lists; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg(__FUNCTION__": func->device, slot_offset, hp_slot = %d, %d ,%d\n", + func->device, ctrl->slot_device_offset, hp_slot); + + if (ctrl->speed == 1) { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + // turn on board without attaching to the bus + enable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Change bits in slot power register to force another shift out + // NOTE: this is to work around the timer bug + temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); + writeb(0x00, ctrl->hpc_reg + SLOT_POWER); + writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) { + rc = WRONG_BUS_FREQUENCY; + } + // turn off board without attaching to the bus + disable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + } + p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + // turn on board and blink green LED + + // Wait for exclusive access to hardware + dbg(__FUNCTION__": before down\n"); + down(&ctrl->crit_sect); + dbg(__FUNCTION__": after down\n"); + + dbg(__FUNCTION__": before slot_enable\n"); + slot_enable (ctrl, hp_slot); + + dbg(__FUNCTION__": before green_LED_blink\n"); + green_LED_blink (ctrl, hp_slot); + + dbg(__FUNCTION__": before amber_LED_blink\n"); + amber_LED_off (ctrl, hp_slot); + + dbg(__FUNCTION__": before set_SOGO\n"); + set_SOGO(ctrl); + + // Wait for SOBS to be unset + dbg(__FUNCTION__": before wait_for_ctrl_irq\n"); + wait_for_ctrl_irq (ctrl); + dbg(__FUNCTION__": after wait_for_ctrl_irq\n"); + + // Done with exclusive hardware access + dbg(__FUNCTION__": before up\n"); + up(&ctrl->crit_sect); + dbg(__FUNCTION__": after up\n"); + + // Wait for ~1 second because of hot plug spec + dbg(__FUNCTION__": before long_delay\n"); + long_delay(1*HZ); + dbg(__FUNCTION__": after long_delay\n"); + + dbg(__FUNCTION__": func status = %x\n", func->status); + // Check for a power fault + if (func->status == 0xFF) { + // power fault occurred, but it was benign + temp_register = 0xFFFFFFFF; + dbg(__FUNCTION__": temp register set to %x by power fault\n", temp_register); + rc = POWER_FAILURE; + func->status = 0; + } else { + // Get vendor/device ID u32 + rc = pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_VENDOR_ID, &temp_register); + dbg(__FUNCTION__": pci_read_config_dword returns %d\n", rc); + dbg(__FUNCTION__": temp_register is %x\n", temp_register); + + if (rc != 0) { + // Something's wrong here + temp_register = 0xFFFFFFFF; + dbg(__FUNCTION__": temp register set to %x by error\n", temp_register); + } + // Preset return code. It will be changed later if things go okay. + rc = NO_ADAPTER_PRESENT; + } + + // All F's is an empty slot or an invalid board + if (temp_register != 0xFFFFFFFF) { // Check for a board in the slot + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + res_lists.irqs = NULL; + + rc = configure_new_device(ctrl, func, 0, &res_lists); + + dbg(__FUNCTION__": back from configure_new_device\n"); + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (rc) { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + return(rc); + } else { + cpqhp_save_slot_config(ctrl, func); + } + + + func->status = 0; + func->switch_save = 0x10; + func->is_a_board = 0x01; + + //next, we will instantiate the linux pci_dev structures (with appropriate driver notification, if already present) + dbg(__FUNCTION__": configure linux pci_dev structure\n"); + index = 0; + do { + new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++); + if (new_slot && !new_slot->pci_dev) { + cpqhp_configure_device(ctrl, new_slot); + } + } while (new_slot); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } else { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(rc); + } + return 0; +} + + +/** + * remove_board - Turns off slot and LED's + * + */ +static u32 remove_board(struct pci_func * func, u32 replace_flag, struct controller * ctrl) +{ + int index; + u8 skip = 0; + u8 device; + u8 hp_slot; + u8 temp_byte; + u32 rc; + struct resource_lists res_lists; + struct pci_func *temp_func; + + if (func == NULL) + return(1); + + if (cpqhp_unconfigure_device(func)) + return(1); + + device = func->device; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg("In "__FUNCTION__", hp_slot = %d\n", hp_slot); + + // When we get here, it is safe to change base Address Registers. + // We will attempt to save the base Address Register Lengths + if (replace_flag || !ctrl->add_support) + rc = cpqhp_save_base_addr_length(ctrl, func); + else if (!func->bus_head && !func->mem_head && + !func->p_mem_head && !func->io_head) { + // Here we check to see if we've saved any of the board's + // resources already. If so, we'll skip the attempt to + // determine what's being used. + index = 0; + temp_func = cpqhp_slot_find(func->bus, func->device, index++); + while (temp_func) { + if (temp_func->bus_head || temp_func->mem_head + || temp_func->p_mem_head || temp_func->io_head) { + skip = 1; + break; + } + temp_func = cpqhp_slot_find(temp_func->bus, temp_func->device, index++); + } + + if (!skip) + rc = cpqhp_save_used_resources(ctrl, func); + } + // Change status to shutdown + if (func->is_a_board) + func->status = 0x01; + func->configured = 0; + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // turn off SERR for slot + temp_byte = readb(ctrl->hpc_reg + SLOT_SERR); + temp_byte &= ~(0x01 << hp_slot); + writeb(temp_byte, ctrl->hpc_reg + SLOT_SERR); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (!replace_flag && ctrl->add_support) { + while (func) { + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + + cpqhp_return_board_resources(func, &res_lists); + + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (is_bridge(func)) { + bridge_slot_remove(func); + } else + slot_remove(func); + + func = cpqhp_slot_find(ctrl->bus, device, 0); + } + + // Setup slot structure with entry for empty slot + func = cpqhp_slot_create(ctrl->bus); + + if (func == NULL) { + // Out of memory + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->switch_save = 0x10; + func->is_a_board = 0; + func->p_task_event = NULL; + } + + return 0; +} + + +static void pushbutton_helper_thread (unsigned long data) +{ + pushbutton_pending = data; + up(&event_semaphore); +} + + +// this is the main worker thread +static int event_thread(void* data) +{ + struct controller *ctrl; + lock_kernel(); + daemonize(); + + // New name + strcpy(current->comm, "phpd_event"); + + unlock_kernel(); + + while (1) { + dbg("!!!!event_thread sleeping\n"); + down_interruptible (&event_semaphore); + dbg("event_thread woken finished = %d\n", event_finished); + if (event_finished) break; + /* Do stuff here */ + if (pushbutton_pending) + cpqhp_pushbutton_thread(pushbutton_pending); + else + for (ctrl = cpqhp_ctrl_list; ctrl; ctrl=ctrl->next) + interrupt_event_handler(ctrl); + } + dbg("event_thread signals exit\n"); + up(&event_exit); + return 0; +} + + +int cpqhp_event_start_thread (void) +{ + int pid; + + /* initialize our semaphores */ + init_MUTEX(&delay_sem); + init_MUTEX_LOCKED(&event_semaphore); + init_MUTEX_LOCKED(&event_exit); + event_finished=0; + + pid = kernel_thread(event_thread, 0, 0); + if (pid < 0) { + err ("Can't start up our event thread\n"); + return -1; + } + dbg("Our event thread pid = %d\n", pid); + return 0; +} + + +void cpqhp_event_stop_thread (void) +{ + event_finished = 1; + dbg("event_thread finish command given\n"); + up(&event_semaphore); + dbg("wait for event_thread to exit\n"); + down(&event_exit); +} + + +static int update_slot_info (struct controller *ctrl, struct slot *slot) +{ + struct hotplug_slot_info *info; + char buffer[SLOT_NAME_SIZE]; + int result; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); + info->power_status = get_slot_enabled(ctrl, slot); + info->attention_status = cpq_get_attention_status(ctrl, slot); + info->latch_status = cpq_get_latch_status(ctrl, slot); + info->adapter_status = get_presence_status(ctrl, slot); + result = pci_hp_change_slot_info(buffer, info); + kfree (info); + return result; +} + +static void interrupt_event_handler(struct controller *ctrl) +{ + int loop = 0; + int change = 1; + struct pci_func *func; + u8 hp_slot; + struct slot *p_slot; + + while (change) { + change = 0; + + for (loop = 0; loop < 10; loop++) { + //dbg("loop %d\n", loop); + if (ctrl->event_queue[loop].event_type != 0) { + hp_slot = ctrl->event_queue[loop].hp_slot; + + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + dbg("hp_slot %d, func %p, p_slot %p\n", + hp_slot, func, p_slot); + + if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { + dbg("button pressed\n"); + } else if (ctrl->event_queue[loop].event_type == + INT_BUTTON_CANCEL) { + dbg("button cancel\n"); + del_timer(&p_slot->task_event); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + if (p_slot->state == BLINKINGOFF_STATE) { + // slot is on + // turn on green LED + dbg("turn on green LED\n"); + green_LED_on (ctrl, hp_slot); + } else if (p_slot->state == BLINKINGON_STATE) { + // slot is off + // turn off green LED + dbg("turn off green LED\n"); + green_LED_off (ctrl, hp_slot); + } + + info(msg_button_cancel, p_slot->number); + + p_slot->state = STATIC_STATE; + + amber_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } + // ***********button Released (No action on press...) + else if (ctrl->event_queue[loop].event_type == INT_BUTTON_RELEASE) { + dbg("button release\n"); + + if (is_slot_enabled (ctrl, hp_slot)) { + // slot is on + dbg("slot is on\n"); + p_slot->state = BLINKINGOFF_STATE; + info(msg_button_off, p_slot->number); + } else { + // slot is off + dbg("slot is off\n"); + p_slot->state = BLINKINGON_STATE; + info(msg_button_on, p_slot->number); + } + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + dbg("blink green LED and turn off amber\n"); + amber_LED_off (ctrl, hp_slot); + green_LED_blink (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + init_timer(&p_slot->task_event); + p_slot->hp_slot = hp_slot; + p_slot->ctrl = ctrl; +// p_slot->physical_slot = physical_slot; + p_slot->task_event.expires = jiffies + 5 * HZ; // 5 second delay + p_slot->task_event.function = pushbutton_helper_thread; + p_slot->task_event.data = (u32) p_slot; + + dbg("add_timer p_slot = %p\n", p_slot); + add_timer(&p_slot->task_event); + } + // ***********POWER FAULT + else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { + dbg("power fault\n"); + } else { + /* refresh notification */ + if (p_slot) + update_slot_info(ctrl, p_slot); + } + + ctrl->event_queue[loop].event_type = 0; + + change = 1; + } + } // End of FOR loop + } + + return; +} + + +/** + * cpqhp_pushbutton_thread + * + * Scheduled procedure to handle blocking stuff for the pushbuttons + * Handles all pending events and exits. + * + */ +void cpqhp_pushbutton_thread (unsigned long slot) +{ + u8 hp_slot; + u8 device; + struct pci_func *func; + struct slot *p_slot = (struct slot *) slot; + struct controller *ctrl = (struct controller *) p_slot->ctrl; + + pushbutton_pending = 0; + hp_slot = p_slot->hp_slot; + + device = p_slot->device; + + if (is_slot_enabled (ctrl, hp_slot)) { + p_slot->state = POWEROFF_STATE; + // power Down board + func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); + dbg("In power_down_board, func = %p, ctrl = %p\n", func, ctrl); + if (!func) { + dbg("Error! func NULL in "__FUNCTION__"\n"); + return ; + } + + if (func != NULL && ctrl != NULL) { + if (cpqhp_process_SS(ctrl, func) != 0) { + amber_LED_on (ctrl, hp_slot); + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + } + + p_slot->state = STATIC_STATE; + } else { + p_slot->state = POWERON_STATE; + // slot is off + + func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); + dbg("In add_board, func = %p, ctrl = %p\n", func, ctrl); + if (!func) { + dbg("Error! func NULL in "__FUNCTION__"\n"); + return ; + } + + if (func != NULL && ctrl != NULL) { + if (cpqhp_process_SI(ctrl, func) != 0) { + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + } + + p_slot->state = STATIC_STATE; + } + + return; +} + + +int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func) +{ + u8 device, hp_slot; + u16 temp_word; + u32 tempdword; + int rc; + struct slot* p_slot; + int physical_slot = 0; + + if (!ctrl) + return(1); + + tempdword = 0; + + device = func->device; + hp_slot = device - ctrl->slot_device_offset; + p_slot = find_slot(ctrl, device); + if (p_slot) { + physical_slot = p_slot->number; + } + + // Check to see if the interlock is closed + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + if (tempdword & (0x01 << hp_slot)) { + return(1); + } + + if (func->is_a_board) { + rc = board_replaced(func, ctrl); + } else { + // add board + slot_remove(func); + + func = cpqhp_slot_create(ctrl->bus); + if (func == NULL) { + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->is_a_board = 1; + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + + rc = board_added(func, ctrl); + if (rc) { + if (is_bridge(func)) { + bridge_slot_remove(func); + } else + slot_remove(func); + + // Setup slot structure with entry for empty slot + func = cpqhp_slot_create(ctrl->bus); + + if (func == NULL) { + // Out of memory + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->is_a_board = 0; + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= + (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + } + } + + if (rc) { + dbg(__FUNCTION__": rc = %d\n", rc); + } + + if (p_slot) + update_slot_info(ctrl, p_slot); + + return rc; +} + + +int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func) +{ + u8 device, class_code, header_type, BCR; + u8 index = 0; + u8 replace_flag; + u32 rc = 0; + struct slot* p_slot; + int physical_slot=0; + + device = func->device; + func = cpqhp_slot_find(ctrl->bus, device, index++); + p_slot = find_slot(ctrl, device); + if (p_slot) { + physical_slot = p_slot->number; + } + + // Make sure there are no video controllers here + while (func && !rc) { + // Check the Class Code + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0B, &class_code); + if (rc) + return rc; + + if (class_code == PCI_BASE_CLASS_DISPLAY) { + /* Display/Video adapter (not supported) */ + rc = REMOVE_NOT_SUPPORTED; + } else { + // See if it's a bridge + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + // If it's a bridge, check the VGA Enable bit + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_BRIDGE_CONTROL, &BCR); + if (rc) + return rc; + + // If the VGA Enable bit is set, remove isn't supported + if (BCR & PCI_BRIDGE_CTL_VGA) { + rc = REMOVE_NOT_SUPPORTED; + } + } + } + + func = cpqhp_slot_find(ctrl->bus, device, index++); + } + + func = cpqhp_slot_find(ctrl->bus, device, 0); + if ((func != NULL) && !rc) { + //FIXME: Replace flag should be passed into process_SS + replace_flag = !(ctrl->add_support); + rc = remove_board(func, replace_flag, ctrl); + } else if (!rc) { + rc = 1; + } + + if (p_slot) + update_slot_info(ctrl, p_slot); + + return(rc); +} + + + +/** + * hardware_test - runs hardware tests + * + * For hot plug ctrl folks to play with. + * test_num is the number entered in the GUI + * + */ +int cpqhp_hardware_test(struct controller *ctrl, int test_num) +{ + u32 save_LED; + u32 work_LED; + int loop; + int num_of_slots; + + num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f; + + switch (test_num) { + case 1: + // Do stuff here! + + // Do that funky LED thing + save_LED = readl(ctrl->hpc_reg + LED_CONTROL); // so we can restore them later + work_LED = 0x01010101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + work_LED = 0x00000101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((3*HZ)/10); + work_LED = work_LED >> 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((3*HZ)/10); + work_LED = work_LED << 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + } + + writel (save_LED, ctrl->hpc_reg + LED_CONTROL); // put it back the way it was + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + break; + case 2: + // Do other stuff here! + break; + case 3: + // and more... + break; + } + return 0; +} + + +/** + * configure_new_device - Configures the PCI header information of one board. + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Returns 0 if success + * + */ +static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists * resources) +{ + u8 temp_byte, function, max_functions, stop_it; + int rc; + u32 ID; + struct pci_func *new_slot; + int index; + + new_slot = func; + + dbg(__FUNCTION__"\n"); + // Check for Multi-function device + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0E, &temp_byte); + if (rc) { + dbg(__FUNCTION__": rc = %d\n", rc); + return rc; + } + + if (temp_byte & 0x80) // Multi-function device + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + rc = configure_new_function(ctrl, new_slot, behind_bridge, resources); + + if (rc) { + dbg("configure_new_function failed %d\n",rc); + index = 0; + + while (new_slot) { + new_slot = cpqhp_slot_find(new_slot->bus, new_slot->device, index++); + + if (new_slot) + cpqhp_return_board_resources(new_slot, resources); + } + + return(rc); + } + + function++; + + stop_it = 0; + + // The following loop skips to the next present function + // and creates a board structure + + while ((function < max_functions) && (!stop_it)) { + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, function, 0x00, &ID); + + if (ID == 0xFFFFFFFF) { // There's nothing there. + function++; + } else { // There's something there + // Setup slot structure. + new_slot = cpqhp_slot_create(func->bus); + + if (new_slot == NULL) { + // Out of memory + return(1); + } + + new_slot->bus = func->bus; + new_slot->device = func->device; + new_slot->function = function; + new_slot->is_a_board = 1; + new_slot->status = 0; + + stop_it++; + } + } + + } while (function < max_functions); + dbg("returning from configure_new_device\n"); + + return 0; +} + + +/* + Configuration logic that involves the hotplug data structures and + their bookkeeping + */ + + +/** + * configure_new_function - Configures the PCI header information of one device + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Calls itself recursively for bridged devices. + * Returns 0 if success + * + */ +static int configure_new_function (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists * resources) +{ + int cloop; + u8 IRQ; + u8 temp_byte; + u8 device; + u8 class_code; + u16 command; + u16 temp_word; + u32 temp_dword; + u32 rc; + u32 temp_register; + u32 base; + u32 ID; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct pci_resource *hold_mem_node; + struct pci_resource *hold_p_mem_node; + struct pci_resource *hold_IO_node; + struct pci_resource *hold_bus_node; + struct irq_mapping irqs; + struct pci_func *new_slot; + struct resource_lists temp_resources; + + // Check for Bridge + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &temp_byte); + if (rc) + return rc; + + if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // set Primary bus + dbg("set Primary bus = %d\n", func->bus); + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PRIMARY_BUS, func->bus); + if (rc) + return rc; + + // find range of busses to use + dbg("find ranges of buses to use\n"); + bus_node = get_max_resource(&resources->bus_head, 1); + + // If we don't have any busses to allocate, we can't continue + if (!bus_node) + return -ENOMEM; + + // set Secondary bus + temp_byte = bus_node->base; + dbg("set Secondary bus = %d\n", bus_node->base); + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, temp_byte); + if (rc) + return rc; + + // set subordinate bus + temp_byte = bus_node->base + bus_node->length - 1; + dbg("set subordinate bus = %d\n", bus_node->base + bus_node->length - 1); + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBORDINATE_BUS, temp_byte); + if (rc) + return rc; + + // set subordinate Latency Timer and base Latency Timer + temp_byte = 0x40; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SEC_LATENCY_TIMER, temp_byte); + if (rc) + return rc; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_LATENCY_TIMER, temp_byte); + if (rc) + return rc; + + // set Cache Line size + temp_byte = 0x08; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_CACHE_LINE_SIZE, temp_byte); + if (rc) + return rc; + + // Setup the IO, memory, and prefetchable windows + + io_node = get_max_resource(&(resources->io_head), 0x1000); + mem_node = get_max_resource(&(resources->mem_head), 0x100000); + p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000); + dbg("Setup the IO, memory, and prefetchable windows\n"); + dbg("io_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); + dbg("mem_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); + dbg("p_mem_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); + + // set up the IRQ info + if (!resources->irqs) { + irqs.barber_pole = 0; + irqs.interrupt[0] = 0; + irqs.interrupt[1] = 0; + irqs.interrupt[2] = 0; + irqs.interrupt[3] = 0; + irqs.valid_INT = 0; + } else { + irqs.barber_pole = resources->irqs->barber_pole; + irqs.interrupt[0] = resources->irqs->interrupt[0]; + irqs.interrupt[1] = resources->irqs->interrupt[1]; + irqs.interrupt[2] = resources->irqs->interrupt[2]; + irqs.interrupt[3] = resources->irqs->interrupt[3]; + irqs.valid_INT = resources->irqs->valid_INT; + } + + // set up resource lists that are now aligned on top and bottom + // for anything behind the bridge. + temp_resources.bus_head = bus_node; + temp_resources.io_head = io_node; + temp_resources.mem_head = mem_node; + temp_resources.p_mem_head = p_mem_node; + temp_resources.irqs = &irqs; + + // Make copies of the nodes we are going to pass down so that + // if there is a problem,we can just use these to free resources + hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { + if (hold_bus_node) + kfree(hold_bus_node); + if (hold_IO_node) + kfree(hold_IO_node); + if (hold_mem_node) + kfree(hold_mem_node); + if (hold_p_mem_node) + kfree(hold_p_mem_node); + + return(1); + } + + memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); + + bus_node->base += 1; + bus_node->length -= 1; + bus_node->next = NULL; + + // If we have IO resources copy them and fill in the bridge's + // IO range registers + if (io_node) { + memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); + io_node->next = NULL; + + // set IO base and Limit registers + temp_byte = io_node->base >> 8; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_BASE, temp_byte); + + temp_byte = (io_node->base + io_node->length - 1) >> 8; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, temp_byte); + } else { + kfree(hold_IO_node); + hold_IO_node = NULL; + } + + // If we have memory resources copy them and fill in the bridge's + // memory range registers. Otherwise, fill in the range + // registers with values that disable them. + if (mem_node) { + memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); + mem_node->next = NULL; + + // set Mem base and Limit registers + temp_word = mem_node->base >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, temp_word); + + temp_word = (mem_node->base + mem_node->length - 1) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word); + + kfree(hold_mem_node); + hold_mem_node = NULL; + } + + // If we have prefetchable memory resources copy them and + // fill in the bridge's memory range registers. Otherwise, + // fill in the range registers with values that disable them. + if (p_mem_node) { + memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); + p_mem_node->next = NULL; + + // set Pre Mem base and Limit registers + temp_word = p_mem_node->base >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, temp_word); + + temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word); + + kfree(hold_p_mem_node); + hold_p_mem_node = NULL; + } + + // Adjust this to compensate for extra adjustment in first loop + irqs.barber_pole--; + + rc = 0; + + // Here we actually find the devices and configure them + for (device = 0; (device <= 0x1F) && !rc; device++) { + irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; + + ID = 0xFFFFFFFF; + pci_read_config_dword_nodev (ctrl->pci_ops, hold_bus_node->base, device, 0, 0x00, &ID); + + if (ID != 0xFFFFFFFF) { // device Present + // Setup slot structure. + new_slot = cpqhp_slot_create(hold_bus_node->base); + + if (new_slot == NULL) { + // Out of memory + rc = -ENOMEM; + continue; + } + + new_slot->bus = hold_bus_node->base; + new_slot->device = device; + new_slot->function = 0; + new_slot->is_a_board = 1; + new_slot->status = 0; + + rc = configure_new_device(ctrl, new_slot, 1, &temp_resources); + dbg("configure_new_device rc=0x%x\n",rc); + } // End of IF (device in slot?) + } // End of FOR loop + + if (rc) { + cpqhp_destroy_resource_list(&temp_resources); + + return_resource(&(resources->bus_head), hold_bus_node); + return_resource(&(resources->io_head), hold_IO_node); + return_resource(&(resources->mem_head), hold_mem_node); + return_resource(&(resources->p_mem_head), hold_p_mem_node); + return(rc); + } + // save the interrupt routing information + if (resources->irqs) { + resources->irqs->interrupt[0] = irqs.interrupt[0]; + resources->irqs->interrupt[1] = irqs.interrupt[1]; + resources->irqs->interrupt[2] = irqs.interrupt[2]; + resources->irqs->interrupt[3] = irqs.interrupt[3]; + resources->irqs->valid_INT = irqs.valid_INT; + } else if (!behind_bridge) { + // We need to hook up the interrupts here + for (cloop = 0; cloop < 4; cloop++) { + if (irqs.valid_INT & (0x01 << cloop)) { + rc = cpqhp_set_irq(func->bus, func->device, + 0x0A + cloop, irqs.interrupt[cloop]); + if (rc) { + cpqhp_destroy_resource_list (&temp_resources); + + return_resource(&(resources-> bus_head), hold_bus_node); + return_resource(&(resources-> io_head), hold_IO_node); + return_resource(&(resources-> mem_head), hold_mem_node); + return_resource(&(resources-> p_mem_head), hold_p_mem_node); + return rc; + } + } + } // end of for loop + } + // Return unused bus resources + // First use the temporary node to store information for the board + if (hold_bus_node && bus_node && temp_resources.bus_head) { + hold_bus_node->length = bus_node->base - hold_bus_node->base; + + hold_bus_node->next = func->bus_head; + func->bus_head = hold_bus_node; + + temp_byte = temp_resources.bus_head->base - 1; + + // set subordinate bus + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBORDINATE_BUS, temp_byte); + + if (temp_resources.bus_head->length == 0) { + kfree(temp_resources.bus_head); + temp_resources.bus_head = NULL; + } else { + return_resource(&(resources->bus_head), temp_resources.bus_head); + } + } + + // If we have IO space available and there is some left, + // return the unused portion + if (hold_IO_node && temp_resources.io_head) { + io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), + &hold_IO_node, 0x1000); + + // Check if we were able to split something off + if (io_node) { + hold_IO_node->base = io_node->base + io_node->length; + + temp_byte = (hold_IO_node->base) >> 8; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_BASE, temp_byte); + + return_resource(&(resources->io_head), io_node); + } + + io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); + + // Check if we were able to split something off + if (io_node) { + // First use the temporary node to store information for the board + hold_IO_node->length = io_node->base - hold_IO_node->base; + + // If we used any, add it to the board's list + if (hold_IO_node->length) { + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + + temp_byte = (io_node->base - 1) >> 8; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, temp_byte); + + return_resource(&(resources->io_head), io_node); + } else { + // it doesn't need any IO + temp_word = 0x0000; + pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, temp_word); + + return_resource(&(resources->io_head), io_node); + kfree(hold_IO_node); + } + } else { + // it used most of the range + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + } else if (hold_IO_node) { + // it used the whole range + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + // If we have memory space available and there is some left, + // return the unused portion + if (hold_mem_node && temp_resources.mem_head) { + mem_node = do_pre_bridge_resource_split(&(temp_resources. mem_head), + &hold_mem_node, 0x100000); + + // Check if we were able to split something off + if (mem_node) { + hold_mem_node->base = mem_node->base + mem_node->length; + + temp_word = (hold_mem_node->base) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, temp_word); + + return_resource(&(resources->mem_head), mem_node); + } + + mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000); + + // Check if we were able to split something off + if (mem_node) { + // First use the temporary node to store information for the board + hold_mem_node->length = mem_node->base - hold_mem_node->base; + + if (hold_mem_node->length) { + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + + // configure end address + temp_word = (mem_node->base - 1) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word); + + // Return unused resources to the pool + return_resource(&(resources->mem_head), mem_node); + } else { + // it doesn't need any Mem + temp_word = 0x0000; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->mem_head), mem_node); + kfree(hold_mem_node); + } + } else { + // it used most of the range + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + } else if (hold_mem_node) { + // it used the whole range + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + // If we have prefetchable memory space available and there is some + // left at the end, return the unused portion + if (hold_p_mem_node && temp_resources.p_mem_head) { + p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), + &hold_p_mem_node, 0x100000); + + // Check if we were able to split something off + if (p_mem_node) { + hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; + + temp_word = (hold_p_mem_node->base) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } + + p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000); + + // Check if we were able to split something off + if (p_mem_node) { + // First use the temporary node to store information for the board + hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; + + // If we used any, add it to the board's list + if (hold_p_mem_node->length) { + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + + temp_word = (p_mem_node->base - 1) >> 16; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } else { + // it doesn't need any PMem + temp_word = 0x0000; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + kfree(hold_p_mem_node); + } + } else { + // it used the most of the range + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + } else if (hold_p_mem_node) { + // it used the whole range + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + // We should be configuring an IRQ and the bridge's base address + // registers if it needs them. Although we have never seen such + // a device + + // enable card + command = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, command); + + // set Bridge Control Register + command = 0x07; // = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_BRIDGE_CONTROL, command); + } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + // Standard device + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_DISPLAY) { + // Display (video) adapter (not supported) + return(DEVICE_TYPE_NOT_SUPPORTED); + } + // Figure out IO and memory needs + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + + dbg("CND: bus=%d, device=%d, func=%d, offset=%d\n", func->bus, func->device, func->function, cloop); + rc = pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + + rc = pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &temp_register); + dbg("CND: base = 0x%x\n", temp_register); + + if (temp_register) { // If this register is implemented + if ((temp_register & 0x03L) == 0x01) { + // Map IO + + // set base = amount of IO space + base = temp_register & 0xFFFFFFFC; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + io_node = get_io_resource(&(resources->io_head), base); + dbg("Got io_node start = %8.8x, length = %8.8x next (%p)\n", + io_node->base, io_node->length, io_node->next); + dbg("func (%p) io_head (%p)\n", func, func->io_head); + + // allocate the resource to the board + if (io_node) { + base = io_node->base; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x08) { + // Map prefetchable memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + p_mem_node = get_resource(&(resources->p_mem_head), base); + + // allocate the resource to the board + if (p_mem_node) { + base = p_mem_node->base; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x00) { + // Map memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + mem_node = get_resource(&(resources->mem_head), base); + + // allocate the resource to the board + if (mem_node) { + base = mem_node->base; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x04) { + // Map memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + mem_node = get_resource(&(resources->mem_head), base); + + // allocate the resource to the board + if (mem_node) { + base = mem_node->base; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x06) { + // Those bits are reserved, we can't handle this + return(1); + } else { + // Requesting space below 1M + return(NOT_ENOUGH_RESOURCES); + } + + rc = pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, base); + + // Check for 64-bit base + if ((temp_register & 0x07L) == 0x04) { + cloop += 4; + + // Upper 32 bits of address always zero on today's systems + // FIXME this is probably not true on Alpha and ia64??? + base = 0; + rc = pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, base); + } + } + } // End of base register loop + + // Figure out which interrupt pin this function uses + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_INTERRUPT_PIN, &temp_byte); + + // If this function needs an interrupt and we are behind a bridge + // and the pin is tied to something that's alread mapped, + // set this one the same + if (temp_byte && resources->irqs && + (resources->irqs->valid_INT & + (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { + // We have to share with something already set up + IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; + } else { + // Program IRQ based on card type + rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_STORAGE) { + IRQ = cpqhp_disk_irq; + } else { + IRQ = cpqhp_nic_irq; + } + } + + // IRQ Line + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_INTERRUPT_LINE, IRQ); + + if (!behind_bridge) { + rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); + if (rc) + return(1); + } else { + //TBD - this code may also belong in the other clause of this If statement + resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ; + resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03; + } + + // Latency Timer + temp_byte = 0x40; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_LATENCY_TIMER, temp_byte); + + // Cache Line size + temp_byte = 0x08; + rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_CACHE_LINE_SIZE, temp_byte); + + // disable ROM base Address + temp_dword = 0x00L; + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_ROM_ADDRESS, temp_dword); + + // enable card + temp_word = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR + rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, temp_word); + } // End of Not-A-Bridge else + else { + // It's some strange type of PCI adapter (Cardbus?) + return(DEVICE_TYPE_NOT_SUPPORTED); + } + + func->configured = 1; + + return 0; +} + diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/cpqphp_nvram.c linux/drivers/hotplug/cpqphp_nvram.c --- v2.4.14/linux/drivers/hotplug/cpqphp_nvram.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/cpqphp_nvram.c Fri Nov 9 14:01:22 2001 @@ -0,0 +1,652 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/miscdevice.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include "cpqphp.h" +#include "cpqphp_nvram.h" + + +#define ROM_INT15_PHY_ADDR 0x0FF859 +#define READ_EV 0xD8A4 +#define WRITE_EV 0xD8A5 + +struct register_foo { + union { + unsigned long lword; /* eax */ + unsigned short word; /* ax */ + + struct { + unsigned char low; /* al */ + unsigned char high; /* ah */ + } byte; + } data; + + unsigned char opcode; /* see below */ + unsigned long length; /* if the reg. is a pointer, how much data */ +} __attribute__ ((packed)); + +struct all_reg { + struct register_foo eax_reg; + struct register_foo ebx_reg; + struct register_foo ecx_reg; + struct register_foo edx_reg; + struct register_foo edi_reg; + struct register_foo esi_reg; + struct register_foo eflags_reg; +} __attribute__ ((packed)); + + +struct ev_hrt_header { + u8 Version; + u8 num_of_ctrl; + u8 next; +}; + +struct ev_hrt_ctrl { + u8 bus; + u8 device; + u8 function; + u8 mem_avail; + u8 p_mem_avail; + u8 io_avail; + u8 bus_avail; + u8 next; +}; + + +static u8 evbuffer_init; +static u8 evbuffer_length; +static u8 evbuffer[1024]; + +static void *compaq_int15_entry_point; + +static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */ + + +/* This is a series of function that deals with + setting & getting the hotplug resource table in some environment variable. +*/ + +/* + * We really shouldn't be doing this unless there is a _very_ good reason to!!! + * greg k-h + */ + + +static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) +{ + u8 **tByte; + + if ((*used + 1) > *avail) + return(1); + + *((u8*)*p_buffer) = value; + tByte = (u8**)p_buffer; + (*tByte)++; + *used+=1; + return(0); +} + + +static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail) +{ + if ((*used + 4) > *avail) + return(1); + + **p_buffer = value; + (*p_buffer)++; + *used+=4; + return(0); +} + + +/* + * check_for_compaq_ROM + * + * this routine verifies that the ROM OEM string is 'COMPAQ' + * + * returns 0 for non-Compaq ROM, 1 for Compaq ROM + */ +static int check_for_compaq_ROM (void *rom_start) +{ + u8 temp1, temp2, temp3, temp4, temp5, temp6; + int result = 0; + + temp1 = readb(rom_start + 0xffea + 0); + temp2 = readb(rom_start + 0xffea + 1); + temp3 = readb(rom_start + 0xffea + 2); + temp4 = readb(rom_start + 0xffea + 3); + temp5 = readb(rom_start + 0xffea + 4); + temp6 = readb(rom_start + 0xffea + 5); + if ((temp1 == 'C') && + (temp2 == 'O') && + (temp3 == 'M') && + (temp4 == 'P') && + (temp5 == 'A') && + (temp6 == 'Q')) { + result = 1; + } + dbg (__FUNCTION__" - returned %d\n", result); + return result; +} + + +static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) +{ + unsigned long flags; + int op = operation; + int ret_val; + + if (!compaq_int15_entry_point) + return -ENODEV; + + spin_lock_irqsave(&int15_lock, flags); + __asm__ ( + "xorl %%ebx,%%ebx + xorl %%edx,%%edx + pushf + push %%cs + cli + call *%6" + : "=c" (*buf_size), "=a" (ret_val) + : "a" (op), "c" (*buf_size), "S" (ev_name), + "D" (buffer), "m" (compaq_int15_entry_point) + : "%ebx", "%edx"); + spin_unlock_irqrestore(&int15_lock, flags); + + return((ret_val & 0xFF00) >> 8); +} + + +/* + * load_HRT + * + * Read the hot plug Resource Table from NVRAM + */ +static int load_HRT (void *rom_start) +{ + u32 available; + u32 temp_dword; + u8 temp_byte = 0xFF; + u32 rc; + + if (!check_for_compaq_ROM(rom_start)) { + return -ENODEV; + } + + available = 1024; + + // Now load the EV + temp_dword = available; + + rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword); + + evbuffer_length = temp_dword; + + // We're maintaining the resource lists so write FF to invalidate old info + temp_dword = 1; + + rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword); + + return rc; +} + + +/* + * store_HRT + * + * Save the hot plug Resource Table in NVRAM + */ +static u32 store_HRT (void *rom_start) +{ + u32 *buffer; + u32 *pFill; + u32 usedbytes; + u32 available; + u32 temp_dword; + u32 rc; + u8 loop; + u8 numCtrl = 0; + struct controller *ctrl; + struct pci_resource *resNode; + struct ev_hrt_header *p_EV_header; + struct ev_hrt_ctrl *p_ev_ctrl; + + available = 1024; + + if (!check_for_compaq_ROM(rom_start)) { + return(1); + } + + buffer = (u32*) evbuffer; + + if (!buffer) + return(1); + + pFill = buffer; + usedbytes = 0; + + p_EV_header = (struct ev_hrt_header *) pFill; + + ctrl = cpqhp_ctrl_list; + + // The revision of this structure + rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); + if (rc) + return(rc); + + // The number of controllers + rc = add_byte( &pFill, 1, &usedbytes, &available); + if (rc) + return(rc); + + while (ctrl) { + p_ev_ctrl = (struct ev_hrt_ctrl *) pFill; + + numCtrl++; + + // The bus number + rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available); + if (rc) + return(rc); + + // The device Number + rc = add_byte( &pFill, ctrl->device, &usedbytes, &available); + if (rc) + return(rc); + + // The function Number + rc = add_byte( &pFill, ctrl->function, &usedbytes, &available); + if (rc) + return(rc); + + // Skip the number of available entries + rc = add_dword( &pFill, 0, &usedbytes, &available); + if (rc) + return(rc); + + // Figure out memory Available + + resNode = ctrl->mem_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->mem_avail = loop; + + // Figure out prefetchable memory Available + + resNode = ctrl->p_mem_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->p_mem_avail = loop; + + // Figure out IO Available + + resNode = ctrl->io_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->io_avail = loop; + + // Figure out bus Available + + resNode = ctrl->bus_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->bus_avail = loop; + + ctrl = ctrl->next; + } + + p_EV_header->num_of_ctrl = numCtrl; + + // Now store the EV + + temp_dword = usedbytes; + + rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword); + + dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword); + + evbuffer_length = temp_dword; + + if (rc) { + err(msg_unable_to_save); + return(1); + } + + return(0); +} + + +void compaq_nvram_init (void *rom_start) +{ + if (rom_start) { + compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR); + } + dbg("int15 entry = %p\n", compaq_int15_entry_point); + + /* initialize our int15 lock */ + spin_lock_init(&int15_lock); +} + + +int compaq_nvram_load (void *rom_start, struct controller *ctrl) +{ + u8 bus, device, function; + u8 nummem, numpmem, numio, numbus; + u32 rc; + u8 *p_byte; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct ev_hrt_ctrl *p_ev_ctrl; + struct ev_hrt_header *p_EV_header; + + if (!evbuffer_init) { + // Read the resource list information in from NVRAM + if (load_HRT(rom_start)) + memset (evbuffer, 0, 1024); + + evbuffer_init = 1; + } + + // If we saved information in NVRAM, use it now + p_EV_header = (struct ev_hrt_header *) evbuffer; + + // The following code is for systems where version 1.0 of this + // driver has been loaded, but doesn't support the hardware. + // In that case, the driver would incorrectly store something + // in NVRAM. + if ((p_EV_header->Version == 2) || + ((p_EV_header->Version == 1) && !ctrl->push_flag)) { + p_byte = &(p_EV_header->next); + + p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next); + + p_byte += 3; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + bus = p_ev_ctrl->bus; + device = p_ev_ctrl->device; + function = p_ev_ctrl->function; + + while ((bus != ctrl->bus) || (device != ctrl->device) + || (function != ctrl->function)) { + nummem = p_ev_ctrl->mem_avail; + numpmem = p_ev_ctrl->p_mem_avail; + numio = p_ev_ctrl->io_avail; + numbus = p_ev_ctrl->bus_avail; + + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + // Skip forward to the next entry + p_byte += (nummem + numpmem + numio + numbus) * 8; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte; + + p_byte += 3; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + bus = p_ev_ctrl->bus; + device = p_ev_ctrl->device; + function = p_ev_ctrl->function; + } + + nummem = p_ev_ctrl->mem_avail; + numpmem = p_ev_ctrl->p_mem_avail; + numio = p_ev_ctrl->io_avail; + numbus = p_ev_ctrl->bus_avail; + + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + while (nummem--) { + mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!mem_node) + break; + + mem_node->base = *(u32*)p_byte; + dbg("mem base = %8.8x\n",mem_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + mem_node->length = *(u32*)p_byte; + dbg("mem length = %8.8x\n",mem_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + mem_node->next = ctrl->mem_head; + ctrl->mem_head = mem_node; + } + + while (numpmem--) { + p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!p_mem_node) + break; + + p_mem_node->base = *(u32*)p_byte; + dbg("pre-mem base = %8.8x\n",p_mem_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + p_mem_node->length = *(u32*)p_byte; + dbg("pre-mem length = %8.8x\n",p_mem_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + p_mem_node->next = ctrl->p_mem_head; + ctrl->p_mem_head = p_mem_node; + } + + while (numio--) { + io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!io_node) + break; + + io_node->base = *(u32*)p_byte; + dbg("io base = %8.8x\n",io_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + io_node->length = *(u32*)p_byte; + dbg("io length = %8.8x\n",io_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + io_node->next = ctrl->io_head; + ctrl->io_head = io_node; + } + + while (numbus--) { + bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!bus_node) + break; + + bus_node->base = *(u32*)p_byte; + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + bus_node->length = *(u32*)p_byte; + p_byte += 4; + + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return(2); + + bus_node->next = ctrl->bus_head; + ctrl->bus_head = bus_node; + } + + // If all of the following fail, we don't have any resources for + // hot plug add + rc = 1; + rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (rc) { + return(rc); + } + } else { + if ((evbuffer[0] != 0) && (!ctrl->push_flag)) { + return(1); + } + } + + return 0; +} + + +int compaq_nvram_store (void *rom_start) +{ + int rc = 1; + + if (rom_start == NULL) + return -ENODEV; + + if (evbuffer_init) { + rc = store_HRT(rom_start); + if (rc) { + err(msg_unable_to_save); + } + } + return rc; +} + diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/cpqphp_nvram.h linux/drivers/hotplug/cpqphp_nvram.h --- v2.4.14/linux/drivers/hotplug/cpqphp_nvram.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/cpqphp_nvram.h Fri Nov 9 14:01:22 2001 @@ -0,0 +1,57 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <greg@kroah.com> + * + */ + +#ifndef _CPQPHP_NVRAM_H +#define _CPQPHP_NVRAM_H + +#ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM + +static inline void compaq_nvram_init (void *rom_start) +{ + return; +} + +static inline int compaq_nvram_load (void *rom_start, struct controller *ctrl) +{ + return 0; +} + +static inline int compaq_nvram_store (void *rom_start) +{ + return 0; +} + +#else + +extern void compaq_nvram_init (void *rom_start); +extern int compaq_nvram_load (void *rom_start, struct controller *ctrl); +extern int compaq_nvram_store (void *rom_start); + +#endif + +#endif + diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/cpqphp_pci.c linux/drivers/hotplug/cpqphp_pci.c --- v2.4.14/linux/drivers/hotplug/cpqphp_pci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/cpqphp_pci.c Fri Nov 9 14:01:22 2001 @@ -0,0 +1,1726 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include <linux/pci.h> +#include "cpqphp.h" +#include "cpqphp_nvram.h" +#include "../../arch/i386/kernel/pci-i386.h" /* horrible hack showing how processor dependant we are... */ + + +u8 cpqhp_nic_irq; +u8 cpqhp_disk_irq; + +static u16 unused_IRQ; + + +static int is_pci_dev_in_use(struct pci_dev* dev) +{ + /* + * dev->driver will be set if the device is in use by a new-style + * driver -- otherwise, check the device's regions to see if any + * driver has claimed them + */ + + int i, inuse=0; + + if (dev->driver) return 1; //assume driver feels responsible + + for (i = 0; !dev->driver && !inuse && (i < 6); i++) { + if (!pci_resource_start(dev, i)) + continue; + + if (pci_resource_flags(dev, i) & IORESOURCE_IO) + inuse = check_region(pci_resource_start(dev, i), + pci_resource_len(dev, i)); + else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) + inuse = check_mem_region(pci_resource_start(dev, i), + pci_resource_len(dev, i)); + } + + return inuse; + +} + + +static int pci_hp_remove_device(struct pci_dev *dev) +{ + if (is_pci_dev_in_use(dev)) { + err("***Cannot safely power down device -- " + "it appears to be in use***\n"); + return -EBUSY; + } + pci_remove_device(dev); + return 0; +} + + +/* + * detect_HRT_floating_pointer + * + * find the Hot Plug Resource Table in the specified region of memory. + * + */ +static void *detect_HRT_floating_pointer(void *begin, void *end) +{ + void *fp; + void *endp; + u8 temp1, temp2, temp3, temp4; + int status = 0; + + endp = (end - sizeof(struct hrt) + 1); + + for (fp = begin; fp <= endp; fp += 16) { + temp1 = readb(fp + SIG0); + temp2 = readb(fp + SIG1); + temp3 = readb(fp + SIG2); + temp4 = readb(fp + SIG3); + if (temp1 == '$' && + temp2 == 'H' && + temp3 == 'R' && + temp4 == 'T') { + status = 1; + break; + } + } + + if (!status) + fp = NULL; + + dbg("Discovered Hotplug Resource Table at %p\n", fp); + return fp; +} + +static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_bus* bus = wrapped_bus->bus; + struct pci_dev* dev = wrapped_dev->dev; + struct pci_func *temp_func; + int i=0; + + //We need to fix up the hotplug function representation with the linux representation + do { + temp_func = cpqhp_slot_find(dev->bus->number, dev->devfn >> 3, i++); + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + if (temp_func) { + temp_func->pci_dev = dev; + } else { + //We did not even find a hotplug rep of the function, create it + //This code might be taken out if we can guarantee the creation of functions + //in parallel (hotplug and Linux at the same time). + dbg("@@@@@@@@@@@ cpqhp_slot_create in "__FUNCTION__"\n"); + temp_func = cpqhp_slot_create(bus->number); + if (temp_func == NULL) + return -ENOMEM; + temp_func->pci_dev = dev; + } + + //Create /proc/bus/pci proc entry for this device and bus device is on + //Notify the drivers of the change + if (temp_func->pci_dev) { + pci_proc_attach_device(temp_func->pci_dev); + pci_announce_device_to_drivers(temp_func->pci_dev); + } + + return 0; +} + + +static int unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev* dev = wrapped_dev->dev; + + struct pci_func *temp_func; + int i=0; + + //We need to remove the hotplug function representation with the linux representation + do { + temp_func = cpqhp_slot_find(dev->bus->number, dev->devfn >> 3, i++); + if (temp_func) { + dbg("temp_func->function = %d\n", temp_func->function); + } + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + //Now, remove the Linux Representation + if (dev) { + if (pci_hp_remove_device(dev) == 0) { + kfree(dev); //Now, remove + } else { + return -1; // problems while freeing, abort visitation + } + } + + if (temp_func) { + temp_func->pci_dev = NULL; + } else { + dbg("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn); + } + + return 0; +} + + +static int unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev) +{ + struct pci_bus* bus = wrapped_bus->bus; + + //The cleanup code for proc entries regarding buses should be in the kernel... + if (bus->procdir) + dbg("detach_pci_bus %s\n", bus->procdir->name); + pci_proc_detach_bus(bus); + // The cleanup code should live in the kernel... + bus->self->subordinate = NULL; + // unlink from parent bus + list_del(&bus->node); + + // Now, remove + if (bus) + kfree(bus); + + return 0; +} + + +static int unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev* dev = wrapped_dev->dev; + + dbg("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + //Now, remove the Linux Driver Representation + if (dev->driver) { + if (dev->driver->remove) { + dev->driver->remove(dev); + dbg("driver was properly removed\n"); + } + dev->driver = NULL; + } + + return is_pci_dev_in_use(dev); +} + + +static struct pci_visit configure_functions = { + visit_pci_dev: configure_visit_pci_dev, +}; + + +static struct pci_visit unconfigure_functions_phase1 = { + post_visit_pci_dev: unconfigure_visit_pci_dev_phase1 +}; + +static struct pci_visit unconfigure_functions_phase2 = { + post_visit_pci_bus: unconfigure_visit_pci_bus_phase2, + post_visit_pci_dev: unconfigure_visit_pci_dev_phase2 +}; + + +int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) +{ + unsigned char bus; + struct pci_dev dev0; + struct pci_bus *child; + struct pci_dev* temp; + int rc = 0; + + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + + memset(&dev0, 0, sizeof(struct pci_dev)); + + if (func->pci_dev == NULL) + func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7)); + + //Still NULL ? Well then scan for it ! + if (func->pci_dev == NULL) { + dbg("INFO: pci_dev still null\n"); + dev0.bus = ctrl->pci_dev->bus; + dev0.devfn = (func->device << 3) + (func->function & 0x7); + dev0.sysdata = ctrl->pci_dev->sysdata; + + //this will generate pci_dev structures for all functions, but we will only call this case when lookup fails + func->pci_dev = pci_scan_slot(&dev0); + if (func->pci_dev == NULL) { + dbg("ERROR: pci_dev still null\n"); + return 0; + } + } + + if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); + pci_do_scan_bus(child); + + } + + temp = func->pci_dev; + + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); + } + return rc; +} + + +int cpqhp_unconfigure_device(struct pci_func* func) +{ + int rc = 0; + int j; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + + dbg(__FUNCTION__": bus/dev/func = %x/%x/%x\n",func->bus, func->device, func->function); + + for (j=0; j<8 ; j++) { + struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j); + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev(&unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus); + if (rc) + break; + + rc = pci_visit_dev(&unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus); + if (rc) + break; + } + } + return rc; +} + +static int PCI_RefinedAccessConfig(struct pci_ops *ops, u8 bus, u8 device, u8 function, u8 offset, u32 *value) +{ + u32 vendID = 0; + + if (pci_read_config_dword_nodev (ops, bus, device, function, PCI_VENDOR_ID, &vendID) == -1) + return -1; + if (vendID == 0xffffffff) + return -1; + return pci_read_config_dword_nodev (ops, bus, device, function, offset, value); +} + + +/* + * cpqhp_set_irq + * + * @bus_num: bus number of PCI device + * @dev_num: device number of PCI device + * @slot: pointer to u8 where slot number will be returned + */ +int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) +{ + int rc; + u16 temp_word; + struct pci_dev fakedev; + struct pci_bus fakebus; + + fakedev.devfn = dev_num << 3; + fakedev.bus = &fakebus; + fakebus.number = bus_num; + dbg(__FUNCTION__": dev %d, bus %d, pin %d, num %d\n", + dev_num, bus_num, int_pin, irq_num); + rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); + dbg(__FUNCTION__":rc %d\n", rc); + if (rc) + return rc; + + // set the Edge Level Control Register (ELCR) + temp_word = inb(0x4d0); + temp_word |= inb(0x4d1) << 8; + + temp_word |= 0x01 << irq_num; + + // This should only be for x86 as it sets the Edge Level Control Register + outb((u8) (temp_word & 0xFF), 0x4d0); + outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); + + return 0; +} + + +/* + * WTF??? This function isn't in the code, yet a function calls it, but the + * compiler optimizes it away? strange. Here as a placeholder to keep the + * compiler happy. + */ +static int PCI_ScanBusNonBridge (u8 bus, u8 device) +{ + return 0; +} + +static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) +{ + u8 tdevice; + u32 work; + u8 tbus; + + for (tdevice = 0; tdevice < 0x100; tdevice++) { + //Scan for access first + if (PCI_RefinedAccessConfig(ctrl->pci_ops, bus_num, tdevice >> 3, tdevice & 0x7, 0x08, &work) == -1) + continue; + dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); + //Yep we got one. Not a bridge ? + if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) { + *dev_num = tdevice; + dbg("found it !\n"); + return 0; + } + } + for (tdevice = 0; tdevice < 0x100; tdevice++) { + //Scan for access first + if (PCI_RefinedAccessConfig(ctrl->pci_ops, bus_num, tdevice >> 3, tdevice & 0x7, 0x08, &work) == -1) + continue; + dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); + //Yep we got one. bridge ? + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_read_config_byte_nodev (ctrl->pci_ops, tbus, tdevice, 0, PCI_SECONDARY_BUS, &tbus); + dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); + if (PCI_ScanBusNonBridge(tbus, tdevice) == 0) + return 0; + } + } + + return -1; +} + + +static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge) +{ + struct irq_routing_table *PCIIRQRoutingInfoLength; + long len; + long loop; + u32 work; + + u8 tbus, tdevice, tslot; + + PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); + + len = (PCIIRQRoutingInfoLength->size - + sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return -1; + } + + for (loop = 0; loop < len; ++loop) { + tbus = PCIIRQRoutingInfoLength->slots[loop].bus; + tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn; + tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + + if (tslot == slot) { + *bus_num = tbus; + *dev_num = tdevice; + pci_read_config_dword_nodev (ctrl->pci_ops, *bus_num, *dev_num >> 3, *dev_num & 0x7, PCI_VENDOR_ID, &work); + if (!nobridge || (work == 0xffffffff)) { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + + dbg("bus_num %d dev_num %d func_num %d\n", *bus_num, *dev_num >> 3, *dev_num & 0x7); + pci_read_config_dword_nodev (ctrl->pci_ops, *bus_num, *dev_num >> 3, *dev_num & 0x7, PCI_CLASS_REVISION, &work); + dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS); + + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_read_config_byte_nodev (ctrl->pci_ops, *bus_num, *dev_num >> 3, *dev_num & 0x7, PCI_SECONDARY_BUS, &tbus); + dbg("Scan bus for Non Bridge: bus %d\n", tbus); + if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { + *bus_num = tbus; + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + } else { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + + } + } + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return -1; +} + + +int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) +{ + return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); //plain (bridges allowed) +} + + +/* More PCI configuration routines; this time centered around hotplug controller */ + + +/* + * cpqhp_save_config + * + * Reads configuration for all slots in a PCI bus and saves info. + * + * Note: For non-hot plug busses, the slot # saved is the device # + * + * returns 0 if success + */ +int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) +{ + long rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + struct pci_func *new_slot; + int sub_bus; + int FirstSupported; + int LastSupported; + int max_functions; + int function; + u8 DevError; + int device = 0; + int cloop = 0; + int stop_it; + int index; + + // Decide which slots are supported + + if (is_hot_plug) { + //********************************* + // is_hot_plug is the slot mask + //********************************* + FirstSupported = is_hot_plug >> 4; + LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1; + } else { + FirstSupported = 0; + LastSupported = 0x1F; + } + + // Save PCI configuration space for all devices in supported slots + + for (device = FirstSupported; device <= LastSupported; device++) { + ID = 0xFFFFFFFF; + rc = pci_read_config_dword_nodev (ctrl->pci_ops, busnumber, device, 0, PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { // device in slot + rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, 0, 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, 0, PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + // If multi-function device, set max_functions to 8 + if (header_type & 0x80) + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + DevError = 0; + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // P-P Bridge + // Recurse the subordinate bus + // get the subordinate bus number + rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, function, PCI_SECONDARY_BUS, &secondary_bus); + if (rc) { + return rc; + } else { + sub_bus = (int) secondary_bus; + + // Save secondary bus cfg spc + // with this recursive call. + rc = cpqhp_save_config(ctrl, sub_bus, 0); + + if (rc) + return rc; + } + } + + index = 0; + new_slot = cpqhp_slot_find(busnumber, device, index++); + while (new_slot && + (new_slot->function != (u8) function)) + new_slot = cpqhp_slot_find(busnumber, device, index++); + + if (!new_slot) { + // Setup slot structure. + new_slot = cpqhp_slot_create(busnumber); + + if (new_slot == NULL) + return(1); + } + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = (u8) function; + new_slot->is_a_board = 1; + new_slot->switch_save = 0x10; + // In case of unsupported board + new_slot->status = DevError; + new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + + for (cloop = 0; cloop < 0x20; cloop++) { + rc = pci_read_config_dword_nodev (ctrl->pci_ops, busnumber, device, function, cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + if (rc) + return rc; + } + + function++; + + stop_it = 0; + + // this loop skips to the next present function + // reading in Class Code and Header type. + + while ((function < max_functions)&&(!stop_it)) { + rc = pci_read_config_dword_nodev (ctrl->pci_ops, busnumber, device, function, PCI_VENDOR_ID, &ID); + if (ID == 0xFFFFFFFF) { // nothing there. + function++; + } else { // Something there + rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, function, 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, function, PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + stop_it++; + } + } + + } while (function < max_functions); + } // End of IF (device in slot?) + else if (is_hot_plug) { + // Setup slot structure with entry for empty slot + new_slot = cpqhp_slot_create(busnumber); + + if (new_slot == NULL) { + return(1); + } + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = 0; + new_slot->is_a_board = 0; + new_slot->presence_save = 0; + new_slot->switch_save = 0; + } + } // End of FOR loop + + return(0); +} + + +/* + * cpqhp_save_slot_config + * + * Saves configuration info for all PCI devices in a given slot + * including subordinate busses. + * + * returns 0 if success + */ +int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) +{ + long rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + int sub_bus; + int max_functions; + int function; + int cloop = 0; + int stop_it; + + ID = 0xFFFFFFFF; + + pci_read_config_dword_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, 0, PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { // device in slot + pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, 0, 0x0B, &class_code); + + pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, 0, PCI_HEADER_TYPE, &header_type); + + if (header_type & 0x80) // Multi-function device + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // Recurse the subordinate bus + pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + // Save the config headers for the secondary bus. + rc = cpqhp_save_config(ctrl, sub_bus, 0); + + if (rc) + return(rc); + + } // End of IF + + new_slot->status = 0; + + for (cloop = 0; cloop < 0x20; cloop++) { + pci_read_config_dword_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + } + + function++; + + stop_it = 0; + + // this loop skips to the next present function + // reading in the Class Code and the Header type. + + while ((function < max_functions) && (!stop_it)) { + pci_read_config_dword_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) { // nothing there. + function++; + } else { // Something there + pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, 0x0B, &class_code); + + pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, PCI_HEADER_TYPE, &header_type); + + stop_it++; + } + } + + } while (function < max_functions); + } // End of IF (device in slot?) + else { + return(2); + } + + return(0); +} + + +/* + * cpqhp_save_base_addr_length + * + * Saves the length of all base address registers for the + * specified slot. this is for hot plug REPLACE + * + * returns 0 if success + */ +int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 type; + int sub_bus; + u32 temp_register; + u32 base; + u32 rc; + struct pci_func *next; + int index = 0; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + + // Check for Bridge + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + // PCI-PCI Bridge + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + next = cpqhp_slot_list[sub_bus]; + + while (next != NULL) { + rc = cpqhp_save_base_addr_length(ctrl, next); + + if (rc) + return(rc); + + next = next->next; + } + + //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x14; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base); + + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // set base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Save information in slot structure + func->base_length[(cloop - 0x10) >> 2] = + base; + func->base_type[(cloop - 0x10) >> 2] = type; + + } // End of base register loop + + + } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base); + + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + // base = amount of memory space requested + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Save information in slot structure + func->base_length[(cloop - 0x10) >> 2] = base; + func->base_type[(cloop - 0x10) >> 2] = type; + + } // End of base register loop + + } else { // Some other unknown header type + } + + // find the next device in this slot + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return(0); +} + + +/* + * cpqhp_save_used_resources + * + * Stores used resource information for existing boards. this is + * for boards that were in the system when this driver was loaded. + * this function is for hot plug ADD + * + * returns 0 if success + */ +int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 temp_byte; + u8 b_base; + u8 b_length; + u16 command; + u16 save_command; + u16 w_base; + u16 w_length; + u32 temp_register; + u32 save_base; + u32 base; + int index = 0; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while ((func != NULL) && func->is_a_board) { + // Save the command register + pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, &save_command); + + // disable card + command = 0x00; + pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, command); + + // Check for Bridge + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // Clear Bridge Control Register + command = 0x00; + pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_BRIDGE_CONTROL, command); + + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, &secondary_bus); + + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBORDINATE_BUS, &temp_byte); + + bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = secondary_bus; + bus_node->length = temp_byte - secondary_bus + 1; + + bus_node->next = func->bus_head; + func->bus_head = bus_node; + + // Save IO base and Limit registers + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_BASE, &b_base); + + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, &b_length); + + if ((b_base <= b_length) && (save_command & 0x01)) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = (b_base & 0xF0) << 8; + io_node->length = (b_length - b_base + 0x10) << 8; + + io_node->next = func->io_head; + func->io_head = io_node; + } + // Save memory base and Limit registers + pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, &w_base); + + pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (save_command & 0x02)) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = w_base << 16; + mem_node->length = (w_length - w_base + 0x10) << 16; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + // Save prefetchable memory base and Limit registers + pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, &w_base); + + pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (save_command & 0x02)) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = w_base << 16; + p_mem_node->length = (w_length - w_base + 0x10) << 16; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x14; cloop += 4) { + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &save_base); + + temp_register = 0xFFFFFFFF; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base); + + temp_register = base; + + if (base) { // If this register is implemented + if (((base & 0x03L) == 0x01) + && (save_command & 0x01)) { + // IO base + // set temp_register = amount of IO space requested + temp_register = base & 0xFFFFFFFE; + temp_register = (~temp_register) + 1; + + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = + save_base & (~0x03L); + io_node->length = temp_register; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + if (((base & 0x0BL) == 0x08) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = save_base & (~0x0FL); + p_mem_node->length = temp_register; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + if (((base & 0x0BL) == 0x00) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = save_base & (~0x0FL); + mem_node->length = temp_register; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return(1); + } + } // End of base register loop + } else if ((header_type & 0x7F) == 0x00) { // Standard header + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &save_base); + + temp_register = 0xFFFFFFFF; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base); + + temp_register = base; + + if (base) { // If this register is implemented + if (((base & 0x03L) == 0x01) + && (save_command & 0x01)) { + // IO base + // set temp_register = amount of IO space requested + temp_register = base & 0xFFFFFFFE; + temp_register = (~temp_register) + 1; + + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = save_base & (~0x01L); + io_node->length = temp_register; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + if (((base & 0x0BL) == 0x08) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = save_base & (~0x0FL); + p_mem_node->length = temp_register; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + if (((base & 0x0BL) == 0x00) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = save_base & (~0x0FL); + mem_node->length = temp_register; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return(1); + } + } // End of base register loop + } else { // Some other unknown header type + } + + // find the next device in this slot + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return(0); +} + + +/* + * cpqhp_configure_board + * + * Copies saved configuration information to one slot. + * this is called recursively for bridge devices. + * this is for hot plug REPLACE! + * + * returns 0 if success + */ +int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) +{ + int cloop; + u8 header_type; + u8 secondary_bus; + int sub_bus; + struct pci_func *next; + u32 temp; + u32 rc; + int index = 0; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + // Start at the top of config space so that the control + // registers are programmed last + for (cloop = 0x3C; cloop > 0; cloop -= 4) { + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, func->config_space[cloop >> 2]); + } + + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type); + + // If this is a bridge device, restore subordinate devices + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + next = cpqhp_slot_list[sub_bus]; + + while (next != NULL) { + rc = cpqhp_configure_board(ctrl, next); + + if (rc) + return rc; + + next = next->next; + } + } else { + + // Check all the base Address Registers to make sure + // they are the same. If not, the board is different. + + for (cloop = 16; cloop < 40; cloop += 4) { + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &temp); + + if (temp != func->config_space[cloop >> 2]) { + dbg("Config space compare failure!!! offset = %x\n", cloop); + dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function); + dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop]); + return 1; + } + } + } + + func->configured = 1; + + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return 0; +} + + +/* + * cpqhp_valid_replace + * + * this function checks to see if a board is the same as the + * one it is replacing. this check will detect if the device's + * vendor or device id's are the same + * + * returns 0 if the board is the same nonzero otherwise + */ +int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 type; + u32 temp_register = 0; + u32 base; + u32 rc; + struct pci_func *next; + int index = 0; + + if (!func->is_a_board) + return(ADD_NOT_SUPPORTED); + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_VENDOR_ID, &temp_register); + + // No adapter present + if (temp_register == 0xFFFFFFFF) + return(NO_ADAPTER_PRESENT); + + if (temp_register != func->config_space[0]) + return(ADAPTER_NOT_SAME); + + // Check for same revision number and class code + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_CLASS_REVISION, &temp_register); + + // Adapter not the same + if (temp_register != func->config_space[0x08 >> 2]) + return(ADAPTER_NOT_SAME); + + // Check for Bridge + pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // In order to continue checking, we must program the + // bus registers in the bridge to respond to accesses + // for it's subordinate bus(es) + + temp_register = func->config_space[0x18 >> 2]; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PRIMARY_BUS, temp_register); + + secondary_bus = (temp_register >> 8) & 0xFF; + + next = cpqhp_slot_list[secondary_bus]; + + while (next != NULL) { + rc = cpqhp_valid_replace(ctrl, next); + + if (rc) + return(rc); + + next = next->next; + } + + } + // Check to see if it is a standard config header + else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + // Check subsystem vendor and ID + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); + + if (temp_register != func->config_space[0x2C >> 2]) { + // If it's a SMART-2 and the register isn't filled + // in, ignore the difference because + // they just have an old rev of the firmware + + if (!((func->config_space[0] == 0xAE100E11) + && (temp_register == 0x00L))) + return(ADAPTER_NOT_SAME); + } + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register); + + pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base); + + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // set base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Check information in slot structure + if (func->base_length[(cloop - 0x10) >> 2] != base) + return(ADAPTER_NOT_SAME); + + if (func->base_type[(cloop - 0x10) >> 2] != type) + return(ADAPTER_NOT_SAME); + + } // End of base register loop + + } // End of (type 0 config space) else + else { + // this is not a type 0 or 1 config space header so + // we don't know how to do it + return(DEVICE_TYPE_NOT_SUPPORTED); + } + + // Get the next function + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + + return(0); +} + + +/* + * cpqhp_find_available_resources + * + * Finds available memory, IO, and IRQ resources for programming + * devices which may be added to the system + * this function is for hot plug ADD! + * + * returns 0 if success + */ +int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start) +{ + u8 temp; + u8 populated_slot; + u8 bridged_slot; + void *one_slot; + struct pci_func *func = NULL; + int i = 10, index; + u32 temp_dword, rc; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + void *rom_resource_table; + + rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff); + dbg("rom_resource_table = %p\n", rom_resource_table); + + if (rom_resource_table == NULL) { + return -ENODEV; + } + // Sum all resources and setup resource maps + unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); + dbg("unused_IRQ = %x\n", unused_IRQ); + + temp = 0; + while (unused_IRQ) { + if (unused_IRQ & 1) { + cpqhp_disk_irq = temp; + break; + } + unused_IRQ = unused_IRQ >> 1; + temp++; + } + + dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq); + unused_IRQ = unused_IRQ >> 1; + temp++; + + while (unused_IRQ) { + if (unused_IRQ & 1) { + cpqhp_nic_irq = temp; + break; + } + unused_IRQ = unused_IRQ >> 1; + temp++; + } + + dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq); + unused_IRQ = readl(rom_resource_table + PCIIRQ); + + temp = 0; + + if (!cpqhp_nic_irq) { + cpqhp_nic_irq = ctrl->interrupt; + } + + if (!cpqhp_disk_irq) { + cpqhp_disk_irq = ctrl->interrupt; + } + + dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); + + rc = compaq_nvram_load(rom_start, ctrl); + if (rc) + return rc; + + one_slot = rom_resource_table + sizeof (struct hrt); + + i = readb(rom_resource_table + NUMBER_OF_ENTRIES); + dbg("number_of_entries = %d\n", i); + + if (!readb(one_slot + SECONDARY_BUS)) { + return(1); + } + + dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n"); + + while (i && readb(one_slot + SECONDARY_BUS)) { + u8 dev_func = readb(one_slot + DEV_FUNC); + u8 primary_bus = readb(one_slot + PRIMARY_BUS); + u8 secondary_bus = readb(one_slot + SECONDARY_BUS); + u8 max_bus = readb(one_slot + MAX_BUS); + u16 io_base = readw(one_slot + IO_BASE); + u16 io_length = readw(one_slot + IO_LENGTH); + u16 mem_base = readw(one_slot + MEM_BASE); + u16 mem_length = readw(one_slot + MEM_LENGTH); + u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); + u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); + + dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", + dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, + primary_bus, secondary_bus, max_bus); + + // If this entry isn't for our controller's bus, ignore it + if (primary_bus != ctrl->bus) { + i--; + one_slot += sizeof (struct slot_rt); + continue; + } + // find out if this entry is for an occupied slot + pci_read_config_dword_nodev (ctrl->pci_ops, primary_bus, dev_func >> 3, dev_func & 0x07, PCI_VENDOR_ID, &temp_dword); + + dbg("temp_D_word = %x\n", temp_dword); + + if (temp_dword != 0xFFFFFFFF) { + index = 0; + func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0); + + while (func && (func->function != (dev_func & 0x07))) { + dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index); + func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++); + } + + // If we can't find a match, skip this table entry + if (!func) { + i--; + one_slot += sizeof (struct slot_rt); + continue; + } + // this may not work and shouldn't be used + if (secondary_bus != primary_bus) + bridged_slot = 1; + else + bridged_slot = 0; + + populated_slot = 1; + } else { + populated_slot = 0; + bridged_slot = 0; + } + + + // If we've got a valid IO base, use it + + temp_dword = io_base + io_length; + + if ((io_base) && (temp_dword < 0x10000)) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = io_base; + io_node->length = io_length; + + dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + io_node->next = ctrl->io_head; + ctrl->io_head = io_node; + } else { + io_node->next = func->io_head; + func->io_head = io_node; + } + } + + // If we've got a valid memory base, use it + temp_dword = mem_base + mem_length; + if ((mem_base) && (temp_dword < 0x10000)) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = mem_base << 16; + + mem_node->length = mem_length << 16; + + dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + mem_node->next = ctrl->mem_head; + ctrl->mem_head = mem_node; + } else { + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + } + + // If we've got a valid prefetchable memory base, and + // the base + length isn't greater than 0xFFFF + temp_dword = pre_mem_base + pre_mem_length; + if ((pre_mem_base) && (temp_dword < 0x10000)) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = pre_mem_base << 16; + + p_mem_node->length = pre_mem_length << 16; + dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); + dbg("populated slot =%d \n", populated_slot); + + if (!populated_slot) { + p_mem_node->next = ctrl->p_mem_head; + ctrl->p_mem_head = p_mem_node; + } else { + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + } + + // If we've got a valid bus number, use it + // The second condition is to ignore bus numbers on + // populated slots that don't have PCI-PCI bridges + if (secondary_bus && (secondary_bus != primary_bus)) { + bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = secondary_bus; + bus_node->length = max_bus - secondary_bus + 1; + dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + bus_node->next = ctrl->bus_head; + ctrl->bus_head = bus_node; + } else { + bus_node->next = func->bus_head; + func->bus_head = bus_node; + } + } + + i--; + one_slot += sizeof (struct slot_rt); + } + + // If all of the following fail, we don't have any resources for + // hot plug add + rc = 1; + rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + return(rc); +} + + +/* + * cpqhp_return_board_resources + * + * this routine returns all resources allocated to a board to + * the available pool. + * + * returns 0 if success + */ +int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources) +{ + int rc = 0; + struct pci_resource *node; + struct pci_resource *t_node; + dbg(__FUNCTION__"\n"); + + if (!func) + return(1); + + node = func->io_head; + func->io_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->io_head), node); + node = t_node; + } + + node = func->mem_head; + func->mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->mem_head), node); + node = t_node; + } + + node = func->p_mem_head; + func->p_mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->p_mem_head), node); + node = t_node; + } + + node = func->bus_head; + func->bus_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->bus_head), node); + node = t_node; + } + + rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->io_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head)); + + return(rc); +} + + +/* + * cpqhp_destroy_resource_list + * + * Puts node back in the resource list pointed to by head + */ +void cpqhp_destroy_resource_list (struct resource_lists * resources) +{ + struct pci_resource *res, *tres; + + res = resources->io_head; + resources->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->mem_head; + resources->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->p_mem_head; + resources->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->bus_head; + resources->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + + +/* + * cpqhp_destroy_board_resources + * + * Puts node back in the resource list pointed to by head + */ +void cpqhp_destroy_board_resources (struct pci_func * func) +{ + struct pci_resource *res, *tres; + + res = func->io_head; + func->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->mem_head; + func->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->p_mem_head; + func->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->bus_head; + func->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/cpqphp_proc.c linux/drivers/hotplug/cpqphp_proc.c --- v2.4.14/linux/drivers/hotplug/cpqphp_proc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/cpqphp_proc.c Fri Nov 9 14:01:22 2001 @@ -0,0 +1,192 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/pci.h> +#include "cpqphp.h" + + + +static struct proc_dir_entry *ctrl_proc_root; + +/* A few routines that create proc entries for the hot plug controller */ + +static int read_ctrl (char *buf, char **start, off_t offset, int len, int *eof, void *data) +{ + struct controller *ctrl = (struct controller *)data; + char * out = buf; + int index; + struct pci_resource *res; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + + out += sprintf(out, "hot plug ctrl Info Page\n"); + out += sprintf(out, "bus = %d, device = %d, function = %d\n",ctrl->bus, + ctrl->device, ctrl->function); + out += sprintf(out, "Free resources: memory\n"); + index = 11; + res = ctrl->mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: prefetchable memory\n"); + index = 11; + res = ctrl->p_mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: IO\n"); + index = 11; + res = ctrl->io_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: bus numbers\n"); + index = 11; + res = ctrl->bus_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + + *start = buf; + len = out-buf; + + return len; +} + +static int read_dev (char *buf, char **start, off_t offset, int len, int *eof, void *data) +{ + struct controller *ctrl = (struct controller *)data; + char * out = buf; + int index; + struct pci_resource *res; + struct pci_func *new_slot; + struct slot *slot; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + + out += sprintf(out, "hot plug ctrl Info Page\n"); + out += sprintf(out, "bus = %d, device = %d, function = %d\n",ctrl->bus, + ctrl->device, ctrl->function); + + slot=ctrl->slot; + + while (slot) { + new_slot = cpqhp_slot_find(slot->bus, slot->device, 0); + out += sprintf(out, "assigned resources: memory\n"); + index = 11; + res = new_slot->mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: prefetchable memory\n"); + index = 11; + res = new_slot->p_mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: IO\n"); + index = 11; + res = new_slot->io_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: bus numbers\n"); + index = 11; + res = new_slot->bus_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + slot=slot->next; + } + + *start = buf; + len = out-buf; + + return len; +} + +int cpqhp_proc_create_ctrl (struct controller *ctrl) +{ + strcpy(ctrl->proc_name, "hpca"); + ctrl->proc_name[3] = 'a' + ctrl->bus; + + ctrl->proc_entry = create_proc_entry(ctrl->proc_name, S_IFREG | S_IRUGO, ctrl_proc_root); + ctrl->proc_entry->data = ctrl; + ctrl->proc_entry->read_proc = &read_ctrl; + + strcpy(ctrl->proc_name2, "slot_a"); + ctrl->proc_name2[5] = 'a' + ctrl->bus; + ctrl->proc_entry2 = create_proc_entry(ctrl->proc_name2, S_IFREG | S_IRUGO, ctrl_proc_root); + ctrl->proc_entry2->data = ctrl; + ctrl->proc_entry2->read_proc = &read_dev; + + return 0; +} + +int cpqhp_proc_remove_ctrl (struct controller *ctrl) +{ + if (ctrl->proc_entry) + remove_proc_entry(ctrl->proc_name, ctrl_proc_root); + if (ctrl->proc_entry2) + remove_proc_entry(ctrl->proc_name2, ctrl_proc_root); + + return 0; +} + +int cpqhp_proc_init_ctrl (void) +{ + ctrl_proc_root = proc_mkdir("driver/hpc", NULL); + if (!ctrl_proc_root) + return -ENOMEM; + ctrl_proc_root->owner = THIS_MODULE; + return 0; +} + +int cpqhp_proc_destroy_ctrl (void) +{ + remove_proc_entry("hpc", proc_root_driver); + return 0; +} + diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/pci_hotplug.h linux/drivers/hotplug/pci_hotplug.h --- v2.4.14/linux/drivers/hotplug/pci_hotplug.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/pci_hotplug.h Fri Nov 9 14:01:22 2001 @@ -0,0 +1,160 @@ +/* + * PCI HotPlug Core Functions + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <greg@kroah.com> + * + */ +#ifndef _PCI_HOTPLUG_H +#define _PCI_HOTPLUG_H + + +struct hotplug_slot; +struct hotplug_slot_core; + +/** + * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use + * @owner: The module owner of this structure + * @enable_slot: Called when the user wants to enable a specific pci slot + * @disable_slot: Called when the user wants to disable a specific pci slot + * @set_attention_status: Called to set the specific slot's attention LED to + * the specified value + * @hardware_test: Called to run a specified hardware test on the specified + * slot. + * @get_power_status: Called to get the current power status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_attention_status: Called to get the current attention status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_latch_status: Called to get the current latch status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_adapter_present: Called to get see if an adapter is present in the slot or not. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * + * The table of function pointers that is passed to the hotplug pci core by a + * hotplug pci driver. These functions are called by the hotplug pci core when + * the user wants to do something to a specific slot (query it for information, + * set an LED, enable / disable power, etc.) + */ +struct hotplug_slot_ops { + struct module *owner; + int (*enable_slot) (struct hotplug_slot *slot); + int (*disable_slot) (struct hotplug_slot *slot); + int (*set_attention_status) (struct hotplug_slot *slot, u8 value); + int (*hardware_test) (struct hotplug_slot *slot, u32 value); + int (*get_power_status) (struct hotplug_slot *slot, u8 *value); + int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); + int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); + int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); +}; + +/** + * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot + * @power: if power is enabled or not (1/0) + * @attention_status: if the attention light is enabled or not (1/0) + * @latch_status: if the latch (if any) is open or closed (1/0) + * @adapter_present: if there is a pci board present in the slot or not (1/0) + * + * Used to notify the hotplug pci core of the status of a specific slot. + */ +struct hotplug_slot_info { + u8 power_status; + u8 attention_status; + u8 latch_status; + u8 adapter_status; +}; + +/** + * struct hotplug_slot - used to register a physical slot with the hotplug pci core + * @name: the name of the slot being registered. This string must + * be unique amoung slots registered on this system. + * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot + * @info: pointer to the &struct hotplug_slot_info for the inital values for + * this slot. + * @private: used by the hotplug pci controller driver to store whatever it + * needs. + */ +struct hotplug_slot { + char *name; + struct hotplug_slot_ops *ops; + struct hotplug_slot_info *info; + void *private; + + /* Variables below this are for use only by the hotplug pci core. */ + struct list_head slot_list; + struct hotplug_slot_core *core_priv; +}; + +extern int pci_hp_register (struct hotplug_slot *slot); +extern int pci_hp_deregister (struct hotplug_slot *slot); +extern int pci_hp_change_slot_info (const char *name, + struct hotplug_slot_info *info); + +struct pci_dev_wrapped { + struct pci_dev *dev; + void *data; +}; + +struct pci_bus_wrapped { + struct pci_bus *bus; + void *data; +}; + +struct pci_visit { + int (* pre_visit_pci_bus) (struct pci_bus_wrapped *, + struct pci_dev_wrapped *); + int (* post_visit_pci_bus) (struct pci_bus_wrapped *, + struct pci_dev_wrapped *); + + int (* pre_visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); + int (* visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); + int (* post_visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); +}; + +extern int pci_visit_dev (struct pci_visit *fn, + struct pci_dev_wrapped *wrapped_dev, + struct pci_bus_wrapped *wrapped_parent); + +extern int pci_read_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u8 *val); +extern int pci_read_config_word_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u16 *val); +extern int pci_read_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u32 *val); + +extern int pci_write_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u8 val); +extern int pci_write_config_word_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u16 val); +extern int pci_write_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 device, + u8 function, int where, u32 val); + + +#endif + diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/pci_hotplug_core.c linux/drivers/hotplug/pci_hotplug_core.c --- v2.4.14/linux/drivers/hotplug/pci_hotplug_core.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/pci_hotplug_core.c Fri Nov 9 14:01:22 2001 @@ -0,0 +1,1132 @@ +/* + * PCI HotPlug Controller Core + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/pagemap.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <asm/uaccess.h> +#include "pci_hotplug.h" + + +#if !defined(CONFIG_HOTPLUG_PCI_MODULE) + #define MY_NAME "pci_hotplug" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: "__FUNCTION__": " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* local variables */ +static int debug; + +#define DRIVER_VERSION "0.3" +#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" +#define DRIVER_DESC "PCI Hot Plug PCI Core" + + +////////////////////////////////////////////////////////////////// + +/* Random magic number */ +#define PCIHPFS_MAGIC 0x52454541 + +struct hotplug_slot_core { + struct dentry *dir_dentry; + struct dentry *power_dentry; + struct dentry *attention_dentry; + struct dentry *latch_dentry; + struct dentry *adapter_dentry; + struct dentry *test_dentry; +}; + +static struct super_operations pcihpfs_ops; +static struct address_space_operations pcihpfs_aops; +static struct file_operations pcihpfs_dir_operations; +static struct file_operations default_file_operations; +static struct inode_operations pcihpfs_dir_inode_operations; +static struct vfsmount *pcihpfs_mount; /* one of the mounts of our fs for reference counting */ +static int pcihpfs_mount_count; /* times we have mounted our fs */ +static spinlock_t mount_lock; /* protects our mount_count */ +static spinlock_t list_lock; + +LIST_HEAD(pci_hotplug_slot_list); + + +static int pcihpfs_statfs (struct super_block *sb, struct statfs *buf) +{ + buf->f_type = PCIHPFS_MAGIC; + buf->f_bsize = PAGE_CACHE_SIZE; + buf->f_namelen = 255; + return 0; +} + +static struct dentry *pcihpfs_lookup (struct inode *dir, struct dentry *dentry) +{ + d_add(dentry, NULL); + return NULL; +} + +static struct inode *pcihpfs_get_inode (struct super_block *sb, int mode, int dev) +{ + struct inode *inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = NODEV; + inode->i_mapping->a_ops = &pcihpfs_aops; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_fop = &default_file_operations; + break; + case S_IFDIR: + inode->i_op = &pcihpfs_dir_inode_operations; + inode->i_fop = &pcihpfs_dir_operations; + break; + } + } + return inode; +} + +static int pcihpfs_mknod (struct inode *dir, struct dentry *dentry, int mode, int dev) +{ + struct inode *inode = pcihpfs_get_inode(dir->i_sb, mode, dev); + int error = -ENOSPC; + + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); + error = 0; + } + return error; +} + +static int pcihpfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) +{ + return pcihpfs_mknod (dir, dentry, mode | S_IFDIR, 0); +} + +static int pcihpfs_create (struct inode *dir, struct dentry *dentry, int mode) +{ + return pcihpfs_mknod (dir, dentry, mode | S_IFREG, 0); +} + +static int pcihpfs_link (struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) +{ + struct inode *inode = old_dentry->d_inode; + + if(S_ISDIR(inode->i_mode)) + return -EPERM; + + inode->i_nlink++; + atomic_inc(&inode->i_count); + dget(dentry); + d_instantiate(dentry, inode); + return 0; +} + +static inline int pcihpfs_positive (struct dentry *dentry) +{ + return dentry->d_inode && !d_unhashed(dentry); +} + +static int pcihpfs_empty (struct dentry *dentry) +{ + struct list_head *list; + + spin_lock(&dcache_lock); + + list_for_each(list, &dentry->d_subdirs) { + struct dentry *de = list_entry(list, struct dentry, d_child); + if (pcihpfs_positive(de)) { + spin_unlock(&dcache_lock); + return 0; + } + } + + spin_unlock(&dcache_lock); + return 1; +} + +static int pcihpfs_unlink (struct inode *dir, struct dentry *dentry) +{ + int error = -ENOTEMPTY; + + if (pcihpfs_empty(dentry)) { + struct inode *inode = dentry->d_inode; + + inode->i_nlink--; + dput(dentry); + error = 0; + } + return error; +} + +static int pcihpfs_rename (struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + int error = -ENOTEMPTY; + + if (pcihpfs_empty(new_dentry)) { + struct inode *inode = new_dentry->d_inode; + if (inode) { + inode->i_nlink--; + dput(new_dentry); + } + error = 0; + } + return error; +} + +#define pcihpfs_rmdir pcihpfs_unlink + +/* default file operations */ +static ssize_t default_read_file (struct file *file, char *buf, size_t count, loff_t *ppos) +{ + dbg ("\n"); + return 0; +} + +static ssize_t default_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + dbg ("\n"); + return count; +} + +static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) +{ + loff_t retval = -EINVAL; + + switch(orig) { + case 0: + if (offset > 0) { + file->f_pos = offset; + retval = file->f_pos; + } + break; + case 1: + if ((offset + file->f_pos) > 0) { + file->f_pos += offset; + retval = file->f_pos; + } + break; + default: + break; + } + return retval; +} + +static int default_open (struct inode *inode, struct file *filp) +{ + if (inode->u.generic_ip) + filp->private_data = inode->u.generic_ip; + + return 0; +} + +static int default_sync_file (struct file *file, struct dentry *dentry, int datasync) +{ + return 0; +} + +static struct address_space_operations pcihpfs_aops = { +}; + +static struct file_operations pcihpfs_dir_operations = { + read: generic_read_dir, + readdir: dcache_readdir, + fsync: default_sync_file, +}; + +static struct file_operations default_file_operations = { + read: default_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +/* file ops for the "power" files */ +static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static ssize_t power_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos); +static struct file_operations power_file_operations = { + read: power_read_file, + write: power_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +/* file ops for the "attention" files */ +static ssize_t attention_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static ssize_t attention_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos); +static struct file_operations attention_file_operations = { + read: attention_read_file, + write: attention_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +/* file ops for the "latch" files */ +static ssize_t latch_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static struct file_operations latch_file_operations = { + read: latch_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +/* file ops for the "presence" files */ +static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static struct file_operations presence_file_operations = { + read: presence_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +/* file ops for the "test" files */ +static ssize_t test_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos); +static struct file_operations test_file_operations = { + read: default_read_file, + write: test_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, +}; + +static struct inode_operations pcihpfs_dir_inode_operations = { + create: pcihpfs_create, + lookup: pcihpfs_lookup, + link: pcihpfs_link, + unlink: pcihpfs_unlink, + mkdir: pcihpfs_mkdir, + rmdir: pcihpfs_rmdir, + mknod: pcihpfs_mknod, + rename: pcihpfs_rename, +}; + +static struct super_operations pcihpfs_ops = { + statfs: pcihpfs_statfs, + put_inode: force_delete, +}; + +static struct super_block *pcihpfs_read_super (struct super_block *sb, void *data, int silent) +{ + struct inode *inode; + struct dentry *root; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = PCIHPFS_MAGIC; + sb->s_op = &pcihpfs_ops; + inode = pcihpfs_get_inode(sb, S_IFDIR | 0755, 0); + + if (!inode) { + dbg("%s: could not get inode!\n",__FUNCTION__); + return NULL; + } + + root = d_alloc_root(inode); + if (!root) { + dbg("%s: could not get root dentry!\n",__FUNCTION__); + iput(inode); + return NULL; + } + sb->s_root = root; + return sb; +} + +static DECLARE_FSTYPE(pcihpfs_fs_type, "pcihpfs", pcihpfs_read_super, FS_SINGLE | FS_LITTER); + +static int get_mount (void) +{ + struct vfsmount *mnt; + + spin_lock (&mount_lock); + if (pcihpfs_mount) { + mntget(pcihpfs_mount); + ++pcihpfs_mount_count; + spin_unlock (&mount_lock); + goto go_ahead; + } + + spin_unlock (&mount_lock); + mnt = kern_mount (&pcihpfs_fs_type); + if (IS_ERR(mnt)) { + err ("could not mount the fs...erroring out!\n"); + return -ENODEV; + } + spin_lock (&mount_lock); + if (!pcihpfs_mount) { + pcihpfs_mount = mnt; + ++pcihpfs_mount_count; + spin_unlock (&mount_lock); + goto go_ahead; + } + mntget(pcihpfs_mount); + ++pcihpfs_mount_count; + spin_unlock (&mount_lock); + mntput(mnt); + +go_ahead: + dbg("pcihpfs_mount_count = %d\n", pcihpfs_mount_count); + return 0; +} + +static void remove_mount (void) +{ + struct vfsmount *mnt; + + spin_lock (&mount_lock); + mnt = pcihpfs_mount; + --pcihpfs_mount_count; + if (!pcihpfs_mount_count) + pcihpfs_mount = NULL; + + spin_unlock (&mount_lock); + mntput(mnt); + dbg("pcihpfs_mount_count = %d\n", pcihpfs_mount_count); +} + + +/** + * pcihpfs_create_by_name - create a file, given a name + * @name: name of file + * @mode: type of file + * @parent: dentry of directory to create it in + * @dentry: resulting dentry of file + * + * There is a bit of overhead in creating a file - basically, we + * have to hash the name of the file, then look it up. This will + * prevent files of the same name. + * We then call the proper vfs_ function to take care of all the + * file creation details. + * This function handles both regular files and directories. + */ +static int pcihpfs_create_by_name (const char *name, mode_t mode, + struct dentry *parent, struct dentry **dentry) +{ + struct dentry *d = NULL; + struct qstr qstr; + int error; + + /* If the parent is not specified, we create it in the root. + * We need the root dentry to do this, which is in the super + * block. A pointer to that is in the struct vfsmount that we + * have around. + */ + if (!parent ) { + if (pcihpfs_mount && pcihpfs_mount->mnt_sb) { + parent = pcihpfs_mount->mnt_sb->s_root; + } + } + + if (!parent) { + dbg("Ah! can not find a parent!\n"); + return -EFAULT; + } + + *dentry = NULL; + qstr.name = name; + qstr.len = strlen(name); + qstr.hash = full_name_hash(name,qstr.len); + + parent = dget(parent); + + down(&parent->d_inode->i_sem); + + d = lookup_hash(&qstr,parent); + + error = PTR_ERR(d); + if (!IS_ERR(d)) { + switch(mode & S_IFMT) { + case 0: + case S_IFREG: + error = vfs_create(parent->d_inode,d,mode); + break; + case S_IFDIR: + error = vfs_mkdir(parent->d_inode,d,mode); + break; + default: + err("cannot create special files\n"); + } + *dentry = d; + } + up(&parent->d_inode->i_sem); + + dput(parent); + return error; +} + +static struct dentry *fs_create_file (const char *name, mode_t mode, + struct dentry *parent, void *data, + struct file_operations *fops) +{ + struct dentry *dentry; + int error; + + dbg("creating file '%s'\n",name); + + error = pcihpfs_create_by_name(name,mode,parent,&dentry); + if (error) { + dentry = NULL; + } else { + if (dentry->d_inode) { + if (data) + dentry->d_inode->u.generic_ip = data; + if (fops) + dentry->d_inode->i_fop = fops; + } + } + + return dentry; +} + +static void fs_remove_file (struct dentry *dentry) +{ + struct dentry *parent = dentry->d_parent; + + if (!parent || !parent->d_inode) + return; + + down(&parent->d_inode->i_sem); + if (pcihpfs_positive(dentry)) { + if (dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode)) + vfs_rmdir(parent->d_inode,dentry); + else + vfs_unlink(parent->d_inode,dentry); + } + + dput(dentry); + } + up(&parent->d_inode->i_sem); +} + +#define GET_STATUS(name) \ +static int get_##name##_status (struct hotplug_slot *slot, u8 *value) \ +{ \ + struct hotplug_slot_ops *ops = slot->ops; \ + int retval = 0; \ + if (ops->owner) \ + __MOD_INC_USE_COUNT(ops->owner); \ + if (ops->get_##name##_status) \ + retval = ops->get_##name##_status (slot, value); \ + else \ + *value = slot->info->name##_status; \ + if (ops->owner) \ + __MOD_DEC_USE_COUNT(ops->owner); \ + return retval; \ +} + +GET_STATUS(power) +GET_STATUS(attention) +GET_STATUS(latch) +GET_STATUS(adapter) + +static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + int retval; + int len; + u8 value; + + dbg(" count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_power_status (slot, &value); + if (retval) + goto exit; + len = sprintf (page, "%d\n", value); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + +static ssize_t power_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + const char *buff; + unsigned long lpower; + u8 power; + int retval = 0; + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + buff = kmalloc (count, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + if (copy_from_user ((void *)buff, (void *)ubuff, count)) { + retval = -EFAULT; + goto exit; + } + + lpower = simple_strtoul (buff, NULL, 10); + power = (u8)(lpower & 0xff); + dbg ("power = %d\n", power); + + switch (power) { + case 0: + if (!slot->ops->disable_slot) + break; + if (slot->ops->owner) + __MOD_INC_USE_COUNT(slot->ops->owner); + retval = slot->ops->disable_slot(slot); + if (slot->ops->owner) + __MOD_DEC_USE_COUNT(slot->ops->owner); + break; + + case 1: + if (!slot->ops->enable_slot) + break; + if (slot->ops->owner) + __MOD_INC_USE_COUNT(slot->ops->owner); + retval = slot->ops->enable_slot(slot); + if (slot->ops->owner) + __MOD_DEC_USE_COUNT(slot->ops->owner); + break; + + default: + err ("Illegal value specified for power\n"); + retval = -EFAULT; + } + +exit: + kfree (buff); + + if (retval) + return retval; + return count; +} + +static ssize_t attention_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + int retval; + int len; + u8 value; + + dbg("count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_attention_status (slot, &value); + if (retval) + goto exit; + len = sprintf (page, "%d\n", value); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + +static ssize_t attention_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + const char *buff; + unsigned long lattention; + u8 attention; + int retval = 0; + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + buff = kmalloc (count, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + if (copy_from_user ((void *)buff, (void *)ubuff, count)) { + retval = -EFAULT; + goto exit; + } + + lattention = simple_strtoul (buff, NULL, 10); + attention = (u8)(lattention & 0xff); + dbg (" - attention = %d\n", attention); + + if (slot->ops->set_attention_status) { + if (slot->ops->owner) + __MOD_INC_USE_COUNT(slot->ops->owner); + retval = slot->ops->set_attention_status(slot, attention); + if (slot->ops->owner) + __MOD_DEC_USE_COUNT(slot->ops->owner); + } + +exit: + kfree (buff); + + if (retval) + return retval; + return count; +} + +static ssize_t latch_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + int retval; + int len; + u8 value; + + dbg("count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_latch_status (slot, &value); + if (retval) + goto exit; + len = sprintf (page, "%d\n", value); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + + +static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + int retval; + int len; + u8 value; + + dbg("count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_adapter_status (slot, &value); + if (retval) + goto exit; + len = sprintf (page, "%d\n", value); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + +static ssize_t test_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + const char *buff; + unsigned long ltest; + u32 test; + int retval = 0; + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + buff = kmalloc (count, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + if (copy_from_user ((void *)buff, (void *)ubuff, count)) { + retval = -EFAULT; + goto exit; + } + + ltest = simple_strtoul (buff, NULL, 10); + test = (u32)(ltest & 0xffffffff); + dbg ("test = %d\n", test); + + if (slot->ops->hardware_test) { + if (slot->ops->owner) + __MOD_INC_USE_COUNT(slot->ops->owner); + retval = slot->ops->hardware_test(slot, test); + if (slot->ops->owner) + __MOD_DEC_USE_COUNT(slot->ops->owner); + } + +exit: + kfree (buff); + + if (retval) + return retval; + return count; +} + +static int fs_add_slot (struct hotplug_slot *slot) +{ + struct hotplug_slot_core *core = slot->core_priv; + int result; + + result = get_mount(); + if (result) + return result; + + core->dir_dentry = fs_create_file (slot->name, + S_IFDIR | S_IXUGO | S_IRUGO, + NULL, NULL, NULL); + if (core->dir_dentry != NULL) { + core->power_dentry = fs_create_file ("power", + S_IFREG | S_IRUGO | S_IWUSR, + core->dir_dentry, slot, + &power_file_operations); + + core->attention_dentry = fs_create_file ("attention", + S_IFREG | S_IRUGO | S_IWUSR, + core->dir_dentry, slot, + &attention_file_operations); + + core->latch_dentry = fs_create_file ("latch", + S_IFREG | S_IRUGO, + core->dir_dentry, slot, + &latch_file_operations); + + core->adapter_dentry = fs_create_file ("adapter", + S_IFREG | S_IRUGO, + core->dir_dentry, slot, + &presence_file_operations); + + core->test_dentry = fs_create_file ("test", + S_IFREG | S_IRUGO | S_IWUSR, + core->dir_dentry, slot, + &test_file_operations); + } + return 0; +} + +static void fs_remove_slot (struct hotplug_slot *slot) +{ + struct hotplug_slot_core *core = slot->core_priv; + + if (core->dir_dentry) { + if (core->power_dentry) + fs_remove_file (core->power_dentry); + if (core->attention_dentry) + fs_remove_file (core->attention_dentry); + if (core->latch_dentry) + fs_remove_file (core->latch_dentry); + if (core->adapter_dentry) + fs_remove_file (core->adapter_dentry); + if (core->test_dentry) + fs_remove_file (core->test_dentry); + fs_remove_file (core->dir_dentry); + } + + remove_mount(); +} + +static struct hotplug_slot *get_slot_from_name (const char *name) +{ + struct hotplug_slot *slot; + struct list_head *tmp; + + list_for_each (tmp, &pci_hotplug_slot_list) { + slot = list_entry (tmp, struct hotplug_slot, slot_list); + if (strcmp(slot->name, name) == 0) + return slot; + } + return NULL; +} + +/** + * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem + * @slot: pointer to the &struct hotplug_slot to register + * + * Registers a hotplug slot with the pci hotplug subsystem, which will allow + * userspace interaction to the slot. + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_register (struct hotplug_slot *slot) +{ + struct hotplug_slot_core *core; + int result; + + if (slot == NULL) + return -ENODEV; + if ((slot->info == NULL) || (slot->ops == NULL)) + return -EFAULT; + + core = kmalloc (sizeof (struct hotplug_slot_core), GFP_KERNEL); + if (!core) + return -ENOMEM; + + /* make sure we have not already registered this slot */ + spin_lock (&list_lock); + if (get_slot_from_name (slot->name) != NULL) { + spin_unlock (&list_lock); + kfree (core); + return -EFAULT; + } + + slot->core_priv = core; + + list_add (&slot->slot_list, &pci_hotplug_slot_list); + spin_unlock (&list_lock); + + result = fs_add_slot (slot); + dbg ("Added slot %s to the list\n", slot->name); + return result; +} + +/** + * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem + * @slot: pointer to the &struct hotplug_slot to deregister + * + * The @slot must have been registered with the pci hotplug subsystem + * previously with a call to pci_hp_register(). + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_deregister (struct hotplug_slot *slot) +{ + struct hotplug_slot *temp; + + if (slot == NULL) + return -ENODEV; + + /* make sure we have this slot in our list before trying to delete it */ + spin_lock (&list_lock); + temp = get_slot_from_name (slot->name); + if (temp != slot) { + spin_unlock (&list_lock); + return -ENODEV; + } + + list_del (&slot->slot_list); + spin_unlock (&list_lock); + + fs_remove_slot (slot); + kfree(slot->core_priv); + dbg ("Removed slot %s from the list\n", slot->name); + return 0; +} + +/** + * pci_hp_change_slot_info - changes the slot's information structure in the core + * @name: the name of the slot whose info has changed + * @info: pointer to the info copy into the slot's info structure + * + * A slot with @name must have been registered with the pci + * hotplug subsystem previously with a call to pci_hp_register(). + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_change_slot_info (const char *name, struct hotplug_slot_info *info) +{ + struct hotplug_slot *temp; + + if (info == NULL) + return -ENODEV; + + spin_lock (&list_lock); + temp = get_slot_from_name (name); + if (temp == NULL) { + spin_unlock (&list_lock); + return -ENODEV; + } + + memcpy (temp->info, info, sizeof (struct hotplug_slot_info)); + spin_unlock (&list_lock); + return 0; +} + +static int __init pci_hotplug_init (void) +{ + int result; + + spin_lock_init(&mount_lock); + spin_lock_init(&list_lock); + + dbg("registering filesystem.\n"); + result = register_filesystem(&pcihpfs_fs_type); + if (result) { + err("register_filesystem failed with %d\n", result); + goto exit; + } + + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + +exit: + return result; +} + +static void __exit pci_hotplug_exit (void) +{ + unregister_filesystem(&pcihpfs_fs_type); +} + +module_init(pci_hotplug_init); +module_exit(pci_hotplug_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +EXPORT_SYMBOL_GPL(pci_hp_register); +EXPORT_SYMBOL_GPL(pci_hp_deregister); +EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); + diff -u --recursive --new-file v2.4.14/linux/drivers/hotplug/pci_hotplug_util.c linux/drivers/hotplug/pci_hotplug_util.c --- v2.4.14/linux/drivers/hotplug/pci_hotplug_util.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/hotplug/pci_hotplug_util.c Fri Nov 9 14:01:22 2001 @@ -0,0 +1,403 @@ +/* + * PCI HotPlug Utility functions + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include "pci_hotplug.h" + + +#if !defined(CONFIG_HOTPLUG_PCI_MODULE) + #define MY_NAME "pci_hotplug" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: "__FUNCTION__": " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* local variables */ +static int debug; + + +static int build_dev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, struct pci_dev **pci_dev) +{ + struct pci_dev *my_dev; + struct pci_bus *my_bus; + + /* Some validity checks. */ + if ((function > 7) || + (slot > 31) || + (pci_dev == NULL) || + (ops == NULL)) + return -ENODEV; + + my_dev = kmalloc (sizeof (struct pci_dev), GFP_KERNEL); + if (!my_dev) + return -ENOMEM; + my_bus = kmalloc (sizeof (struct pci_bus), GFP_KERNEL); + if (!my_bus) { + kfree (my_dev); + return -ENOMEM; + } + memset(my_dev, 0, sizeof(struct pci_dev)); + memset(my_bus, 0, sizeof(struct pci_bus)); + + my_bus->number = bus; + my_bus->ops = ops; + my_dev->devfn = PCI_DEVFN(slot, function); + my_dev->bus = my_bus; + *pci_dev = my_dev; + return 0; +} + +/** + * pci_read_config_byte_nodev - read a byte from a pci device + * @ops: pointer to a &struct pci_ops that will be used to read from the pci device + * @bus: the bus of the pci device to read from + * @slot: the pci slot number of the pci device to read from + * @function: the function of the pci device to read from + * @where: the location on the pci address space to read from + * @value: pointer to where to place the data read + * + * Like pci_read_config_byte() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_read_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 *value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_read_config_byte (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_read_config_byte(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/** + * pci_read_config_word_nodev - read a word from a pci device + * @ops: pointer to a &struct pci_ops that will be used to read from the pci device + * @bus: the bus of the pci device to read from + * @slot: the pci slot number of the pci device to read from + * @function: the function of the pci device to read from + * @where: the location on the pci address space to read from + * @value: pointer to where to place the data read + * + * Like pci_read_config_word() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_read_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 *value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_read_config_word (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_read_config_word(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/** + * pci_read_config_dword_nodev - read a dword from a pci device + * @ops: pointer to a &struct pci_ops that will be used to read from the pci + * device + * @bus: the bus of the pci device to read from + * @slot: the pci slot number of the pci device to read from + * @function: the function of the pci device to read from + * @where: the location on the pci address space to read from + * @value: pointer to where to place the data read + * + * Like pci_read_config_dword() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_read_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 *value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_read_config_dword (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_read_config_dword(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/** + * pci_write_config_byte_nodev - write a byte to a pci device + * @ops: pointer to a &struct pci_ops that will be used to write to the pci + * device + * @bus: the bus of the pci device to write to + * @slot: the pci slot number of the pci device to write to + * @function: the function of the pci device to write to + * @where: the location on the pci address space to write to + * @value: the value to write to the pci device + * + * Like pci_write_config_byte() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_write_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_write_config_byte (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_write_config_byte(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/** + * pci_write_config_word_nodev - write a word to a pci device + * @ops: pointer to a &struct pci_ops that will be used to write to the pci + * device + * @bus: the bus of the pci device to write to + * @slot: the pci slot number of the pci device to write to + * @function: the function of the pci device to write to + * @where: the location on the pci address space to write to + * @value: the value to write to the pci device + * + * Like pci_write_config_word() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_write_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_write_config_word (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_write_config_word(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/** + * pci_write_config_dword_nodev - write a dword to a pci device + * @ops: pointer to a &struct pci_ops that will be used to write to the pci + * device + * @bus: the bus of the pci device to write to + * @slot: the pci slot number of the pci device to write to + * @function: the function of the pci device to write to + * @where: the location on the pci address space to write to + * @value: the value to write to the pci device + * + * Like pci_write_config_dword() but works for pci devices that do not have a + * pci_dev structure set up yet. + * Returns 0 on success. + */ +int pci_write_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 value) +{ + struct pci_dev *dev = NULL; + int result; + + dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value); + dev = pci_find_slot(bus, PCI_DEVFN(slot, function)); + if (dev) { + dbg("using native pci_dev\n"); + return pci_write_config_dword (dev, where, value); + } + + result = build_dev (ops, bus, slot, function, &dev); + if (result) + return result; + result = pci_write_config_dword(dev, where, value); + kfree (dev->bus); + kfree (dev); + return result; +} + +/* + * This is code that scans the pci buses. + * Every bus and every function is presented to a custom + * function that can act upon it. + */ + +static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent) +{ + struct list_head *ln; + struct pci_dev *dev; + struct pci_dev_wrapped wrapped_dev; + int result = 0; + + dbg("scanning bus %02x\n", wrapped_bus->bus->number); + + if (fn->pre_visit_pci_bus) { + result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent); + if (result) + return result; + } + + ln = wrapped_bus->bus->devices.next; + while (ln != &wrapped_bus->bus->devices) { + dev = pci_dev_b(ln); + ln = ln->next; + + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + wrapped_dev.dev = dev; + + result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus); + if (result) + return result; + } + + if (fn->post_visit_pci_bus) + result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent); + + return result; +} + + +static int pci_visit_bridge (struct pci_visit * fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent) +{ + struct pci_bus *bus = wrapped_dev->dev->subordinate; + struct pci_bus_wrapped wrapped_bus; + int result; + + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + wrapped_bus.bus = bus; + + dbg("scanning bridge %02x, %02x\n", wrapped_dev->dev->devfn >> 3, + wrapped_dev->dev->devfn & 0x7); + + if (fn->visit_pci_dev) { + result = fn->visit_pci_dev(wrapped_dev, wrapped_parent); + if (result) + return result; + } + + result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev); + return result; +} + + +int pci_visit_dev (struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent) +{ + struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL; + int result = 0; + + if (!dev) + return 0; + + if (fn->pre_visit_pci_dev) { + result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent); + if (result) + return result; + } + + switch (dev->class >> 8) { + case PCI_CLASS_BRIDGE_PCI: + result = pci_visit_bridge(fn, wrapped_dev, + wrapped_parent); + if (result) + return result; + break; + default: + dbg("scanning device %02x, %02x\n", + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + if (fn->visit_pci_dev) { + result = fn->visit_pci_dev (wrapped_dev, + wrapped_parent); + if (result) + return result; + } + } + + if (fn->post_visit_pci_dev) + result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent); + + return result; +} + + +EXPORT_SYMBOL(pci_visit_dev); +EXPORT_SYMBOL(pci_read_config_byte_nodev); +EXPORT_SYMBOL(pci_read_config_word_nodev); +EXPORT_SYMBOL(pci_read_config_dword_nodev); +EXPORT_SYMBOL(pci_write_config_byte_nodev); +EXPORT_SYMBOL(pci_write_config_word_nodev); +EXPORT_SYMBOL(pci_write_config_dword_nodev); + diff -u --recursive --new-file v2.4.14/linux/drivers/i2c/i2c-core.c linux/drivers/i2c/i2c-core.c --- v2.4.14/linux/drivers/i2c/i2c-core.c Tue Oct 23 22:48:50 2001 +++ linux/drivers/i2c/i2c-core.c Mon Nov 5 18:15:40 2001 @@ -1284,7 +1284,7 @@ #ifdef CONFIG_I2C_ALGOBIT extern int i2c_algo_bit_init(void); #endif -#ifdef CONFIG_I2C_CONFIG_I2C_PHILIPSPAR +#ifdef CONFIG_I2C_PHILIPSPAR extern int i2c_bitlp_init(void); #endif #ifdef CONFIG_I2C_ELV diff -u --recursive --new-file v2.4.14/linux/drivers/ide/ide-geometry.c linux/drivers/ide/ide-geometry.c --- v2.4.14/linux/drivers/ide/ide-geometry.c Thu Jan 4 12:50:17 2001 +++ linux/drivers/ide/ide-geometry.c Fri Nov 9 14:23:34 2001 @@ -71,8 +71,8 @@ drive->sect = drive->bios_sect = sect; drive->ctl = *(BIOS+8); } else { - printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n", - unit, cyl, head, sect); + printk("hd%c: C/H/S=%d/%d/%d from BIOS ignored\n", + unit+'a', cyl, head, sect); } } diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c --- v2.4.14/linux/drivers/isdn/eicon/eicon_idi.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/isdn/eicon/eicon_idi.c Fri Nov 9 13:41:41 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.41.6.3 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_idi.c,v 1.41.6.4 2001/11/06 20:58:29 kai Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -25,7 +25,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.41.6.3 $"; +char *eicon_idi_revision = "$Revision: 1.41.6.4 $"; eicon_manifbuf *manbuf; @@ -3119,8 +3119,8 @@ return(ret); } - timeout = jiffies + 50; - while (timeout > jiffies) { + timeout = jiffies + HZ / 2; + while (time_before(jiffies, timeout)) { if (chan->e.B2Id) break; SLEEP(10); } @@ -3181,8 +3181,8 @@ eicon_schedule_tx(card); - timeout = jiffies + 50; - while (timeout > jiffies) { + timeout = jiffies + HZ / 2; + while (time_before(jiffies, timeout)) { if (chan->fsm_state) break; SLEEP(10); } diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/eicon/eicon_isa.c linux/drivers/isdn/eicon/eicon_isa.c --- v2.4.14/linux/drivers/isdn/eicon/eicon_isa.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/isdn/eicon/eicon_isa.c Fri Nov 9 13:41:41 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.16.6.1 2001/09/23 22:24:37 kai Exp $ +/* $Id: eicon_isa.c,v 1.16.6.2 2001/11/06 20:58:29 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -20,7 +20,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.16.6.1 $"; +char *eicon_isa_revision = "$Revision: 1.16.6.2 $"; #undef EICON_MCA_DEBUG @@ -231,7 +231,7 @@ boot = &card->shmem->boot; /* Delay 0.2 sec. */ - SLEEP(20); + SLEEP(HZ / 5); /* Start CPU */ writeb(cbuf.boot_opt, &boot->ctrl); @@ -244,10 +244,10 @@ #endif /* CONFIG_MCA */ /* Delay 0.2 sec. */ - SLEEP(20); + SLEEP(HZ / 5); timeout = jiffies + (HZ * 22); - while (timeout > jiffies) { + while (time_before(jiffies, timeout)) { if (readb(&boot->ctrl) == 0) break; SLEEP(10); @@ -362,8 +362,8 @@ while (tmp--) { memcpy_toio(&boot->b, p, 256); writeb(1, &boot->ctrl); - timeout = jiffies + 10; - while (timeout > jiffies) { + timeout = jiffies + HZ / 10; + while (time_before(jiffies, timeout)) { if (readb(&boot->ctrl) == 0) break; SLEEP(2); @@ -386,7 +386,7 @@ /* Start firmware, wait for signature */ writeb(2, &boot->ctrl); timeout = jiffies + (5*HZ); - while (timeout > jiffies) { + while (time_before(jiffies, timeout)) { if (readw(&boot->signature) == 0x4447) break; SLEEP(2); @@ -410,8 +410,8 @@ tmp = readb(&card->shmem->com.ReadyInt); tmp ++; writeb(tmp, &card->shmem->com.ReadyInt); - timeout = jiffies + 20; - while (timeout > jiffies) { + timeout = jiffies + HZ / 5; + while (time_before(jiffies, timeout)) { if (card->irqprobe > 1) break; SLEEP(2); diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/hysdn/boardergo.c linux/drivers/isdn/hysdn/boardergo.c --- v2.4.14/linux/drivers/isdn/hysdn/boardergo.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/isdn/hysdn/boardergo.c Fri Nov 9 13:41:42 2001 @@ -1,4 +1,4 @@ -/* $Id: boardergo.c,v 1.5.6.6 2001/09/23 22:24:54 kai Exp $ +/* $Id: boardergo.c,v 1.5.6.7 2001/11/06 21:58:19 kai Exp $ * * Linux driver for HYSDN cards, specific routines for ergo type boards. * diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/hysdn/hysdn_sched.c linux/drivers/isdn/hysdn/hysdn_sched.c --- v2.4.14/linux/drivers/isdn/hysdn/hysdn_sched.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/isdn/hysdn/hysdn_sched.c Fri Nov 9 13:41:42 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_sched.c,v 1.5.6.3 2001/09/23 22:24:54 kai Exp $ +/* $Id: hysdn_sched.c,v 1.5.6.4 2001/11/06 21:58:19 kai Exp $ * * Linux driver for HYSDN cards * scheduler routines for handling exchange card <-> pc. diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.4.14/linux/drivers/isdn/isdn_common.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/isdn/isdn_common.c Fri Nov 9 13:41:41 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.114.6.15 2001/09/23 22:24:31 kai Exp $ +/* $Id: isdn_common.c,v 1.114.6.16 2001/11/06 20:58:28 kai Exp $ * * Linux ISDN subsystem, common used functions (linklevel). * @@ -44,7 +44,7 @@ isdn_dev *dev; -static char *isdn_revision = "$Revision: 1.114.6.15 $"; +static char *isdn_revision = "$Revision: 1.114.6.16 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -1644,7 +1644,7 @@ if (minor == ISDN_MINOR_STATUS) { infostruct *p; - if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) { + if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) { p->next = (char *) dev->infochain; p->private = (char *) &(filep->private_data); dev->infochain = p; @@ -1996,7 +1996,7 @@ if ((adding) && (d->rcverr)) kfree(d->rcverr); - if (!(d->rcverr = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) { + if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); return -1; } @@ -2004,7 +2004,7 @@ if ((adding) && (d->rcvcount)) kfree(d->rcvcount); - if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) { + if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); if (!adding) kfree(d->rcverr); return -1; @@ -2016,8 +2016,7 @@ skb_queue_purge(&d->rpqueue[j]); kfree(d->rpqueue); } - if (!(d->rpqueue = - (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) { + if (!(d->rpqueue = kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); if (!adding) { kfree(d->rcvcount); @@ -2031,8 +2030,7 @@ if ((adding) && (d->rcv_waitq)) kfree(d->rcv_waitq); - d->rcv_waitq = (wait_queue_head_t *) - kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL); + d->rcv_waitq = kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL); if (!d->rcv_waitq) { printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); if (!adding) { @@ -2157,7 +2155,7 @@ printk(KERN_WARNING "register_isdn: No write routine given.\n"); return 0; } - if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) { + if (!(d = kmalloc(sizeof(driver), GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); return 0; } diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.4.14/linux/drivers/isdn/isdn_net.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/isdn/isdn_net.c Fri Nov 9 13:41:41 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.140.6.10 2001/09/28 08:05:29 kai Exp $ +/* $Id: isdn_net.c,v 1.140.6.11 2001/11/06 20:58:28 kai Exp $ * * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -175,7 +175,7 @@ static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); -char *isdn_net_revision = "$Revision: 1.140.6.10 $"; +char *isdn_net_revision = "$Revision: 1.140.6.11 $"; /* * Code for raw-networking over ISDN @@ -333,7 +333,7 @@ anymore = 0; while (p) { isdn_net_local *l = p->local; - if ((jiffies - last_jiffies) == 0) + if (jiffies == last_jiffies) l->cps = l->transcount; else l->cps = (l->transcount * HZ) / (jiffies - last_jiffies); @@ -352,9 +352,9 @@ { if (l->hupflags & ISDN_MANCHARGE && l->hupflags & ISDN_CHARGEHUP) { - while (jiffies - l->chargetime > l->chargeint) + while (time_after(jiffies, l->chargetime + l->chargeint)) l->chargetime += l->chargeint; - if (jiffies - l->chargetime >= l->chargeint - 2 * HZ) + if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ)) if (l->outgoing || l->hupflags & ISDN_INHUP) isdn_net_hangup(&p->dev); } else if (l->outgoing) { @@ -363,7 +363,7 @@ printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n", l->name, l->hupflags); isdn_net_hangup(&p->dev); - } else if (jiffies - l->chargetime > l->chargeint) { + } else if (time_after(jiffies, l->chargetime + l->chargeint)) { printk(KERN_DEBUG "isdn_net: %s: chtime = %lu, chint = %d\n", l->name, l->chargetime, l->chargeint); @@ -599,7 +599,7 @@ anymore = 1; if(lp->dialtimeout > 0) - if(lp->dialstarted == 0 || jiffies > (lp->dialstarted + lp->dialtimeout + lp->dialwait)) { + if(lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) { lp->dialstarted = jiffies; lp->dialwait_timer = 0; } @@ -659,7 +659,7 @@ printk(KERN_INFO "%s: Open leased line ...\n", lp->name); } else { if(lp->dialtimeout > 0) - if(jiffies > (lp->dialstarted + lp->dialtimeout)) { + if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { restore_flags(flags); lp->dialwait_timer = jiffies + lp->dialwait; lp->dialstarted = 0; @@ -1106,7 +1106,7 @@ lp->sqfull_stamp = jiffies; } else { /* subsequent overload: if slavedelay exceeded, start dialing */ - if ((jiffies - lp->sqfull_stamp) > lp->slavedelay) { + if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) { slp = lp->slave->priv; if (!(slp->flags & ISDN_NET_CONNECTED)) { isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv); @@ -1115,7 +1115,7 @@ } } } else { - if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ)))) { + if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) { lp->sqfull = 0; } /* this is a hack to allow auto-hangup for slaves on moderate loads */ @@ -1225,11 +1225,11 @@ cli(); if(lp->dialwait_timer <= 0) - if(lp->dialstarted > 0 && lp->dialtimeout > 0 && jiffies < lp->dialstarted + lp->dialtimeout + lp->dialwait) + if(lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait; if(lp->dialwait_timer > 0) { - if(jiffies < lp->dialwait_timer) { + if(time_before(jiffies, lp->dialwait_timer)) { isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); dev_kfree_skb(skb); restore_flags(flags); diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v2.4.14/linux/drivers/isdn/isdn_ppp.c Mon Nov 5 15:55:30 2001 +++ linux/drivers/isdn/isdn_ppp.c Fri Nov 9 13:41:41 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.85.6.7 2001/09/23 22:24:31 kai Exp $ +/* $Id: isdn_ppp.c,v 1.85.6.9 2001/11/06 20:58:28 kai Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -69,7 +69,7 @@ static int isdn_ppp_bundle(struct ippp_struct *, int unit); #endif /* CONFIG_ISDN_MPP */ -char *isdn_ppp_revision = "$Revision: 1.85.6.7 $"; +char *isdn_ppp_revision = "$Revision: 1.85.6.9 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; @@ -977,7 +977,7 @@ printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } - if (is->compflags & SC_DECOMP_ON) { + if (mis->compflags & SC_DECOMP_ON) { skb = isdn_ppp_decompress(skb, is, mis, &proto); if (!skb) // decompression error return; @@ -993,6 +993,10 @@ printk(KERN_DEBUG "isdn_ppp: IP\n"); skb->protocol = htons(ETH_P_IP); break; + case PPP_COMP: + case PPP_COMPFRAG: + printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n"); + goto drop_packet; #ifdef CONFIG_ISDN_PPP_VJ case PPP_VJC_UNCOMP: if (is->debug & 0x20) @@ -1216,8 +1220,15 @@ /* * normal (single link) or bundle compression */ - if(ipts->compflags & SC_COMP_ON) - skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); + if(ipts->compflags & SC_COMP_ON) { + /* We send compressed only if both down- und upstream + compression is negotiated, that means, CCP is up */ + if(ipts->compflags & SC_DECOMP_ON) { + skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); + } else { + printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n"); + } + } if (ipt->debug & 0x24) printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); @@ -2082,8 +2093,6 @@ } if(rs->ta && rs->state == CCPResetSentReq) { /* We are correct here */ - printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", - rs->id); if(!rs->expra) { /* Hmm, there is no Ack really expected. We can clean up the state now, it will be reallocated if the @@ -2092,6 +2101,8 @@ isdn_ppp_ccp_reset_free_state(rs->is, rs->id); return; } + printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", + rs->id); /* Push it again */ isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id, rs->data, rs->dlen); @@ -2318,7 +2329,6 @@ if (len <= 0) { switch(len) { case DECOMP_ERROR: - ri->pppcfg |= SC_DC_ERROR; printk(KERN_INFO "ippp: decomp wants reset %s params\n", rsparm.valid ? "with" : "without"); @@ -2482,7 +2492,6 @@ len, NULL); /* TODO: This is not easy to decide here */ mis->compflags &= ~SC_DECOMP_DISCARD; - mis->pppcfg &= ~SC_DC_ERROR; } else { isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]); @@ -2495,7 +2504,6 @@ len, NULL); /* TODO: neither here */ is->compflags &= ~SC_LINK_DECOMP_DISCARD; - is->pppcfg &= ~SC_DC_ERROR; } break; @@ -2570,6 +2578,15 @@ * that's too big of a change now. --kai */ +/* Actually, we might turn this into an advantage: deal with the RFC in + * the old tradition of beeing generous on what we accept, but beeing + * strict on what we send. Thus we should just + * - accept compressed frames as soon as decompression is negotiated + * - send compressed frames only when decomp *and* comp are negotiated + * - drop rx compressed frames if we cannot decomp (instead of pushing them + * up to ipppd) + * and I tried to modify this file according to that. --abp + */ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) { diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.4.14/linux/drivers/isdn/isdn_tty.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/isdn/isdn_tty.c Fri Nov 9 13:41:41 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.94.6.8 2001/09/23 22:24:32 kai Exp $ +/* $Id: isdn_tty.c,v 1.94.6.9 2001/11/06 20:58:29 kai Exp $ * * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -53,7 +53,7 @@ static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.94.6.8 $"; +char *isdn_tty_revision = "$Revision: 1.94.6.9 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -2596,11 +2596,11 @@ if (*(p++) == plus) { if ((*pluscount)++) { /* Time since last '+' > 0.5 sec. ? */ - if ((jiffies - *lastplus) > PLUSWAIT1) + if (time_after(jiffies, *lastplus + PLUSWAIT1)) *pluscount = 1; } else { /* Time since last non-'+' < 1.5 sec. ? */ - if ((jiffies - *lastplus) < PLUSWAIT2) + if (time_before(jiffies, *lastplus + PLUSWAIT2)) *pluscount = 0; } if ((*pluscount == 3) && (count == 1)) @@ -3974,7 +3974,7 @@ if (info->online) { ton = 1; if ((info->emu.pluscount == 3) && - ((jiffies - info->emu.lastplus) > PLUSWAIT2)) { + time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) { info->emu.pluscount = 0; info->online = 0; isdn_tty_modem_result(RESULT_OK, info); diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/tpam/tpam.h linux/drivers/isdn/tpam/tpam.h --- v2.4.14/linux/drivers/isdn/tpam/tpam.h Tue Oct 9 17:06:51 2001 +++ linux/drivers/isdn/tpam/tpam.h Fri Nov 9 13:41:41 2001 @@ -1,4 +1,4 @@ -/* $Id: tpam.h,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $ +/* $Id: tpam.h,v 1.1.2.3 2001/11/06 20:58:30 kai Exp $ * * Turbo PAM ISDN driver for Linux. (Kernel Driver) * @@ -213,8 +213,8 @@ extern void tpam_recv_U3ReadyToReceiveInd(tpam_card *, struct sk_buff *); /* Function prototypes from tpam_hdlc.c */ -extern u32 hdlc_encode(u8 *, u8 *, u32 *, u32); -extern u32 hdlc_decode(u8 *, u8 *, u32); +extern u32 tpam_hdlc_encode(u8 *, u8 *, u32 *, u32); +extern u32 tpam_hdlc_decode(u8 *, u8 *, u32); /* Function prototypes from tpam_crcpc.c */ extern void init_CRC(void); diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/tpam/tpam_commands.c linux/drivers/isdn/tpam/tpam_commands.c --- v2.4.14/linux/drivers/isdn/tpam/tpam_commands.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/isdn/tpam/tpam_commands.c Fri Nov 9 13:41:41 2001 @@ -1,4 +1,4 @@ -/* $Id: tpam_commands.c,v 1.1.2.3 2001/09/23 22:25:03 kai Exp $ +/* $Id: tpam_commands.c,v 1.1.2.4 2001/11/06 20:58:30 kai Exp $ * * Turbo PAM ISDN driver for Linux. (Kernel Driver - ISDN commands) * @@ -206,7 +206,7 @@ /* wait for the board signature */ timeout = jiffies + SIGNATURE_TIMEOUT; - while (timeout > jiffies) { + while (time_before(jiffies, timeout)) { spin_lock_irq(&card->lock); signature = copy_from_pam_dword(card, (void *)TPAM_MAGICNUMBER_REGISTER); @@ -241,7 +241,7 @@ /* wait for NCO creation confirmation */ timeout = jiffies + NCOCREATE_TIMEOUT; - while (timeout > jiffies) { + while (time_before(jiffies, timeout)) { if (card->channels_tested == TPAM_NBCHANNEL) break; set_current_state(TASK_UNINTERRUPTIBLE); @@ -572,7 +572,7 @@ return -ENOMEM; } hdlc_no_accm_encode(skb->data, skb->len, tempdata, &templen); - finallen = hdlc_encode(tempdata, finaldata, + finallen = tpam_hdlc_encode(tempdata, finaldata, &card->channels[channel].hdlcshift, templen); free_page((u32)tempdata); @@ -897,7 +897,7 @@ "get_free_page failed\n"); return; } - templen = hdlc_decode(data, tempdata, len); + templen = tpam_hdlc_decode(data, tempdata, len); templen = hdlc_no_accm_decode(tempdata, templen); if (!(result = alloc_skb(templen, GFP_ATOMIC))) { printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): " @@ -1019,6 +1019,6 @@ init_timer(timer); timer->function = tpam_statcallb_run; timer->data = (unsigned long)ds; - timer->expires = jiffies + 0.1 * HZ; /* 0.1 second */ + timer->expires = jiffies + HZ / 10; /* 0.1 second */ add_timer(timer); } diff -u --recursive --new-file v2.4.14/linux/drivers/isdn/tpam/tpam_hdlc.c linux/drivers/isdn/tpam/tpam_hdlc.c --- v2.4.14/linux/drivers/isdn/tpam/tpam_hdlc.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/isdn/tpam/tpam_hdlc.c Fri Nov 9 13:41:41 2001 @@ -1,4 +1,4 @@ -/* $Id: tpam_hdlc.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $ +/* $Id: tpam_hdlc.c,v 1.1.2.3 2001/11/06 20:58:30 kai Exp $ * * Turbo PAM ISDN driver for Linux. (Kernel Driver - HDLC encoding) * @@ -35,11 +35,11 @@ destuff5 : array necessary for the bit destuffing algorithm destuffs[] : array conaining the previous 6 arrays - hdlc_encode : bit stuffing of a byte array, with the addition of a start and - end flag, using the bit shift given in parameter (which is - updated at the end of encoding). - hdlc_decode : bit de-stuffing of a byte array with detection of possible - ABORTs. + tpam_hdlc_encode : bit stuffing of a byte array, with the addition + of a start and end flag, using the bit shift given in + parameter (which is updated at the end of encoding). + tpam_hdlc_decode : bit de-stuffing of a byte array with detection of + possible ABORTs. Revision History: @@ -553,7 +553,7 @@ /*- AuverTech Telecom -------------------------------------------------------+ | | - | @Function : hdlc_encode | + | @Function : tpam_hdlc_encode | | @Author : Cyrille Boudon | | | +---------------------------------------------------------------------------+ @@ -576,8 +576,8 @@ | beginning (for the first frame), the shift must be initialized to 0. | | | +---------------------------------------------------------------------------*/ -DWORD hdlc_encode(BYTE *pbyBuffIn, BYTE *pbyBuffOut, - DWORD *pdwInitialShift, DWORD dwLength) +DWORD tpam_hdlc_encode(BYTE *pbyBuffIn, BYTE *pbyBuffOut, + DWORD *pdwInitialShift, DWORD dwLength) { DWORD dwShifter; // temporary variable DWORD dwShiftNb; // shift due to the insertion of '0' @@ -754,7 +754,7 @@ /*- AuverTech Telecom -------------------------------------------------------+ | | - | @Function : hdlc_decode | + | @Function : tpam_hdlc_decode | | @Author : Cyrille Boudon | | | +---------------------------------------------------------------------------+ @@ -773,7 +773,7 @@ | If an abort is encountered, the returned count is '0'. | | | +---------------------------------------------------------------------------*/ -DWORD hdlc_decode(BYTE * pbyBuffIn, BYTE * pbyBuffOut, DWORD dwLength) +DWORD tpam_hdlc_decode(BYTE * pbyBuffIn, BYTE * pbyBuffOut, DWORD dwLength) { BYTE byCharIn; // byte being decoded BYTE byCarry; // current carry diff -u --recursive --new-file v2.4.14/linux/drivers/media/radio/Config.in linux/drivers/media/radio/Config.in --- v2.4.14/linux/drivers/media/radio/Config.in Mon Aug 27 12:41:42 2001 +++ linux/drivers/media/radio/Config.in Fri Nov 9 14:01:22 2001 @@ -21,7 +21,7 @@ if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c fi -dep_tristate ' GemTek PCI Radio Card support' CONFIG_RADIO_GEMTEK_PCI $CONFIG_VIDEO_DEV +dep_tristate ' GemTek PCI Radio Card support' CONFIG_RADIO_GEMTEK_PCI $CONFIG_VIDEO_DEV $CONFIG_PCI dep_tristate ' Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV dep_tristate ' Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV dep_tristate ' miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER diff -u --recursive --new-file v2.4.14/linux/drivers/media/video/Config.in linux/drivers/media/video/Config.in --- v2.4.14/linux/drivers/media/video/Config.in Wed Jul 25 17:10:20 2001 +++ linux/drivers/media/video/Config.in Fri Nov 9 14:01:22 2001 @@ -46,6 +46,9 @@ dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI fi dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C +dep_tristate ' Iomega Buz support' CONFIG_VIDEO_ZORAN_BUZ $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C +dep_tristate ' Miro DC10(+) support' CONFIG_VIDEO_ZORAN_DC10 $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C +dep_tristate ' Linux Media Labs LML33 support' CONFIG_VIDEO_ZORAN_LML33 $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Sony Vaio Picturebook Motion Eye Video For Linux' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI diff -u --recursive --new-file v2.4.14/linux/drivers/media/video/Makefile linux/drivers/media/video/Makefile --- v2.4.14/linux/drivers/media/video/Makefile Wed Jul 25 17:10:20 2001 +++ linux/drivers/media/video/Makefile Fri Nov 9 14:01:22 2001 @@ -44,7 +44,10 @@ obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o obj-$(CONFIG_VIDEO_W9966) += w9966.o -obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o saa7110.o saa7111.o saa7185.o adv7175.o bt819.o bt856.o +obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o +obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o +obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o +obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o obj-$(CONFIG_VIDEO_PMS) += pms.o obj-$(CONFIG_VIDEO_PLANB) += planb.o diff -u --recursive --new-file v2.4.14/linux/drivers/media/video/saa7110.c linux/drivers/media/video/saa7110.c --- v2.4.14/linux/drivers/media/video/saa7110.c Tue Oct 23 22:48:51 2001 +++ linux/drivers/media/video/saa7110.c Fri Nov 9 14:01:22 2001 @@ -83,6 +83,7 @@ while (len-- > 0) { if (i2c_sendbyte(decoder->bus,*data,0)) { i2c_stop(decoder->bus); + UNLOCK_I2C_BUS(decoder->bus); return -EAGAIN; } decoder->reg[subaddr++] = *data++; diff -u --recursive --new-file v2.4.14/linux/drivers/media/video/zr36067.c linux/drivers/media/video/zr36067.c --- v2.4.14/linux/drivers/media/video/zr36067.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/media/video/zr36067.c Fri Nov 9 14:01:22 2001 @@ -245,6 +245,13 @@ MODULE_PARM(lml33dpath, "i"); MODULE_PARM(video_nr, "i"); +static struct pci_device_id zr36067_pci_tbl[] = { + { PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); + /* Anybody who uses more than four? */ #define BUZ_MAX 4 diff -u --recursive --new-file v2.4.14/linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c --- v2.4.14/linux/drivers/media/video/zr36120.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/media/video/zr36120.c Fri Nov 9 14:01:22 2001 @@ -60,6 +60,13 @@ static int video_nr = -1; static int vbi_nr = -1; +static struct pci_device_id zr36120_pci_tbl[] = { + { PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, zr36120_pci_tbl); + MODULE_AUTHOR("Pauline Middelink <middelin@polyware.nl>"); MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber"); MODULE_LICENSE("GPL"); diff -u --recursive --new-file v2.4.14/linux/drivers/mtd/chips/jedec.c linux/drivers/mtd/chips/jedec.c --- v2.4.14/linux/drivers/mtd/chips/jedec.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/mtd/chips/jedec.c Fri Nov 9 14:29:40 2001 @@ -11,7 +11,7 @@ * not going to guess how to send commands to them, plus I expect they will * all speak CFI.. * - * $Id: jedec.c,v 1.11 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: jedec.c,v 1.12 2001/11/06 14:37:35 dwmw2 Exp $ */ #include <linux/mtd/jedec.h> @@ -42,6 +42,7 @@ {0xC2AD,"Macronix MX29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH}, {}}; +static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); static void jedec_sync(struct mtd_info *mtd) {}; static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); @@ -249,7 +250,7 @@ /* Take an array of JEDEC numbers that represent interleved flash chips and process them. Check to make sure they are good JEDEC numbers, look them up and then add them to the chip list */ -int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, +static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, unsigned long base,struct jedec_private *priv) { unsigned I,J; @@ -336,7 +337,7 @@ } /* Lookup the chip information from the JEDEC ID table. */ -const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id) +static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id) { __u16 Id = (mfr << 8) | id; unsigned long I = 0; @@ -873,19 +874,19 @@ } } -int __init jedec_probe_init(void) +int __init jedec_init(void) { register_mtd_chip_driver(&jedec_chipdrv); return 0; } -static void __exit jedec_probe_exit(void) +static void __exit jedec_exit(void) { unregister_mtd_chip_driver(&jedec_chipdrv); } -module_init(jedec_probe_init); -module_exit(jedec_probe_exit); +module_init(jedec_init); +module_exit(jedec_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com> et al."); diff -u --recursive --new-file v2.4.14/linux/drivers/mtd/redboot.c linux/drivers/mtd/redboot.c --- v2.4.14/linux/drivers/mtd/redboot.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/mtd/redboot.c Fri Nov 9 14:01:22 2001 @@ -1,5 +1,5 @@ /* - * $Id: redboot.c,v 1.5 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: redboot.c,v 1.6 2001/10/25 09:16:06 dwmw2 Exp $ * * Parse RedBoot-style Flash Image System (FIS) tables and * produce a Linux partition array to match. @@ -62,7 +62,15 @@ goto out; } - if (memcmp(buf, "RedBoot", 8)) { + /* RedBoot image could appear in any of the first three slots */ + for (i = 0; i < 3; i++) { + if (!memcmp(buf[i].name, "RedBoot", 8)) + break; + } + if (i == 3) { + /* Didn't find it */ + printk(KERN_NOTICE "No RedBoot partition table detected in %s\n", + master->name); ret = 0; goto out; } diff -u --recursive --new-file v2.4.14/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.4.14/linux/drivers/net/3c59x.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/net/3c59x.c Fri Nov 9 13:41:42 2001 @@ -868,7 +868,7 @@ static int vortex_suspend (struct pci_dev *pdev, u32 state) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); if (dev && dev->priv) { if (netif_running(dev)) { @@ -881,7 +881,7 @@ static int vortex_resume (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); if (dev && dev->priv) { if (netif_running(dev)) { diff -u --recursive --new-file v2.4.14/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.4.14/linux/drivers/net/8139too.c Tue Oct 23 22:48:51 2001 +++ linux/drivers/net/8139too.c Fri Nov 9 13:45:35 2001 @@ -80,6 +80,8 @@ Kalle Olavi Niemitalo - Wake-on-LAN ioctls + Robert Kuebel - Save kernel thread from dying on any signal. + Submitting bug reports: "rtl8139-diag -mmmaaavvveefN" output @@ -87,64 +89,16 @@ See 8139too.txt for more details. ------------------------------------------------------------------------------ - - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the RealTek RTL8139 series, the RealTek -Fast Ethernet controllers for PCI and CardBus. This chip is used on many -low-end boards, sometimes with its markings changed. - - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS will assign the -PCI INTA signal to a (preferably otherwise unused) system IRQ line. - -III. Driver operation - -IIIa. Rx Ring buffers - -The receive unit uses a single linear ring buffer rather than the more -common (and more efficient) descriptor-based architecture. Incoming frames -are sequentially stored into the Rx region, and the host copies them into -skbuffs. - -Comment: While it is theoretically possible to process many frames in place, -any delay in Rx processing would cause us to drop frames. More importantly, -the Linux protocol stack is not designed to operate in this manner. - -IIIb. Tx operation - -The RTL8139 uses a fixed set of four Tx descriptors in register space. -In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux -aligns the IP header on word boundaries, and 14 byte ethernet header means -that almost all frames will need to be copied to an alignment buffer. - -IVb. References - -http://www.realtek.com.tw/cn/cn.html -http://www.scyld.com/expert/NWay.html - -IVc. Errata - -1) The RTL-8139 has a serious problem with motherboards which do -posted MMIO writes to PCI space. This driver works around the -problem by having an MMIO register write be immediately followed by -an MMIO register read. - */ #define DRV_NAME "8139too" -#define DRV_VERSION "0.9.20" +#define DRV_VERSION "0.9.22" #include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/compiler.h> #include <linux/pci.h> #include <linux/init.h> #include <linux/ioport.h> @@ -207,11 +161,10 @@ /* Size of the in-memory receive ring. */ #define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) -#define RX_BUF_PAD 16 +#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) +#define RX_BUF_PAD 16 #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ -#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) -#define RX_EARLY_THRESH 14 +#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 @@ -231,7 +184,7 @@ #define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */ #define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */ #define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ - +#define TX_RETRY 8 /* 0-15. retries = 16 + (TX_RETRY * 16) */ /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -315,8 +268,6 @@ TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ RxBuf = 0x30, - RxEarlyCnt = 0x34, - RxEarlyStatus = 0x36, ChipCmd = 0x37, RxBufPtr = 0x38, RxBufAddr = 0x3A, @@ -415,7 +366,8 @@ TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ TxClearAbt = (1 << 0), /* Clear abort (WO) */ - TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */ + TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */ TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ }; @@ -463,10 +415,6 @@ }; enum RxConfigBits { - /* Early Rx threshold, none or X/16 */ - RxCfgEarlyRxNone = 0, - RxCfgEarlyRxShift = 24, - /* rx fifo threshold */ RxCfgFIFOShift = 13, RxCfgFIFONone = (7 << RxCfgFIFOShift), @@ -513,12 +461,6 @@ {0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83} }; -struct ring_info { - struct sk_buff *skb; - dma_addr_t mapping; -}; - - typedef enum { CH_8139 = 0, CH_8139_K, @@ -595,8 +537,6 @@ unsigned int tx_flag; unsigned long cur_tx; unsigned long dirty_tx; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct ring_info tx_info[NUM_TX_DESC]; unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ unsigned char *tx_bufs; /* Tx bounce buffer region. */ dma_addr_t rx_ring_dma; @@ -616,6 +556,7 @@ struct completion thr_exited; u32 rx_config; struct rtl_extra_stats xstats; + int time_to_die; }; MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>"); @@ -714,10 +655,12 @@ TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8139_rx_config = - (RX_EARLY_THRESH << RxCfgEarlyRxShift) | RxCfgRcv32K | RxNoWrap | - (RX_FIFO_THRESH << RxCfgFIFOShift) | - (RX_DMA_BURST << RxCfgDMAShift); + RxCfgRcv32K | RxNoWrap | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); +static const unsigned int rtl8139_tx_config = + (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift); static void __rtl8139_cleanup_dev (struct net_device *dev) { @@ -782,8 +725,6 @@ unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; u32 tmp; - DPRINTK ("ENTER\n"); - assert (pdev != NULL); *dev_out = NULL; @@ -792,7 +733,6 @@ dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pdev->slot_name); - DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } SET_MODULE_OWNER(dev); @@ -926,13 +866,11 @@ rtl8139_chip_reset (ioaddr); - DPRINTK ("EXIT, returning 0\n"); *dev_out = dev; return 0; err_out: __rtl8139_cleanup_dev (dev); - DPRINTK ("EXIT, returning %d\n", rc); return rc; } @@ -947,8 +885,6 @@ static int board_idx = -1; u8 pci_rev; - DPRINTK ("ENTER\n"); - assert (pdev != NULL); assert (ent != NULL); @@ -975,10 +911,8 @@ } i = rtl8139_init_board (pdev, &dev); - if (i < 0) { - DPRINTK ("EXIT, returning %d\n", i); + if (i < 0) return i; - } tp = dev->priv; ioaddr = tp->mmio_addr; @@ -1091,12 +1025,10 @@ if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ - DPRINTK ("EXIT - returning 0\n"); return 0; err_out: __rtl8139_cleanup_dev (dev); - DPRINTK ("EXIT - returning %d\n", i); return i; } @@ -1106,8 +1038,6 @@ struct net_device *dev = pci_get_drvdata (pdev); struct rtl8139_private *np; - DPRINTK ("ENTER\n"); - assert (dev != NULL); np = dev->priv; assert (np != NULL); @@ -1115,8 +1045,6 @@ unregister_netdev (dev); __rtl8139_cleanup_dev (dev); - - DPRINTK ("EXIT\n"); } @@ -1149,8 +1077,6 @@ void *ee_addr = ioaddr + Cfg9346; int read_cmd = location | (EE_READ_CMD << addr_len); - DPRINTK ("ENTER\n"); - writeb (EE_ENB & ~EE_CS, ee_addr); writeb (EE_ENB, ee_addr); eeprom_delay (); @@ -1180,7 +1106,6 @@ writeb (~EE_CS, ee_addr); eeprom_delay (); - DPRINTK ("EXIT - returning %d\n", retval); return retval; } @@ -1218,16 +1143,12 @@ { int i; - DPRINTK ("ENTER\n"); - for (i = 32; i >= 0; i--) { writeb (MDIO_WRITE1, mdio_addr); mdio_delay (mdio_addr); writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); mdio_delay (mdio_addr); } - - DPRINTK ("EXIT\n"); } #endif @@ -1241,10 +1162,7 @@ int i; #endif - DPRINTK ("ENTER\n"); - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - DPRINTK ("EXIT after directly using 8139 internal regs\n"); return location < 8 && mii_2_8139_map[location] ? readw (tp->mmio_addr + mii_2_8139_map[location]) : 0; } @@ -1271,7 +1189,6 @@ } #endif - DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff); return (retval >> 1) & 0xffff; } @@ -1286,8 +1203,6 @@ int i; #endif - DPRINTK ("ENTER\n"); - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ void *ioaddr = tp->mmio_addr; if (location == 0) { @@ -1330,13 +1245,9 @@ void *ioaddr = tp->mmio_addr; #endif - DPRINTK ("ENTER\n"); - retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev); - if (retval) { - DPRINTK ("EXIT, returning %d\n", retval); + if (retval) return retval; - } tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN, &tp->tx_bufs_dma); @@ -1352,7 +1263,6 @@ pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, tp->rx_ring, tp->rx_ring_dma); - DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } @@ -1375,7 +1285,6 @@ printk (KERN_WARNING "%s: unable to start kernel thread\n", dev->name); - DPRINTK ("EXIT, returning 0\n"); return 0; } @@ -1384,8 +1293,6 @@ { struct rtl8139_private *tp = dev->priv; - DPRINTK("ENTER\n"); - if (tp->phys[0] >= 0) { u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); if (mii_reg5 == 0xffff) @@ -1410,8 +1317,6 @@ u32 i; u8 tmp; - DPRINTK ("ENTER\n"); - /* Bring old chips out of low-power mode. */ if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'R'); @@ -1431,7 +1336,7 @@ RTL_W32 (RxConfig, tp->rx_config); /* Check this value: the documentation for IFG contradicts ifself. */ - RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); + RTL_W32 (TxConfig, rtl8139_tx_config); tp->cur_rx = 0; @@ -1472,8 +1377,6 @@ RTL_W16 (IntrMask, rtl8139_intr_mask); netif_start_queue (dev); - - DPRINTK ("EXIT\n"); } @@ -1483,19 +1386,12 @@ struct rtl8139_private *tp = dev->priv; int i; - DPRINTK ("ENTER\n"); - tp->cur_rx = 0; tp->cur_tx = 0; tp->dirty_tx = 0; - for (i = 0; i < NUM_TX_DESC; i++) { - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; + for (i = 0; i < NUM_TX_DESC; i++) tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE]; - } - - DPRINTK ("EXIT\n"); } @@ -1512,8 +1408,6 @@ int linkcase; void *ioaddr = tp->mmio_addr; - DPRINTK ("ENTER\n"); - /* This is a complicated state machine to configure the "twister" for impedance/echos based on the cable length. All of this is magic and undocumented. @@ -1591,8 +1485,6 @@ /* do nothing */ break; } - - DPRINTK ("EXIT\n"); } #endif /* CONFIG_8139TOO_TUNE_TWISTER */ @@ -1636,11 +1528,8 @@ DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", dev->name, RTL_R16 (NWayLPAR)); - DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x" - " RxStatus %4.4lx.\n", dev->name, - RTL_R16 (IntrMask), - RTL_R16 (IntrStatus), - RTL_R32 (RxEarlyStatus)); + DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x\n", + dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus)); DPRINTK ("%s: Chip config %2.2x %2.2x.\n", dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); @@ -1669,7 +1558,13 @@ timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout); } while (!signal_pending (current) && (timeout > 0)); - if (signal_pending (current)) + if (signal_pending (current)) { + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + } + + if (tp->time_to_die) break; rtnl_lock (); @@ -1683,25 +1578,10 @@ static void rtl8139_tx_clear (struct rtl8139_private *tp) { - int i; - tp->cur_tx = 0; tp->dirty_tx = 0; - /* Dump the unsent Tx packets. */ - for (i = 0; i < NUM_TX_DESC; i++) { - struct ring_info *rp = &tp->tx_info[i]; - if (rp->mapping != 0) { - pci_unmap_single (tp->pci_dev, rp->mapping, - rp->skb->len, PCI_DMA_TODEVICE); - rp->mapping = 0; - } - if (rp->skb) { - dev_kfree_skb (rp->skb); - rp->skb = NULL; - tp->stats.tx_dropped++; - } - } + /* XXX account for unsent Tx packets in tp->stats.tx_dropped */ } @@ -1755,42 +1635,29 @@ struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned int entry; - u32 dma_addr; - - mb(); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; - assert (tp->tx_info[entry].skb == NULL); - assert (tp->tx_info[entry].mapping == 0); - - tp->tx_info[entry].skb = skb; - if ( !((unsigned long)skb->data & 3) && skb_shinfo(skb)->nr_frags == 0 && - skb->ip_summed != CHECKSUM_HW) { - tp->xstats.tx_buf_mapped++; - tp->tx_info[entry].mapping = - pci_map_single (tp->pci_dev, skb->data, skb->len, - PCI_DMA_TODEVICE); - dma_addr = tp->tx_info[entry].mapping; - } else if (skb->len < TX_BUF_SIZE) { + if (likely(skb->len < TX_BUF_SIZE)) { skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); - dma_addr = tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs); + dev_kfree_skb(skb); } else { dev_kfree_skb(skb); - tp->tx_info[entry].skb = NULL; + tp->stats.tx_dropped++; return 0; } + /* Note: the chip doesn't have auto-pad! */ spin_lock_irq(&tp->lock); - RTL_W32_F (TxAddr0 + (entry * 4), dma_addr); RTL_W32_F (TxStatus0 + (entry * sizeof (u32)), tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; tp->cur_tx++; - mb(); + wmb(); + if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); spin_unlock_irq(&tp->lock); @@ -1831,7 +1698,9 @@ tp->stats.tx_errors++; if (txstatus & TxAborted) { tp->stats.tx_aborted_errors++; - RTL_W32_F (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift)); + RTL_W32 (TxConfig, TxClearAbt); + RTL_W16 (IntrStatus, TxErr); + wmb(); } if (txstatus & TxCarrierLost) tp->stats.tx_carrier_errors++; @@ -1853,17 +1722,6 @@ tp->stats.tx_packets++; } - /* Free the original skb. */ - if (tp->tx_info[entry].mapping != 0) { - pci_unmap_single(tp->pci_dev, - tp->tx_info[entry].mapping, - tp->tx_info[entry].skb->len, - PCI_DMA_TODEVICE); - tp->tx_info[entry].mapping = 0; - } - dev_kfree_skb_irq (tp->tx_info[entry].skb); - tp->tx_info[entry].skb = NULL; - dirty_tx++; tx_left--; } @@ -2000,7 +1858,11 @@ } #endif - if (rx_size == 0xfff0) { /* Early Rx in progress */ + /* Packet copy from FIFO still in progress. + * Theoretically, this should never happen + * since EarlyRx is disabled. + */ + if (rx_size == 0xfff0) { tp->xstats.early_rx++; break; } @@ -2059,10 +1921,6 @@ RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); tp->cur_rx = cur_rx; - - if ((RTL_R8 (ChipCmd) & RxBufEmpty) && - (RTL_R16 (IntrStatus) & RxAckBits)) - RTL_W16_F (IntrStatus, RxAckBits); } @@ -2104,13 +1962,14 @@ (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) tp->stats.rx_errors++; - if (status & (PCSTimeout)) + if (status & PCSTimeout) tp->stats.rx_length_errors++; if (status & (RxUnderrun | RxFIFOOver)) tp->stats.rx_fifo_errors++; if (status & PCIErr) { u16 pci_cmd_status; pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); + pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status); printk (KERN_ERR "%s: PCI Bus error %4.4x.\n", dev->name, pci_cmd_status); @@ -2139,6 +1998,11 @@ if (status == 0xFFFF) break; + if ((status & + (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | + RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) + break; + /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ if (status & RxUnderrun) @@ -2147,28 +2011,26 @@ /* The chip takes special action when we clear RxAckBits, * so we clear them later in rtl8139_rx_interrupt */ - ackstat = status & ~RxAckBits; + ackstat = status & ~(RxAckBits | TxErr); RTL_W16 (IntrStatus, ackstat); DPRINTK ("%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.\n", dev->name, ackstat, status, RTL_R16 (IntrStatus)); - if ((status & - (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0) - break; - if (netif_running (dev) && (status & RxAckBits)) rtl8139_rx_interrupt (dev, tp, ioaddr); /* Check uncommon events with one test. */ if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | - RxFIFOOver | TxErr | RxErr)) + RxFIFOOver | RxErr)) rtl8139_weird_interrupt (dev, tp, ioaddr, status, link_changed); - if (netif_running (dev) && (status & (TxOK | TxErr))) + if (netif_running (dev) && (status & (TxOK | TxErr))) { rtl8139_tx_interrupt (dev, tp, ioaddr); + if (status & TxErr) + RTL_W16 (IntrStatus, TxErr); + } boguscnt--; } while (boguscnt > 0); @@ -2195,11 +2057,11 @@ int ret = 0; unsigned long flags; - DPRINTK ("ENTER\n"); - netif_stop_queue (dev); if (tp->thr_pid >= 0) { + tp->time_to_die = 1; + wmb(); ret = kill_proc (tp->thr_pid, SIGTERM, 1); if (ret) { printk (KERN_ERR "%s: unable to signal thread\n", dev->name); @@ -2243,7 +2105,6 @@ if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ - DPRINTK ("EXIT\n"); return 0; } @@ -2439,8 +2300,6 @@ int rc = 0; int phy = tp->phys[0] & 0x3f; - DPRINTK ("ENTER\n"); - if (cmd != SIOCETHTOOL) { /* With SIOCETHTOOL, this would corrupt the pointer. */ data->phy_id &= 0x1f; @@ -2488,7 +2347,6 @@ break; } - DPRINTK ("EXIT, returning %d\n", rc); return rc; } @@ -2499,8 +2357,6 @@ void *ioaddr = tp->mmio_addr; unsigned long flags; - DPRINTK ("ENTER\n"); - if (netif_running(dev)) { spin_lock_irqsave (&tp->lock, flags); tp->stats.rx_missed_errors += RTL_R32 (RxMissed); @@ -2508,7 +2364,6 @@ spin_unlock_irqrestore (&tp->lock, flags); } - DPRINTK ("EXIT\n"); return &tp->stats; } @@ -2520,8 +2375,6 @@ { int crc = -1; - DPRINTK ("ENTER\n"); - while (--length >= 0) { unsigned char current_octet = *data++; int bit; @@ -2530,7 +2383,6 @@ ethernet_polynomial : 0); } - DPRINTK ("EXIT, returning %u\n", crc); return crc; } @@ -2543,8 +2395,6 @@ int i, rx_mode; u32 tmp; - DPRINTK ("ENTER\n"); - DPRINTK ("%s: rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n", dev->name, dev->flags, RTL_R32 (RxConfig)); @@ -2583,9 +2433,6 @@ } RTL_W32_F (MAR0 + 0, mc_filter[0]); RTL_W32_F (MAR0 + 4, mc_filter[1]); - - - DPRINTK ("EXIT\n"); } static void rtl8139_set_rx_mode (struct net_device *dev) diff -u --recursive --new-file v2.4.14/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.4.14/linux/drivers/net/Config.in Tue Oct 23 22:48:51 2001 +++ linux/drivers/net/Config.in Fri Nov 9 14:01:22 2001 @@ -274,6 +274,9 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP fi + if [ ! "$CONFIG_ATM" = "n" ]; then + dep_tristate ' PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP + fi fi tristate 'SLIP (serial line) support' CONFIG_SLIP diff -u --recursive --new-file v2.4.14/linux/drivers/net/appletalk/Config.in linux/drivers/net/appletalk/Config.in --- v2.4.14/linux/drivers/net/appletalk/Config.in Sat Mar 11 11:27:14 2000 +++ linux/drivers/net/appletalk/Config.in Fri Nov 9 14:01:22 2001 @@ -6,14 +6,14 @@ mainmenu_option next_comment comment 'Appletalk devices' bool 'Appletalk interfaces support' CONFIG_APPLETALK - if [ "$CONFIG_APPLETALK" != "n" ]; then - dep_tristate ' Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_APPLETALK - dep_tristate ' COPS LocalTalk PC support' CONFIG_COPS $CONFIG_APPLETALK + if [ "$CONFIG_ATALK" != "n" ]; then + dep_tristate ' Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_DEV_APPLETALK + dep_tristate ' COPS LocalTalk PC support' CONFIG_COPS $CONFIG_DEV_APPLETALK if [ "$CONFIG_COPS" != "n" ]; then bool ' Dayna firmware support' CONFIG_COPS_DAYNA bool ' Tangent firmware support' CONFIG_COPS_TANGENT fi - dep_tristate ' Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_APPLETALK + dep_tristate ' Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_DEV_APPLETALK if [ "$CONFIG_IPDDP" != "n" ]; then bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP diff -u --recursive --new-file v2.4.14/linux/drivers/net/arcnet/com20020-pci.c linux/drivers/net/arcnet/com20020-pci.c --- v2.4.14/linux/drivers/net/arcnet/com20020-pci.c Mon Nov 5 15:55:30 2001 +++ linux/drivers/net/arcnet/com20020-pci.c Fri Nov 9 13:41:42 2001 @@ -83,7 +83,7 @@ goto out_dev; } memset(lp, 0, sizeof(struct arcnet_local)); - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); ioaddr = pci_resource_start(pdev, 2); dev->base_addr = ioaddr; @@ -128,7 +128,7 @@ static void __devexit com20020pci_remove(struct pci_dev *pdev) { - com20020_remove(pdev->driver_data); + com20020_remove(pci_get_drvdata(pdev)); } static struct pci_device_id com20020pci_id_table[] __devinitdata = { diff -u --recursive --new-file v2.4.14/linux/drivers/net/arlan.c linux/drivers/net/arlan.c --- v2.4.14/linux/drivers/net/arlan.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/net/arlan.c Fri Nov 9 13:45:35 2001 @@ -8,6 +8,10 @@ #include <linux/config.h> #include "arlan.h" +#if BITS_PER_LONG != 32 +# error FIXME: this driver requires a 32-bit platform +#endif + static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/"; struct net_device *arlan_device[MAX_ARLANS]; diff -u --recursive --new-file v2.4.14/linux/drivers/net/bonding.c linux/drivers/net/bonding.c --- v2.4.14/linux/drivers/net/bonding.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/net/bonding.c Wed Nov 7 14:39:36 2001 @@ -4,11 +4,14 @@ * Copyright 1999, Thomas Davis, tadavis@lbl.gov. * Licensed under the GPL. Based on dummy.c, and eql.c devices. * - * bond.c: a bonding/etherchannel/sun trunking net driver + * bonding.c: an Ethernet Bonding driver * - * This is useful to talk to a Cisco 5500, running Etherchannel, aka: - * Linux Channel Bonding + * This is useful to talk to a Cisco EtherChannel compatible equipment: + * Cisco 5500 * Sun Trunking (Solaris) + * Alteon AceDirector Trunks + * Linux Bonding + * and probably many L2 switches ... * * How it works: * ifconfig bond0 ipaddress netmask up @@ -21,280 +24,2019 @@ * will release all slaves, marking them as down. * * ifenslave bond0 eth0 - * will attache eth0 to bond0 as a slave. eth0 hw mac address will either + * will attach eth0 to bond0 as a slave. eth0 hw mac address will either * a: be used as initial mac address * b: if a hw mac address already is there, eth0's hw mac address - * will then be set from bond0. + * will then be set from bond0. * * v0.1 - first working version. * v0.2 - changed stats to be calculated by summing slaves stats. + * + * Changes: + * Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * - fix leaks on failure at bond_init + * + * 2000/09/30 - Willy Tarreau <willy at meta-x.org> + * - added trivial code to release a slave device. + * - fixed security bug (CAP_NET_ADMIN not checked) + * - implemented MII link monitoring to disable dead links : + * All MII capable slaves are checked every <miimon> milliseconds + * (100 ms seems good). This value can be changed by passing it to + * insmod. A value of zero disables the monitoring (default). + * - fixed an infinite loop in bond_xmit_roundrobin() when there's no + * good slave. + * - made the code hopefully SMP safe + * + * 2000/10/03 - Willy Tarreau <willy at meta-x.org> + * - optimized slave lists based on relevant suggestions from Thomas Davis + * - implemented active-backup method to obtain HA with two switches: + * stay as long as possible on the same active interface, while we + * also monitor the backup one (MII link status) because we want to know + * if we are able to switch at any time. ( pass "mode=1" to insmod ) + * - lots of stress testings because we need it to be more robust than the + * wires ! :-> + * + * 2000/10/09 - Willy Tarreau <willy at meta-x.org> + * - added up and down delays after link state change. + * - optimized the slaves chaining so that when we run forward, we never + * repass through the bond itself, but we can find it by searching + * backwards. Renders the deletion more difficult, but accelerates the + * scan. + * - smarter enslaving and releasing. + * - finer and more robust SMP locking + * + * 2000/10/17 - Willy Tarreau <willy at meta-x.org> + * - fixed two potential SMP race conditions + * + * 2000/10/18 - Willy Tarreau <willy at meta-x.org> + * - small fixes to the monitoring FSM in case of zero delays + * 2000/11/01 - Willy Tarreau <willy at meta-x.org> + * - fixed first slave not automatically used in trunk mode. + * 2000/11/10 : spelling of "EtherChannel" corrected. + * 2000/11/13 : fixed a race condition in case of concurrent accesses to ioctl(). + * 2000/12/16 : fixed improper usage of rtnl_exlock_nowait(). + * + * 2001/1/3 - Chad N. Tindel <ctindel at ieee dot org> + * - The bonding driver now simulates MII status monitoring, just like + * a normal network device. It will show that the link is down iff + * every slave in the bond shows that their links are down. If at least + * one slave is up, the bond's MII status will appear as up. + * + * 2001/2/7 - Chad N. Tindel <ctindel at ieee dot org> + * - Applications can now query the bond from user space to get + * information which may be useful. They do this by calling + * the BOND_INFO_QUERY ioctl. Once the app knows how many slaves + * are in the bond, it can call the BOND_SLAVE_INFO_QUERY ioctl to + * get slave specific information (# link failures, etc). See + * <linux/if_bonding.h> for more details. The structs of interest + * are ifbond and ifslave. + * + * 2001/4/5 - Chad N. Tindel <ctindel at ieee dot org> + * - Ported to 2.4 Kernel * + * 2001/5/2 - Jeffrey E. Mast <jeff at mastfamily dot com> + * - When a device is detached from a bond, the slave device is no longer + * left thinking that is has a master. + * + * 2001/5/16 - Jeffrey E. Mast <jeff at mastfamily dot com> + * - memset did not appropriately initialized the bond rw_locks. Used + * rwlock_init to initialize to unlocked state to prevent deadlock when + * first attempting a lock + * - Called SET_MODULE_OWNER for bond device + * + * 2001/5/17 - Tim Anderson <tsa at mvista.com> + * - 2 paths for releasing for slave release; 1 through ioctl + * and 2) through close. Both paths need to release the same way. + * - the free slave in bond release is changing slave status before + * the free. The netdev_set_master() is intended to change slave state + * so it should not be done as part of the release process. + * - Simple rule for slave state at release: only the active in A/B and + * only one in the trunked case. + * + * 2001/6/01 - Tim Anderson <tsa at mvista.com> + * - Now call dev_close when releasing a slave so it doesn't screw up + * out routing table. + * + * 2001/6/01 - Chad N. Tindel <ctindel at ieee dot org> + * - Added /proc support for getting bond and slave information. + * Information is in /proc/net/<bond device>/info. + * - Changed the locking when calling bond_close to prevent deadlock. + * + * 2001/8/05 - Janice Girouard <girouard at us.ibm.com> + * - correct problem where refcnt of slave is not incremented in bond_ioctl + * so the system hangs when halting. + * - correct locking problem when unable to malloc in bond_enslave. + * - adding bond_xmit_xor logic. + * - adding multiple bond device support. + * + * 2001/8/13 - Erik Habbinga <erik_habbinga at hp dot com> + * - correct locking problem with rtnl_exlock_nowait + * + * 2001/8/23 - Janice Girouard <girouard at us.ibm.com> + * - bzero initial dev_bonds, to correct oops + * - convert SIOCDEVPRIVATE to new MII ioctl calls + * + * 2001/9/13 - Takao Indoh <indou dot takao at jp dot fujitsu dot com> + * - Add the BOND_CHANGE_ACTIVE ioctl implementation + * + * 2001/9/14 - Mark Huth <mhuth at mvista dot com> + * - Change MII_LINK_READY to not check for end of auto-negotiation, + * but only for an up link. + * + * 2001/9/20 - Chad N. Tindel <ctindel at ieee dot org> + * - Add the device field to bonding_t. Previously the net_device + * corresponding to a bond wasn't available from the bonding_t + * structure. + * + * 2001/9/25 - Janice Girouard <girouard at us.ibm.com> + * - add arp_monitor for active backup mode + * + * 2001/10/23 - Takao Indoh <indou dot takao at jp dot fujitsu dot com> + * - Various memory leak fixes */ -#include <linux/module.h> +#include <linux/config.h> #include <linux/kernel.h> -#include <linux/netdevice.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/in.h> +#include <linux/malloc.h> +#include <linux/string.h> #include <linux/init.h> +#include <linux/timer.h> +#include <linux/socket.h> +#include <asm/system.h> +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/uaccess.h> +#include <linux/errno.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <net/sock.h> +#include <linux/rtnetlink.h> + #include <linux/if_bonding.h> +#include <linux/smp.h> +#include <limits.h> +#include <linux/if_ether.h> +#include <linux/if_arp.h> + +/* monitor all links that often (in milliseconds). <=0 disables monitoring */ +#ifndef BOND_LINK_MON_INTERV +#define BOND_LINK_MON_INTERV 0 +#endif + +#undef MII_LINK_UP +#define MII_LINK_UP 0x04 + +#undef MII_ENDOF_NWAY +#define MII_ENDOF_NWAY 0x20 + +#undef MII_LINK_READY +/*#define MII_LINK_READY (MII_LINK_UP | MII_ENDOF_NWAY)*/ +#define MII_LINK_READY (MII_LINK_UP) + +#define MAX_BOND_ADDR 256 + +#ifndef BOND_LINK_ARP_INTERV +#define BOND_LINK_ARP_INTERV 0 +#endif + +static int arp_interval = BOND_LINK_ARP_INTERV; +static char *arp_ip_target = NULL; +static unsigned long arp_target = 0; +static u32 my_ip = 0; +char *arp_target_hw_addr = NULL; + +static int max_bonds = MAX_BONDS; +static int miimon = BOND_LINK_MON_INTERV; +static int mode = BOND_MODE_ROUNDROBIN; +static int updelay = 0; +static int downdelay = 0; + +static int first_pass = 1; +int bond_cnt; +static struct bonding *these_bonds = NULL; +static struct net_device *dev_bonds = NULL; + +MODULE_PARM(max_bonds, "1-" __MODULE_STRING(INT_MAX) "i"); +MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); +MODULE_PARM(miimon, "i"); +MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); +MODULE_PARM(mode, "i"); +MODULE_PARM(arp_interval, "i"); +MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); +MODULE_PARM(arp_ip_target, "1-12s"); +MODULE_PARM_DESC(arp_ip_target, "arp target in n.n.n.n form"); +MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); +MODULE_PARM(updelay, "i"); +MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); +MODULE_PARM(downdelay, "i"); +MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds"); + +extern void arp_send( int type, int ptype, u32 dest_ip, struct net_device *dev, + u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, + unsigned char *target_hw); + +static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev); +static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev); +static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev); +static struct net_device_stats *bond_get_stats(struct net_device *dev); +static void bond_mii_monitor(struct net_device *dev); +static void bond_arp_monitor(struct net_device *dev); +static int bond_event(struct notifier_block *this, unsigned long event, void *ptr); +static void bond_set_slave_inactive_flags(slave_t *slave); +static void bond_set_slave_active_flags(slave_t *slave); +static int bond_enslave(struct net_device *master, struct net_device *slave); +static int bond_release(struct net_device *master, struct net_device *slave); +static int bond_sethwaddr(struct net_device *master, struct net_device *slave); + +/* + * bond_get_info is the interface into the /proc filesystem. This is + * a different interface than the BOND_INFO_QUERY ioctl. That is done + * through the generic networking ioctl interface, and bond_info_query + * is the internal function which provides that information. + */ +static int bond_get_info(char *buf, char **start, off_t offset, int length); + +/* #define BONDING_DEBUG 1 */ -typedef struct slave +/* several macros */ + +#define IS_UP(dev) ((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \ + (netif_running(dev) && netif_carrier_ok(dev))) + +static void bond_set_slave_inactive_flags(slave_t *slave) { - struct slave *next; - struct slave *prev; - struct net_device *dev; -} slave_t; + slave->state = BOND_STATE_BACKUP; + slave->dev->flags |= IFF_NOARP; +} -typedef struct bonding +static void bond_set_slave_active_flags(slave_t *slave) { - slave_t *next; - slave_t *prev; - struct net_device *master; + slave->state = BOND_STATE_ACTIVE; + slave->dev->flags &= ~IFF_NOARP; +} - slave_t *current_slave; - struct net_device_stats stats; -} bonding_t; +/* + * This function detaches the slave <slave> from the list <bond>. + * WARNING: no check is made to verify if the slave effectively + * belongs to <bond>. It returns <slave> in case it's needed. + * Nothing is freed on return, structures are just unchained. + * If the bond->current_slave pointer was pointing to <slave>, + * it's replaced with slave->next, or <bond> if not applicable. + */ +static slave_t *bond_detach_slave(bonding_t *bond, slave_t *slave) +{ + if ((bond == NULL) || (slave == NULL) || + ((void *)bond == (void *)slave)) { + printk(KERN_ERR + "bond_detach_slave(): trying to detach " + "slave %p from bond %p\n", bond, slave); + return slave; + } + if (bond->next == slave) { /* is the slave at the head ? */ + if (bond->prev == slave) { /* is the slave alone ? */ + write_lock(&bond->ptrlock); + bond->current_slave = NULL; /* no slave anymore */ + write_unlock(&bond->ptrlock); + bond->prev = bond->next = (slave_t *)bond; + } else { /* not alone */ + bond->next = slave->next; + slave->next->prev = (slave_t *)bond; + bond->prev->next = slave->next; + + write_lock(&bond->ptrlock); + if (bond->current_slave == slave) { + bond->current_slave = slave->next; + } + write_unlock(&bond->ptrlock); + } + } + else { + slave->prev->next = slave->next; + if (bond->prev == slave) { /* is this slave the last one ? */ + bond->prev = slave->prev; + } else { + slave->next->prev = slave->prev; + } -static int bond_xmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *bond_get_stats(struct net_device *dev); + write_lock(&bond->ptrlock); + if (bond->current_slave == slave) { + bond->current_slave = slave->next; + } + write_unlock(&bond->ptrlock); + } -static struct net_device *this_bond; + return slave; +} -static void release_one_slave(struct net_device *master, slave_t *slave) +/* + * if <dev> supports MII link status reporting, check its link + * and report it as a bit field in a short int : + * - 0x04 means link is up, + * - 0x20 means end of autonegociation + * If the device doesn't support MII, then we only report 0x24, + * meaning that the link is up and running since we can't check it. + */ +static u16 bond_check_dev_link(struct net_device *dev) { - bonding_t *bond = master->priv; + static int (* ioctl)(struct net_device *, struct ifreq *, int); + struct ifreq ifr; + u16 *data = (u16 *)&ifr.ifr_data; + + /* data[0] automagically filled by the ioctl */ + data[1] = 1; /* MII location 1 reports Link Status */ + + if (((ioctl = dev->do_ioctl) != NULL) && /* ioctl to access MII */ + (ioctl(dev, &ifr, SIOCGMIIPHY) == 0)) { + /* now, data[3] contains info about link status : + - data[3] & 0x04 means link up + - data[3] & 0x20 means end of auto-negociation + */ + return data[3]; + } else { + return MII_LINK_READY; /* spoof link up ( we can't check it) */ + } +} - spin_lock_bh(&master->xmit_lock); - if (bond->current_slave == slave) - bond->current_slave = slave->next; - slave->next->prev = slave->prev; - slave->prev->next = slave->next; - spin_unlock_bh(&master->xmit_lock); +static u16 bond_check_mii_link(bonding_t *bond) +{ + int has_active_interface = 0; - netdev_set_master(slave->dev, NULL); + read_lock(&bond->ptrlock); + has_active_interface = (bond->current_slave != NULL); + read_unlock(&bond->ptrlock); - dev_put(slave->dev); - kfree(slave); + return (has_active_interface ? MII_LINK_READY : 0); +} + +static int bond_open(struct net_device *dev) +{ + struct timer_list *timer = &((struct bonding *)(dev->priv))->mii_timer; + struct timer_list *arp_timer = &((struct bonding *)(dev->priv))->arp_timer; + MOD_INC_USE_COUNT; + + if (miimon > 0) { /* link check interval, in milliseconds. */ + init_timer(timer); + timer->expires = jiffies + (miimon * HZ / 1000); + timer->data = (unsigned long)dev; + timer->function = (void *)&bond_mii_monitor; + add_timer(timer); + } + + if (arp_interval> 0) { /* arp interval, in milliseconds. */ + init_timer(arp_timer); + arp_timer->expires = jiffies + (arp_interval * HZ / 1000); + arp_timer->data = (unsigned long)dev; + arp_timer->function = (void *)&bond_arp_monitor; + add_timer(arp_timer); + } + return 0; } static int bond_close(struct net_device *master) { - bonding_t *bond = master->priv; + bonding_t *bond = (struct bonding *) master->priv; slave_t *slave; + unsigned long flags; - while ((slave = bond->next) != (slave_t*)bond) - release_one_slave(master, slave); + write_lock_irqsave(&bond->lock, flags); + if (miimon > 0) { /* link check interval, in milliseconds. */ + del_timer(&bond->mii_timer); + } + if (arp_interval> 0) { /* arp interval, in milliseconds. */ + del_timer(&bond->arp_timer); + } + /* We need to unlock this because bond_release will re-lock it */ + write_unlock_irqrestore(&bond->lock, flags); + + /* Release the bonded slaves */ + while ((slave = bond->prev) != (slave_t *)bond) { + bond_release(master, slave->dev); + } + + MOD_DEC_USE_COUNT; return 0; } -static void bond_set_multicast_list(struct net_device *master) +static void set_multicast_list(struct net_device *master) { +/* + bonding_t *bond = master->priv; + slave_t *slave; + + for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) { + slave->dev->mc_list = master->mc_list; + slave->dev->mc_count = master->mc_count; + slave->dev->flags = master->flags; + slave->dev->set_multicast_list(slave->dev); + } + */ } -static int bond_enslave(struct net_device *master, struct net_device *dev) +/* + * This function counts the the number of attached + * slaves for use by bond_xmit_xor. + */ +static void update_slave_cnt(bonding_t *bond) { - int err; - bonding_t *bond = master->priv; - slave_t *slave; + slave_t *slave = NULL; + + bond->slave_cnt = 0; + for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) { + bond->slave_cnt++; + } +} - if (dev->type != master->type) +/* enslave device <slave> to bond device <master> */ +static int bond_enslave(struct net_device *master_dev, + struct net_device *slave_dev) +{ + bonding_t *bond = NULL; + slave_t *new_slave = NULL; + unsigned long flags = 0; + int ndx = 0; + int err = 0; + + if (master_dev == NULL || slave_dev == NULL) { return -ENODEV; + } + bond = (struct bonding *) master_dev->priv; + + if (slave_dev->do_ioctl == NULL) { + printk(KERN_DEBUG + "Warning : no link monitoring support for %s\n", + slave_dev->name); + } + write_lock_irqsave(&bond->lock, flags); + + /* not running. */ + if ((slave_dev->flags & IFF_UP) != IFF_UP) { +#ifdef BONDING_DEBUG + printk(KERN_CRIT "Error, slave_dev is not running\n"); +#endif + write_unlock_irqrestore(&bond->lock, flags); + return -EINVAL; + } - if ((slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) + /* already enslaved */ + if (master_dev->flags & IFF_SLAVE || slave_dev->flags & IFF_SLAVE) { +#ifdef BONDING_DEBUG + printk(KERN_CRIT "Error, Device was already enslaved\n"); +#endif + write_unlock_irqrestore(&bond->lock, flags); + return -EBUSY; + } + + if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) { + write_unlock_irqrestore(&bond->lock, flags); return -ENOMEM; + } + memset(new_slave, 0, sizeof(slave_t)); - memset(slave, 0, sizeof(slave_t)); + err = netdev_set_master(slave_dev, master_dev); - err = netdev_set_master(dev, master); if (err) { - kfree(slave); - return err; +#ifdef BONDING_DEBUG + printk(KERN_CRIT "Error %d calling netdev_set_master\n", err); +#endif + kfree(new_slave); + write_unlock_irqrestore(&bond->lock, flags); + return err; } - slave->dev = dev; + new_slave->dev = slave_dev; - spin_lock_bh(&master->xmit_lock); + /* + * queue to the end of the slaves list, make the first element its + * successor, the last one its predecessor, and make it the bond's + * predecessor. + */ + new_slave->prev = bond->prev; + new_slave->prev->next = new_slave; + bond->prev = new_slave; + new_slave->next = bond->next; + + new_slave->delay = 0; + new_slave->link_failure_count = 0; + + /* check for initial state */ + if ((miimon <= 0) || ((bond_check_dev_link(slave_dev) & MII_LINK_READY) + == MII_LINK_READY)) { +#ifdef BONDING_DEBUG + printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n"); +#endif + new_slave->link = BOND_LINK_UP; + } + else { +#ifdef BONDING_DEBUG + printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_DOWN\n"); +#endif + new_slave->link = BOND_LINK_DOWN; + } - dev_hold(dev); + /* if we're in active-backup mode, we need one and only one active + * interface. The backup interfaces will have their NOARP flag set + * because we need them to be completely deaf and not to respond to + * any ARP request on the network to avoid fooling a switch. Thus, + * since we guarantee that current_slave always point to the last + * usable interface, we just have to verify this interface's flag. + */ + if (mode == BOND_MODE_ACTIVEBACKUP) { + if (((bond->current_slave == NULL) + || (bond->current_slave->dev->flags & IFF_NOARP)) + && (new_slave->link == BOND_LINK_UP)) { +#ifdef BONDING_DEBUG + printk(KERN_CRIT "This is the first active slave\n"); +#endif + /* first slave or no active slave yet, and this link + is OK, so make this interface the active one */ + bond->current_slave = new_slave; + bond_set_slave_active_flags(new_slave); + } + else { +#ifdef BONDING_DEBUG + printk(KERN_CRIT "This is just a backup slave\n"); +#endif + bond_set_slave_inactive_flags(new_slave); + } + } else { +#ifdef BONDING_DEBUG + printk(KERN_CRIT "This slave is always active in trunk mode\n"); +#endif + /* always active in trunk mode */ + new_slave->state = BOND_STATE_ACTIVE; + if (bond->current_slave == NULL) { + bond->current_slave = new_slave; + } + } + + update_slave_cnt(bond); - slave->prev = bond->prev; - slave->next = (slave_t*)bond; - slave->prev->next = slave; - slave->next->prev = slave; + write_unlock_irqrestore(&bond->lock, flags); + + /* + * !!! This is to support old versions of ifenslave. We can remove + * this in 2.5 because our ifenslave takes care of this for us. + * We check to see if the master has a mac address yet. If not, + * we'll give it the mac address of our slave device. + */ + for (ndx = 0; ndx < slave_dev->addr_len; ndx++) { +#ifdef BONDING_DEBUG + printk(KERN_CRIT "Checking ndx=%d of master_dev->dev_addr\n", + ndx); +#endif + if (master_dev->dev_addr[ndx] != 0) { +#ifdef BONDING_DEBUG + printk(KERN_CRIT "Found non-zero byte at ndx=%d\n", + ndx); +#endif + break; + } + } + if (ndx == slave_dev->addr_len) { + /* + * We got all the way through the address and it was + * all 0's. + */ +#ifdef BONDING_DEBUG + printk(KERN_CRIT "%s doesn't have a MAC address yet. ", + master_dev->name); + printk(KERN_CRIT "Going to give assign it from %s.\n", + slave_dev->name); +#endif + bond_sethwaddr(master_dev, slave_dev); + } - spin_unlock_bh(&master->xmit_lock); + printk (KERN_INFO "%s: enslaving %s as a%s interface with a%s link.\n", + master_dev->name, slave_dev->name, + new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", + new_slave->link == BOND_LINK_UP ? "n up" : " down"); return 0; } -static int bond_release(struct net_device *master, struct net_device *dev) +/* + * This function changes the active slave to slave <slave_dev>. + * It returns -EINVAL in the following cases. + * - <slave_dev> is not found in the list. + * - There is not active slave now. + * - <slave_dev> is already active. + * - The link state of <slave_dev> is not BOND_LINK_UP. + * - <slave_dev> is not running. + * In these cases, this fuction does nothing. + * In the other cases, currnt_slave pointer is changed and 0 is returned. + */ +static int bond_change_active(struct net_device *master_dev, struct net_device *slave_dev) { - bonding_t *bond = master->priv; + bonding_t *bond; slave_t *slave; + slave_t *oldactive = NULL; + slave_t *newactive = NULL; + unsigned long flags; + int ret = 0; - if (dev->master != master) + if (master_dev == NULL || slave_dev == NULL) { + return -ENODEV; + } + + bond = (struct bonding *) master_dev->priv; + write_lock_irqsave(&bond->lock, flags); + slave = (slave_t *)bond; + oldactive = bond->current_slave; + + while ((slave = slave->prev) != (slave_t *)bond) { + if(slave_dev == slave->dev) { + newactive = slave; + break; + } + } + + if ((newactive != NULL)&& + (oldactive != NULL)&& + (newactive != oldactive)&& + (newactive->link == BOND_LINK_UP)&& + IS_UP(newactive->dev)) { + bond_set_slave_inactive_flags(oldactive); + bond_set_slave_active_flags(newactive); + bond->current_slave = newactive; + printk("%s : activate %s(old : %s)\n", + master_dev->name, newactive->dev->name, + oldactive->dev->name); + } + else { + ret = -EINVAL; + } + write_unlock_irqrestore(&bond->lock, flags); + return ret; +} + +/* Choose a new valid interface from the pool, set it active + * and make it the current slave. If no valid interface is + * found, the oldest slave in BACK state is choosen and + * activated. If none is found, it's considered as no + * interfaces left so the current slave is set to NULL. + * The result is a pointer to the current slave. + * + * Since this function sends messages tails through printk, the caller + * must have started something like `printk(KERN_INFO "xxxx ");'. + * + * Warning: must put locks around the call to this function if needed. + */ +slave_t *change_active_interface(bonding_t *bond) +{ + slave_t *newslave, *oldslave; + slave_t *bestslave = NULL; + int mintime; + + read_lock(&bond->ptrlock); + newslave = oldslave = bond->current_slave; + read_unlock(&bond->ptrlock); + + if (newslave == NULL) { /* there were no active slaves left */ + if (bond->next != (slave_t *)bond) { /* found one slave */ + write_lock(&bond->ptrlock); + newslave = bond->current_slave = bond->next; + write_unlock(&bond->ptrlock); + } else { + printk (" but could not find any %s interface.\n", + (mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other"); + write_lock(&bond->ptrlock); + bond->current_slave = (slave_t *)NULL; + write_unlock(&bond->ptrlock); + return NULL; /* still no slave, return NULL */ + } + } + + mintime = updelay; + + do { + if (IS_UP(newslave->dev)) { + if (newslave->link == BOND_LINK_UP) { + /* this one is immediately usable */ + if (mode == BOND_MODE_ACTIVEBACKUP) { + bond_set_slave_active_flags(newslave); + printk (" and making interface %s the active one.\n", + newslave->dev->name); + } + else { + printk (" and setting pointer to interface %s.\n", + newslave->dev->name); + } + + write_lock(&bond->ptrlock); + bond->current_slave = newslave; + write_unlock(&bond->ptrlock); + return newslave; + } + else if (newslave->link == BOND_LINK_BACK) { + /* link up, but waiting for stabilization */ + if (newslave->delay < mintime) { + mintime = newslave->delay; + bestslave = newslave; + } + } + } + } while ((newslave = newslave->next) != oldslave); + + /* no usable backup found, we'll see if we at least got a link that was + coming back for a long time, and could possibly already be usable. + */ + + if (bestslave != NULL) { + /* early take-over. */ + printk (" and making interface %s the active one %d ms earlier.\n", + bestslave->dev->name, + (updelay - bestslave->delay)*miimon); + + bestslave->delay = 0; + bestslave->link = BOND_LINK_UP; + bond_set_slave_active_flags(bestslave); + + write_lock(&bond->ptrlock); + bond->current_slave = bestslave; + write_unlock(&bond->ptrlock); + return bestslave; + } + + printk (" but could not find any %s interface.\n", + (mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other"); + + /* absolutely nothing found. let's return NULL */ + write_lock(&bond->ptrlock); + bond->current_slave = (slave_t *)NULL; + write_unlock(&bond->ptrlock); + return NULL; +} + +/* + * Try to release the slave device <slave> from the bond device <master> + * It is legal to access current_slave without a lock because all the function + * is write-locked. + * + * The rules for slave state should be: + * for Active/Backup: + * Active stays on all backups go down + * for Bonded connections: + * The first up interface should be left on and all others downed. + */ +static int bond_release(struct net_device *master, struct net_device *slave) +{ + bonding_t *bond; + slave_t *our_slave, *old_current; + unsigned long flags; + + if (master == NULL || slave == NULL) { + return -ENODEV; + } + + bond = (struct bonding *) master->priv; + + write_lock_irqsave(&bond->lock, flags); + + /* master already enslaved, or slave not enslaved, + or no slave for this master */ + if ((master->flags & IFF_SLAVE) || !(slave->flags & IFF_SLAVE)) { + printk (KERN_DEBUG "%s: cannot release %s.\n", master->name, slave->name); + write_unlock_irqrestore(&bond->lock, flags); return -EINVAL; + } - for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) { - if (slave->dev == dev) { - release_one_slave(master, slave); + our_slave = (slave_t *)bond; + old_current = bond->current_slave; + while ((our_slave = our_slave->prev) != (slave_t *)bond) { + if (our_slave->dev == slave) { + bond_detach_slave(bond, our_slave); + + printk (KERN_INFO "%s: releasing %s interface %s", + master->name, + (our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup", + slave->name); + + if (our_slave == old_current) { + /* find a new interface and be verbose */ + change_active_interface(bond); + } else { + printk(".\n"); + } + kfree(our_slave); + + /* release the slave from its bond */ + + netdev_set_master(slave, NULL); + + /* only restore its RUNNING flag if monitoring set it down */ + if (slave->flags & IFF_UP) { + slave->flags |= IFF_RUNNING; + } + + if (slave->flags & IFF_NOARP || + bond->current_slave != NULL) { + dev_close(slave); + } + + if (bond->current_slave == NULL) { + printk(KERN_INFO + "%s: now running without any active interface !\n", + master->name); + } + + update_slave_cnt(bond); + + write_unlock_irqrestore(&bond->lock, flags); + return 0; /* deletion OK */ + } + } + + /* if we get here, it's because the device was not found */ + write_unlock_irqrestore(&bond->lock, flags); + + printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name); + return -EINVAL; +} + +/* this function is called regularly to monitor each slave's link. */ +static void bond_mii_monitor(struct net_device *master) +{ + bonding_t *bond = (struct bonding *) master->priv; + slave_t *slave, *bestslave, *oldcurrent; + unsigned long flags; + int slave_died = 0; + + read_lock_irqsave(&bond->lock, flags); + + if (rtnl_shlock_nowait()) { + goto monitor_out; + } + + if (rtnl_exlock_nowait()) { + rtnl_shunlock(); + goto monitor_out; + } + /* we will try to read the link status of each of our slaves, and + * set their IFF_RUNNING flag appropriately. For each slave not + * supporting MII status, we won't do anything so that a user-space + * program could monitor the link itself if needed. + */ + + bestslave = NULL; + slave = (slave_t *)bond; + + read_lock(&bond->ptrlock); + oldcurrent = bond->current_slave; + read_unlock(&bond->ptrlock); + + while ((slave = slave->prev) != (slave_t *)bond) { + /* use updelay+1 to match an UP slave even when updelay is 0 */ + int mindelay = updelay + 1; + struct net_device *dev = slave->dev; + u16 link_state; + + link_state = bond_check_dev_link(dev); + + switch (slave->link) { + case BOND_LINK_UP: /* the link was up */ + if ((link_state & MII_LINK_UP) == MII_LINK_UP) { + /* link stays up, tell that this one + is immediately available */ + if (IS_UP(dev) && (mindelay > -2)) { + /* -2 is the best case : + this slave was already up */ + mindelay = -2; + bestslave = slave; + } + break; + } + else { /* link going down */ + slave->link = BOND_LINK_FAIL; + slave->delay = downdelay; + if (slave->link_failure_count < UINT_MAX) { + slave->link_failure_count++; + } + if (downdelay > 0) { + printk (KERN_INFO + "%s: link status down for %sinterface " + "%s, disabling it in %d ms.\n", + master->name, + IS_UP(dev) + ? ((mode == BOND_MODE_ACTIVEBACKUP) + ? ((slave == oldcurrent) + ? "active " : "backup ") + : "") + : "idle ", + dev->name, + downdelay * miimon); + } + } + /* no break ! fall through the BOND_LINK_FAIL test to + ensure proper action to be taken + */ + case BOND_LINK_FAIL: /* the link has just gone down */ + if ((link_state & MII_LINK_UP) == 0) { + /* link stays down */ + if (slave->delay <= 0) { + /* link down for too long time */ + slave->link = BOND_LINK_DOWN; + /* in active/backup mode, we must + completely disable this interface */ + if (mode == BOND_MODE_ACTIVEBACKUP) { + bond_set_slave_inactive_flags(slave); + } + printk(KERN_INFO + "%s: link status definitely down " + "for interface %s, disabling it", + master->name, + dev->name); + + read_lock(&bond->ptrlock); + if (slave == bond->current_slave) { + read_unlock(&bond->ptrlock); + /* find a new interface and be verbose */ + change_active_interface(bond); + } else { + read_unlock(&bond->ptrlock); + printk(".\n"); + } + slave_died = 1; + } else { + slave->delay--; + } + } else if ((link_state & MII_LINK_READY) == MII_LINK_READY) { + /* link up again */ + slave->link = BOND_LINK_UP; + printk(KERN_INFO + "%s: link status up again after %d ms " + "for interface %s.\n", + master->name, + (downdelay - slave->delay) * miimon, + dev->name); + + if (IS_UP(dev) && (mindelay > -1)) { + /* -1 is a good case : this slave went + down only for a short time */ + mindelay = -1; + bestslave = slave; + } + } break; + case BOND_LINK_DOWN: /* the link was down */ + if ((link_state & MII_LINK_READY) != MII_LINK_READY) { + /* the link stays down, nothing more to do */ + break; + } else { /* link going up */ + slave->link = BOND_LINK_BACK; + slave->delay = updelay; + + if (updelay > 0) { + /* if updelay == 0, no need to + advertise about a 0 ms delay */ + printk (KERN_INFO + "%s: link status up for interface" + " %s, enabling it in %d ms.\n", + master->name, + dev->name, + updelay * miimon); + } + } + /* no break ! fall through the BOND_LINK_BACK state in + case there's something to do. + */ + case BOND_LINK_BACK: /* the link has just come back */ + if ((link_state & MII_LINK_UP) == 0) { + /* link down again */ + slave->link = BOND_LINK_DOWN; + printk(KERN_INFO + "%s: link status down again after %d ms " + "for interface %s.\n", + master->name, + (updelay - slave->delay) * miimon, + dev->name); + } + else if ((link_state & MII_LINK_READY) == MII_LINK_READY) { + /* link stays up */ + if (slave->delay == 0) { + /* now the link has been up for long time enough */ + slave->link = BOND_LINK_UP; + + if (mode == BOND_MODE_ACTIVEBACKUP) { + /* prevent it from being the active one */ + slave->state = BOND_STATE_BACKUP; + } + else { + /* make it immediately active */ + slave->state = BOND_STATE_ACTIVE; + } + + printk(KERN_INFO + "%s: link status definitely up " + "for interface %s.\n", + master->name, + dev->name); + } + else + slave->delay--; + + /* we'll also look for the mostly eligible slave */ + if (IS_UP(dev) && (slave->delay < mindelay)) { + mindelay = slave->delay; + bestslave = slave; + } + } + break; + } /* end of switch */ + } /* end of while */ + + /* if there's no active interface and we discovered that one + of the slaves could be activated earlier, so we do it. + */ + read_lock(&bond->ptrlock); + oldcurrent = bond->current_slave; + read_unlock(&bond->ptrlock); + + if (oldcurrent == NULL) { /* no active interface at the moment */ + if (bestslave != NULL) { /* last chance to find one ? */ + if (bestslave->link == BOND_LINK_UP) { + printk (KERN_INFO + "%s: making interface %s the new active one.\n", + master->name, bestslave->dev->name); + } else { + printk (KERN_INFO + "%s: making interface %s the new " + "active one %d ms earlier.\n", + master->name, bestslave->dev->name, + (updelay - bestslave->delay) * miimon); + + bestslave->delay= 0; + bestslave->link = BOND_LINK_UP; + } + + if (mode == BOND_MODE_ACTIVEBACKUP) { + bond_set_slave_active_flags(bestslave); + } else { + bestslave->state = BOND_STATE_ACTIVE; + } + write_lock(&bond->ptrlock); + bond->current_slave = bestslave; + write_unlock(&bond->ptrlock); + } else if (slave_died) { + /* print this message only once a slave has just died */ + printk(KERN_INFO + "%s: now running without any active interface !\n", + master->name); } } - return 0; + rtnl_exunlock(); + rtnl_shunlock(); +monitor_out: + read_unlock_irqrestore(&bond->lock, flags); + /* re-arm the timer */ + mod_timer(&bond->mii_timer, jiffies + (miimon * HZ / 1000)); } -/* It is pretty silly, SIOCSIFHWADDR exists to make this. */ +/* + * this function is called regularly to monitor each slave's link + * insuring that traffic is being sent and received. If the adapter + * has been dormant, then an arp is transmitted to generate traffic + */ +static void bond_arp_monitor(struct net_device *master) +{ + bonding_t *bond; + unsigned long flags; + slave_t *slave; + int the_delta_in_ticks = arp_interval * HZ / 1000; + int next_timer = jiffies + (arp_interval * HZ / 1000); + + bond = (struct bonding *) master->priv; + if (master->priv == NULL) { + mod_timer(&bond->arp_timer, next_timer); + return; + } + + read_lock_irqsave(&bond->lock, flags); + + if (!IS_UP(master)) { + mod_timer(&bond->arp_timer, next_timer); + goto monitor_out; + } + + + if (rtnl_shlock_nowait()) { + goto monitor_out; + } + + if (rtnl_exlock_nowait()) { + rtnl_shunlock(); + goto monitor_out; + } + + /* see if any of the previous devices are up now (i.e. they have seen a + * response from an arp request sent by another adapter, since they + * have the same hardware address). + */ + + slave = (slave_t *)bond; + while ((slave = slave->prev) != (slave_t *)bond) { + + read_lock(&bond->ptrlock); + if ( (!(slave->link == BOND_LINK_UP)) + && (slave!= bond->current_slave) ) { + + read_unlock(&bond->ptrlock); + + if ( ((jiffies - slave->dev->trans_start) <= + the_delta_in_ticks) && + ((jiffies - slave->dev->last_rx) <= + the_delta_in_ticks) ) { + + slave->link = BOND_LINK_UP; + write_lock(&bond->ptrlock); + if (bond->current_slave == NULL) { + slave->state = BOND_STATE_ACTIVE; + bond->current_slave = slave; + } + if (slave!=bond->current_slave) { + slave->dev->flags |= IFF_NOARP; + } + write_unlock(&bond->ptrlock); + } else { + if ((jiffies - slave->dev->last_rx) <= + the_delta_in_ticks) { + arp_send(ARPOP_REQUEST, ETH_P_ARP, + arp_target, slave->dev, + my_ip, arp_target_hw_addr, + slave->dev->dev_addr, + arp_target_hw_addr); + } + } + } else + read_unlock(&bond->ptrlock); + } + + read_lock(&bond->ptrlock); + slave = bond->current_slave; + read_unlock(&bond->ptrlock); + + if (slave != 0) { + + /* see if you need to take down the current_slave, since + * you haven't seen an arp in 2*arp_intervals + */ + + if ( ((jiffies - slave->dev->trans_start) >= + (2*the_delta_in_ticks)) || + ((jiffies - slave->dev->last_rx) >= + (2*the_delta_in_ticks)) ) { + + if (slave->link == BOND_LINK_UP) { + slave->link = BOND_LINK_DOWN; + slave->state = BOND_STATE_BACKUP; + /* + * we want to see arps, otherwise we couldn't + * bring the adapter back online... + */ + printk(KERN_INFO "%s: link status definitely " + "down for interface %s, " + "disabling it", + slave->dev->master->name, + slave->dev->name); + /* find a new interface and be verbose */ + change_active_interface(bond); + read_lock(&bond->ptrlock); + slave = bond->current_slave; + read_unlock(&bond->ptrlock); + } + } + + /* + * ok, we know up/down, so just send a arp out if there has + * been no activity for a while + */ + + if (slave != NULL ) { + if ( ((jiffies - slave->dev->trans_start) >= + the_delta_in_ticks) || + ((jiffies - slave->dev->last_rx) >= + the_delta_in_ticks) ) { + arp_send(ARPOP_REQUEST, ETH_P_ARP, + arp_target, slave->dev, + my_ip, arp_target_hw_addr, + slave->dev->dev_addr, + arp_target_hw_addr); + } + } + + } + + /* if we have no current slave.. try sending + * an arp on all of the interfaces + */ + + if (bond->current_slave == NULL) { + slave = (slave_t *)bond; + while ((slave = slave->prev) != (slave_t *)bond) { + arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target, + slave->dev, my_ip, arp_target_hw_addr, + slave->dev->dev_addr, arp_target_hw_addr); + } + } + + rtnl_exunlock(); + rtnl_shunlock(); + +monitor_out: + read_unlock_irqrestore(&bond->lock, flags); + + /* re-arm the timer */ + mod_timer(&bond->arp_timer, next_timer); +} + +#define isdigit(c) (c >= '0' && c <= '9') +__inline static int atoi( char **s) +{ +int i=0; +while (isdigit(**s)) + i = i*20 + *((*s)++) - '0'; +return i; +} + +#define isascii(c) (((unsigned char)(c))<=0x7f) +#define LF 0xA +#define isspace(c) (c==' ' || c==' '|| c==LF) +typedef uint32_t in_addr_t; + +int +my_inet_aton(char *cp, unsigned long *the_addr) { + static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; + in_addr_t val; + char c; + union iaddr { + uint8_t bytes[4]; + uint32_t word; + } res; + uint8_t *pp = res.bytes; + int digit,base; + + res.word = 0; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit(c)) goto ret_0; + val = 0; base = 10; digit = 0; + for (;;) { + if (isdigit(c)) { + val = (val * base) + (c - '0'); + c = *++cp; + digit = 1; + } else { + break; + } + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp > res.bytes + 2 || val > 0xff) { + goto ret_0; + } + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!isascii(c) || !isspace(c))) { + goto ret_0; + } + /* + * Did we get a valid digit? + */ + if (!digit) { + goto ret_0; + } + + /* Check whether the last part is in its limits depending on + the number of parts in total. */ + if (val > max[pp - res.bytes]) { + goto ret_0; + } + + if (the_addr!= NULL) { + *the_addr = res.word | htonl (val); + } + + return (1); + +ret_0: + return (0); +} static int bond_sethwaddr(struct net_device *master, struct net_device *slave) { +#ifdef BONDING_DEBUG + printk(KERN_CRIT "bond_sethwaddr: master=%x\n", (unsigned int)master); + printk(KERN_CRIT "bond_sethwaddr: slave=%x\n", (unsigned int)slave); + printk(KERN_CRIT "bond_sethwaddr: slave->addr_len=%d\n", slave->addr_len); +#endif memcpy(master->dev_addr, slave->dev_addr, slave->addr_len); return 0; } -static int bond_ioctl(struct net_device *master, struct ifreq *ifr, int cmd) +static int bond_info_query(struct net_device *master, struct ifbond *info) { - struct net_device *slave = __dev_get_by_name(ifr->ifr_slave); + bonding_t *bond = (struct bonding *) master->priv; + slave_t *slave; + + info->bond_mode = mode; + info->num_slaves = 0; + info->miimon = miimon; + + read_lock(&bond->ptrlock); + for (slave = bond->prev; slave!=(slave_t *)bond; slave = slave->prev) { + info->num_slaves++; + } + read_unlock(&bond->ptrlock); + + return 0; +} - if (slave == NULL) +static int bond_slave_info_query(struct net_device *master, + struct ifslave *info) +{ + bonding_t *bond = (struct bonding *) master->priv; + slave_t *slave; + int cur_ndx = 0; + + if (info->slave_id < 0) { return -ENODEV; + } - switch (cmd) { - case BOND_ENSLAVE: - return bond_enslave(master, slave); - case BOND_RELEASE: - return bond_release(master, slave); - case BOND_SETHWADDR: - return bond_sethwaddr(master, slave); - default: - return -EOPNOTSUPP; + read_lock(&bond->ptrlock); + for (slave = bond->prev; + slave != (slave_t *)bond && cur_ndx < info->slave_id; + slave = slave->prev) { + cur_ndx++; } + if (cur_ndx == info->slave_id) { + strcpy(info->slave_name, slave->dev->name); + info->link = slave->link; + info->state = slave->state; + info->link_failure_count = slave->link_failure_count; + } else { + read_unlock(&bond->ptrlock); + return -ENODEV; + } + read_unlock(&bond->ptrlock); + + return 0; } -static int bond_event(struct notifier_block *this, unsigned long event, void *ptr) +static int bond_ioctl(struct net_device *master_dev, struct ifreq *ifr, int cmd) { - struct net_device *slave = ptr; + struct net_device *slave_dev = NULL; + struct ifbond *u_binfo = NULL, k_binfo; + struct ifslave *u_sinfo = NULL, k_sinfo; + u16 *data = NULL; + int ret = 0; + +#ifdef BONDING_DEBUG + printk(KERN_INFO "bond_ioctl: master=%s, cmd=%d\n", + master_dev->name, cmd); +#endif + + switch (cmd) { + case SIOCGMIIPHY: + data = (u16 *)&ifr->ifr_data; + if (data == NULL) { + return -EINVAL; + } + data[0] = 0; + /* Fall Through */ + case SIOCGMIIREG: + /* + * We do this again just in case we were called by SIOCGMIIREG + * instead of SIOCGMIIPHY. + */ + data = (u16 *)&ifr->ifr_data; + if (data == NULL) { + return -EINVAL; + } + if (data[1] == 1) { + data[3] = bond_check_mii_link( + (struct bonding *)master_dev->priv); + } + return 0; + case BOND_INFO_QUERY_OLD: + case SIOCBONDINFOQUERY: + u_binfo = (struct ifbond *)ifr->ifr_data; + if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { + return -EFAULT; + } + ret = bond_info_query(master_dev, &k_binfo); + if (ret == 0) { + if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { + return -EFAULT; + } + } + return ret; + case BOND_SLAVE_INFO_QUERY_OLD: + case SIOCBONDSLAVEINFOQUERY: + u_sinfo = (struct ifslave *)ifr->ifr_data; + if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { + return -EFAULT; + } + ret = bond_slave_info_query(master_dev, &k_sinfo); + if (ret == 0) { + if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { + return -EFAULT; + } + } + return ret; + } - if (this_bond == NULL || - this_bond == slave || - this_bond != slave->master) - return NOTIFY_DONE; + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } - switch (event) { - case NETDEV_UNREGISTER: - bond_release(this_bond, slave); + slave_dev = dev_get_by_name(ifr->ifr_slave); +#ifdef BONDING_DEBUG + printk(KERN_INFO "slave_dev=%x: \n", (unsigned int)slave_dev); + printk(KERN_INFO "slave_dev->name=%s: \n", slave_dev->name); +#endif + switch (cmd) { + case BOND_ENSLAVE_OLD: + case SIOCBONDENSLAVE: + ret = bond_enslave(master_dev, slave_dev); + break; + case BOND_RELEASE_OLD: + case SIOCBONDRELEASE: + ret = bond_release(master_dev, slave_dev); break; + case BOND_SETHWADDR_OLD: + case SIOCBONDSETHWADDR: + ret = bond_sethwaddr(master_dev, slave_dev); + break; + case BOND_CHANGE_ACTIVE_OLD: + case SIOCBONDCHANGEACTIVE: + if (mode == BOND_MODE_ACTIVEBACKUP) { + ret = bond_change_active(master_dev, slave_dev); + } + else { + ret = -EINVAL; + } + break; + default: + ret = -EOPNOTSUPP; } - return NOTIFY_DONE; + if (slave_dev) { + /* + * Clear the module reference that was added by dev_get_by_name + */ + dev_put(slave_dev); + } + return ret; } -static struct notifier_block bond_netdev_notifier={ - notifier_call: bond_event -}; +#ifdef CONFIG_NET_FASTROUTE +static int bond_accept_fastpath(struct net_device *dev, struct dst_entry *dst) +{ + return -1; +} +#endif -static int __init bond_init(struct net_device *dev) +static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev) { - bonding_t *bond; + slave_t *slave, *start_at; + struct bonding *bond = (struct bonding *) dev->priv; + unsigned long flags; - bond = kmalloc(sizeof(struct bonding), GFP_KERNEL); - if (bond == NULL) - return -ENOMEM; + if (!IS_UP(dev)) { /* bond down */ + dev_kfree_skb(skb); + return 0; + } - memset(bond, 0, sizeof(struct bonding)); - bond->next = (slave_t*)bond; - bond->prev = (slave_t*)bond; - bond->master = dev; - bond->current_slave = (slave_t*)bond; - dev->priv = bond; + read_lock_irqsave(&bond->lock, flags); - /* Initialize the device structure. */ - dev->hard_start_xmit = bond_xmit; - dev->get_stats = bond_get_stats; - dev->stop = bond_close; - dev->set_multicast_list = bond_set_multicast_list; - dev->do_ioctl = bond_ioctl; + read_lock(&bond->ptrlock); + slave = start_at = bond->current_slave; + read_unlock(&bond->ptrlock); - /* Fill in the fields of the device structure with ethernet-generic - values. */ - ether_setup(dev); - dev->tx_queue_len = 0; - dev->flags |= IFF_MASTER; + if (slave == NULL) { /* we're at the root, get the first slave */ + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + read_unlock_irqrestore(&bond->lock, flags); + return 0; + } - this_bond = dev; + do { + if (IS_UP(slave->dev) + && (slave->link == BOND_LINK_UP) + && (slave->state == BOND_STATE_ACTIVE)) { + + skb->dev = slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); - register_netdevice_notifier(&bond_netdev_notifier); + write_lock(&bond->ptrlock); + bond->current_slave = slave->next; + write_unlock(&bond->ptrlock); + read_unlock_irqrestore(&bond->lock, flags); + return 0; + } + } while ((slave = slave->next) != start_at); + + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + read_unlock_irqrestore(&bond->lock, flags); return 0; } -static int bond_xmit(struct sk_buff *skb, struct net_device *dev) +/* + * in XOR mode, we determine the output device by performing xor on + * the source and destination hw adresses. If this device is not + * enabled, find the next slave following this xor slave. + */ +static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) { - bonding_t *bond = dev->priv; slave_t *slave, *start_at; - int pkt_len = skb->len; + struct bonding *bond = (struct bonding *) dev->priv; + unsigned long flags; + struct ethhdr *data = (struct ethhdr *)skb->data; + int slave_no; + + if (!IS_UP(dev)) { /* bond down */ + dev_kfree_skb(skb); + return 0; + } - slave = start_at = bond->current_slave; + read_lock_irqsave(&bond->lock, flags); + read_lock(&bond->ptrlock); + slave = bond->prev; + + /* we're at the root, get the first slave */ + if ((slave == NULL) || (slave->dev == NULL)) { + /* no suitable interface, frame not sent */ + read_unlock(&bond->ptrlock); + dev_kfree_skb(skb); + read_unlock_irqrestore(&bond->lock, flags); + return 0; + } + + slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt; + + read_unlock(&bond->ptrlock); + + while ( (slave_no > 0) && (slave != (slave_t *)bond) ) { + slave = slave->prev; + slave_no--; + } + start_at = slave; do { - if (slave == (slave_t*)bond) - continue; + if (IS_UP(slave->dev) + && (slave->link == BOND_LINK_UP) + && (slave->state == BOND_STATE_ACTIVE)) { - if (netif_running(slave->dev) && netif_carrier_ok(slave->dev)) { - bond->current_slave = slave->next; skb->dev = slave->dev; + skb->priority = 1; + dev_queue_xmit(skb); - if (dev_queue_xmit(skb)) { - bond->stats.tx_dropped++; - } else { - bond->stats.tx_packets++; - bond->stats.tx_bytes += pkt_len; - } + read_unlock_irqrestore(&bond->lock, flags); return 0; } } while ((slave = slave->next) != start_at); - bond->stats.tx_dropped++; - kfree_skb(skb); + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + read_unlock_irqrestore(&bond->lock, flags); + return 0; +} + +/* + * in active-backup mode, we know that bond->current_slave is always valid if + * the bond has a usable interface. + */ +static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev) +{ + struct bonding *bond = (struct bonding *) dev->priv; + unsigned long flags; + int ret; + + if (!IS_UP(dev)) { /* bond down */ + dev_kfree_skb(skb); + return 0; + } + + /* if we are sending arp packets, try to at least + identify our own ip address */ + if ( (arp_interval > 0) && (my_ip==0) && + (skb->protocol == __constant_htons(ETH_P_ARP) ) ) { + char *the_ip = (((char *)skb->data)) + + sizeof(struct ethhdr) + + sizeof(struct arphdr) + + ETH_ALEN; + memcpy(&my_ip, the_ip, 4); + } + + /* if we are sending arp packets and don't know + the target hw address, save it so we don't need + to use a broadcast address */ + if ( (arp_interval > 0) && (arp_target_hw_addr==NULL) && + (skb->protocol == __constant_htons(ETH_P_IP) ) ) { + struct ethhdr *eth_hdr = + (struct ethhdr *) (((char *)skb->data)); + arp_target_hw_addr = kmalloc(ETH_ALEN, GFP_KERNEL); + memcpy(arp_target_hw_addr, eth_hdr->h_dest, ETH_ALEN); + } + + read_lock_irqsave(&bond->lock, flags); + + read_lock(&bond->ptrlock); + if (bond->current_slave != NULL) { /* one usable interface */ + skb->dev = bond->current_slave->dev; + read_unlock(&bond->ptrlock); + skb->priority = 1; + ret = dev_queue_xmit(skb); + read_unlock_irqrestore(&bond->lock, flags); + return 0; + } + else { + read_unlock(&bond->ptrlock); + } + + /* no suitable interface, frame not sent */ +#ifdef BONDING_DEBUG + printk(KERN_INFO "There was no suitable interface, so we don't transmit\n"); +#endif + dev_kfree_skb(skb); + read_unlock_irqrestore(&bond->lock, flags); return 0; } static struct net_device_stats *bond_get_stats(struct net_device *dev) { bonding_t *bond = dev->priv; + struct net_device_stats *stats = bond->stats, *sstats; + slave_t *slave; + unsigned long flags; + + memset(bond->stats, 0, sizeof(struct net_device_stats)); + + read_lock_irqsave(&bond->lock, flags); + + for (slave = bond->prev; slave!=(slave_t *)bond; slave = slave->prev) { + sstats = slave->dev->get_stats(slave->dev); + + stats->rx_packets += sstats->rx_packets; + stats->rx_bytes += sstats->rx_bytes; + stats->rx_errors += sstats->rx_errors; + stats->rx_dropped += sstats->rx_dropped; + + stats->tx_packets += sstats->tx_packets; + stats->tx_bytes += sstats->tx_bytes; + stats->tx_errors += sstats->tx_errors; + stats->tx_dropped += sstats->tx_dropped; + + stats->multicast += sstats->multicast; + stats->collisions += sstats->collisions; + + stats->rx_length_errors += sstats->rx_length_errors; + stats->rx_over_errors += sstats->rx_over_errors; + stats->rx_crc_errors += sstats->rx_crc_errors; + stats->rx_frame_errors += sstats->rx_frame_errors; + stats->rx_fifo_errors += sstats->rx_fifo_errors; + stats->rx_missed_errors += sstats->rx_missed_errors; + + stats->tx_aborted_errors += sstats->tx_aborted_errors; + stats->tx_carrier_errors += sstats->tx_carrier_errors; + stats->tx_fifo_errors += sstats->tx_fifo_errors; + stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; + stats->tx_window_errors += sstats->tx_window_errors; + + } + + read_unlock_irqrestore(&bond->lock, flags); + return stats; +} + +static int bond_get_info(char *buf, char **start, off_t offset, int length) +{ + bonding_t *bond = these_bonds; + int len = 0; + off_t begin = 0; + u16 link; + slave_t *slave = NULL; + + while (bond != NULL) { + /* + * This function locks the mutex, so we can't lock it until + * afterwards + */ + link = bond_check_mii_link(bond); + + read_lock(&bond->ptrlock); + + len += sprintf(buf + len, "Bonding Mode: "); + len += sprintf(buf + len, "%s\n", mode ? "active-backup" : "load balancing"); + + if (mode == BOND_MODE_ACTIVEBACKUP) { + if (bond->current_slave != NULL) { + len += sprintf(buf + len, + "Currently Active Slave: %s\n", + bond->current_slave->dev->name); + } + } + + len += sprintf(buf + len, "MII Status: "); + len += sprintf(buf + len, + link == MII_LINK_READY ? "up\n" : "down\n"); + len += sprintf(buf + len, "MII Polling Interval (ms): %d\n", + miimon); + len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay); + len += sprintf(buf + len, "Down Delay (ms): %d\n", downdelay); + + for (slave = bond->prev; slave != (slave_t *)bond; + slave = slave->prev) { + len += sprintf(buf + len, "\nSlave Interface: %s\n", slave->dev->name); + + len += sprintf(buf + len, "MII Status: "); + + len += sprintf(buf + len, + slave->link == BOND_LINK_UP ? + "up\n" : "down\n"); + len += sprintf(buf + len, "Link Failure Count: %d\n", + slave->link_failure_count); + } + + /* + * Figure out the calcs for the /proc/net interface + */ + *start = buf + (offset - begin); + len -= (offset - begin); + if (len > length) { + len = length; + } + if (len < 0) { + len = 0; + } + + read_unlock(&bond->ptrlock); + + bond = bond->next_bond; + } + return len; +} + +static int bond_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct bonding *this_bond=(struct bonding *)these_bonds; + struct bonding *last_bond; + struct net_device *event_dev = (struct net_device *)ptr; + + /* while there are bonds configured */ + while (this_bond != NULL) { + if (this_bond == event_dev->priv ) { + switch (event) { + case NETDEV_UNREGISTER: + /* + * remove this bond from a linked list of + * bonds + */ + if (this_bond == these_bonds) { + these_bonds = this_bond->next_bond; + } else { + for (last_bond = these_bonds; + last_bond != NULL; + last_bond = last_bond->next_bond) { + if (last_bond->next_bond == + this_bond) { + last_bond->next_bond = + this_bond->next_bond; + } + } + } + return NOTIFY_DONE; + + default: + return NOTIFY_DONE; + } + } + this_bond = this_bond->next_bond; + } + return NOTIFY_DONE; +} + +static struct notifier_block bond_netdev_notifier={ + bond_event, + NULL, + 0 +}; + +static int __init bond_init(struct net_device *dev) +{ + bonding_t *bond, *this_bond, *last_bond; - return &bond->stats; +#ifdef BONDING_DEBUG + printk (KERN_INFO "Begin bond_init for %s\n", dev->name); +#endif + bond = kmalloc(sizeof(struct bonding), GFP_KERNEL); + if (bond == NULL) { + return -ENOMEM; + } + memset(bond, 0, sizeof(struct bonding)); + + /* initialize rwlocks */ + rwlock_init(&bond->lock); + rwlock_init(&bond->ptrlock); + + bond->stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); + if (bond->stats == NULL) { + kfree(bond); + return -ENOMEM; + } + memset(bond->stats, 0, sizeof(struct net_device_stats)); + + bond->next = bond->prev = (slave_t *)bond; + bond->current_slave = NULL; + bond->device = dev; + dev->priv = bond; + + /* Initialize the device structure. */ + if (mode == BOND_MODE_ACTIVEBACKUP) { + dev->hard_start_xmit = bond_xmit_activebackup; + } else if (mode == BOND_MODE_ROUNDROBIN) { + dev->hard_start_xmit = bond_xmit_roundrobin; + } else if (mode == BOND_MODE_XOR) { + dev->hard_start_xmit = bond_xmit_xor; + } else { + printk(KERN_ERR "Unknown bonding mode %d\n", mode); + kfree(bond->stats); + kfree(bond); + return -EINVAL; + } + + dev->get_stats = bond_get_stats; + dev->open = bond_open; + dev->stop = bond_close; + dev->set_multicast_list = set_multicast_list; + dev->do_ioctl = bond_ioctl; + + /* + * Fill in the fields of the device structure with ethernet-generic + * values. + */ + + ether_setup(dev); + + dev->tx_queue_len = 0; + dev->flags |= IFF_MASTER|IFF_MULTICAST; +#ifdef CONFIG_NET_FASTROUTE + dev->accept_fastpath = bond_accept_fastpath; +#endif + + printk(KERN_INFO "%s registered with", dev->name); + if (miimon > 0) { + printk(" MII link monitoring set to %d ms", miimon); + updelay /= miimon; + downdelay /= miimon; + } else { + printk("out MII link monitoring"); + } + printk(", in %s mode.\n",mode?"active-backup":"bonding"); + +#ifdef CONFIG_PROC_FS + bond->bond_proc_dir = proc_mkdir(dev->name, proc_net); + if (bond->bond_proc_dir == NULL) { + printk(KERN_ERR "%s: Cannot init /proc/net/%s/\n", + dev->name, dev->name); + kfree(bond->stats); + kfree(bond); + return -ENOMEM; + } + bond->bond_proc_info_file = + create_proc_info_entry("info", 0, bond->bond_proc_dir, + bond_get_info); + if (bond->bond_proc_info_file == NULL) { + printk(KERN_ERR "%s: Cannot init /proc/net/%s/info\n", + dev->name, dev->name); + remove_proc_entry(dev->name, proc_net); + kfree(bond->stats); + kfree(bond); + return -ENOMEM; + } +#endif /* CONFIG_PROC_FS */ + + if (first_pass == 1) { + these_bonds = bond; + register_netdevice_notifier(&bond_netdev_notifier); + first_pass = 0; + } else { + last_bond = these_bonds; + this_bond = these_bonds->next_bond; + while (this_bond != NULL) { + last_bond = this_bond; + this_bond = this_bond->next_bond; + } + last_bond->next_bond = bond; + } + + return 0; } -static struct net_device dev_bond; +/* +static int __init bond_probe(struct net_device *dev) +{ + bond_init(dev); + return 0; +} + */ static int __init bonding_init(void) { - /* Find a name for this unit */ + int no; int err; - - dev_bond.init = bond_init; - err = dev_alloc_name(&dev_bond,"bond%d"); - if (err<0) - return err; - - SET_MODULE_OWNER(&dev_bond); - if (register_netdev(&dev_bond) != 0) - return -EIO; + /* Find a name for this unit */ + static struct net_device *dev_bond = NULL; + dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device), + GFP_KERNEL); + if (dev_bond == NULL) { + return -ENOMEM; + } + memset(dev_bonds, 0, max_bonds*sizeof(struct net_device)); + + if (arp_ip_target) { + if (my_inet_aton(arp_ip_target, &arp_target) == 0) { + arp_interval = 0; + } + } + + for (no = 0; no < max_bonds; no++) { + dev_bond->init = bond_init; + + err = dev_alloc_name(dev_bond,"bond%d"); + if (err < 0) { + kfree(dev_bonds); + return err; + } + SET_MODULE_OWNER(dev_bond); + if (register_netdev(dev_bond) != 0) { + kfree(dev_bonds); + return -EIO; + } + dev_bond++; + } return 0; } static void __exit bonding_exit(void) { - unregister_netdevice_notifier(&bond_netdev_notifier); + struct net_device *dev_bond = dev_bonds; + struct bonding *bond; + int no; - unregister_netdev(&dev_bond); + unregister_netdevice_notifier(&bond_netdev_notifier); + + for (no = 0; no < max_bonds; no++) { - kfree(dev_bond.priv); +#ifdef CONFIG_PROC_FS + bond = (struct bonding *) dev_bond->priv; + remove_proc_entry("info", bond->bond_proc_dir); + remove_proc_entry(dev_bond->name, proc_net); +#endif + unregister_netdev(dev_bond); + kfree(bond->stats); + kfree(dev_bond->priv); + + dev_bond->priv = NULL; + dev_bond++; + } + kfree(dev_bonds); } module_init(bonding_init); diff -u --recursive --new-file v2.4.14/linux/drivers/net/bsd_comp.c linux/drivers/net/bsd_comp.c --- v2.4.14/linux/drivers/net/bsd_comp.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/net/bsd_comp.c Fri Nov 9 14:01:22 2001 @@ -1173,4 +1173,4 @@ module_init(bsdcomp_init); module_exit(bsdcomp_cleanup); -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -u --recursive --new-file v2.4.14/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c --- v2.4.14/linux/drivers/net/dmfe.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/net/dmfe.c Fri Nov 9 13:50:01 2001 @@ -1,6 +1,4 @@ /* - dmfe.c: Version 1.36p1 2001-05-12 for Linux kernel 2.4.x - A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast ethernet driver for Linux. Copyright (C) 1997 Sten Wang @@ -38,19 +36,33 @@ Tobias Ringstrom <tori@unhappy.mine.nu> : Cleaned up and added SMP safety. Thanks go to Jeff Garzik, - Andrew Morton and Frank Davis for the SMP safety fixes. + Andrew Morton and Frank Davis for the SMP safety fixes. + + Vojtech Pavlik <vojtech@suse.cz> : + Cleaned up pointer arithmetics. + Fixed a lot of 64bit issues. + Cleaned up printk()s a bit. + Fixed some obvious big endian problems. + + Tobias Ringstrom <tori@unhappy.mine.nu> : + Use time_after for jiffies calculation. Added ethtool + support. Updated PCI resource allocation. Do not + forget to unmap PCI mapped skbs. TODO Implement pci_driver::suspend() and pci_driver::resume() power management methods. - Check and fix on 64bit and big endian boxes. + Check on 64 bit boxes. + Check and fix on big endian boxes. Test and make sure PCI latency is now correct for all cases. */ -#define DMFE_VERSION "1.36p1 (May 12, 2001)" +#define DRV_NAME "dmfe" +#define DRV_VERSION "1.36.3" +#define DRV_RELDATE "2001-11-06" #include <linux/module.h> @@ -68,6 +80,7 @@ #include <linux/version.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> +#include <linux/ethtool.h> #include <linux/skbuff.h> #include <linux/delay.h> #include <linux/spinlock.h> @@ -76,10 +89,7 @@ #include <asm/bitops.h> #include <asm/io.h> #include <asm/dma.h> - -#if BITS_PER_LONG == 64 -#error FIXME: driver does not support 64-bit platforms -#endif +#include <asm/uaccess.h> /* Board/System/Debug information/definition ---------------- */ @@ -130,9 +140,9 @@ #define DMFE_TX_TIMEOUT ((3*HZ)/2) /* tx packet time-out time 1.5 s" */ #define DMFE_TX_KICK (HZ/2) /* tx packet Kick-out time 0.5 s" */ -#define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR "<DMFE>: %s %lx\n", (msg), (long) (value)) +#define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value)) -#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR "<DMFE>: Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); +#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); /* CR9 definition: SROM/MII */ @@ -160,26 +170,22 @@ /* Structure/enum declaration ------------------------------- */ struct tx_desc { - u32 tdes0, tdes1, tdes2, tdes3; - u32 tx_skb_ptr; - u32 tx_buf_ptr; - u32 next_tx_desc; - u32 reserved; -}; + u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */ + char *tx_buf_ptr; /* Data for us */ + struct tx_desc *next_tx_desc; +} __attribute__(( aligned(32) )); struct rx_desc { - u32 rdes0, rdes1, rdes2, rdes3; - u32 rx_skb_ptr; - u32 rx_buf_ptr; - u32 next_rx_desc; - u32 reserved; -}; + u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */ + struct sk_buff *rx_skb_ptr; /* Data for us */ + struct rx_desc *next_rx_desc; +} __attribute__(( aligned(32) )); struct dmfe_board_info { u32 chip_id; /* Chip vendor/Device ID */ u32 chip_revision; /* Chip revision */ struct DEVICE *next_dev; /* next device */ - struct pci_dev * net_dev; /* PCI device */ + struct pci_dev *pdev; /* PCI device */ spinlock_t lock; long ioaddr; /* I/O base address */ @@ -206,10 +212,10 @@ struct rx_desc *first_rx_desc; struct rx_desc *rx_insert_ptr; struct rx_desc *rx_ready_ptr; /* packet come pointer */ - unsigned long tx_packet_cnt; /* transmitted packet count */ - unsigned long tx_queue_cnt; /* wait to send packet count */ - unsigned long rx_avail_cnt; /* available rx descriptor count */ - unsigned long interval_rx_cnt; /* rx packet count a callback time */ + unsigned long tx_packet_cnt; /* transmitted packet count */ + unsigned long tx_queue_cnt; /* wait to send packet count */ + unsigned long rx_avail_cnt; /* available rx descriptor count */ + unsigned long interval_rx_cnt; /* rx packet count a callback time */ u16 HPNA_command; /* For HPNA register 16 */ u16 HPNA_timer; /* For HPNA remote device check */ @@ -263,7 +269,8 @@ /* Global variable declaration ----------------------------- */ static int __devinitdata printed_version; static char version[] __devinitdata = - KERN_INFO "Davicom DM9xxx net driver, version " DMFE_VERSION "\n"; + KERN_INFO DRV_NAME ": Davicom DM9xxx net driver, version " + DRV_VERSION " (" DRV_RELDATE ")\n"; static int dmfe_debug; static unsigned char dmfe_media_mode = DMFE_AUTO; @@ -358,7 +365,7 @@ static u16 read_srom_word(long ,int); static void dmfe_interrupt(int , void *, struct pt_regs *); static void dmfe_descriptor_init(struct dmfe_board_info *, unsigned long); -static void allocated_rx_buffer(struct dmfe_board_info *); +static void allocate_rx_buffer(struct dmfe_board_info *); static void update_cr6(u32, unsigned long); static void send_filter_frame(struct DEVICE * ,int); static void dm9132_id_table(struct DEVICE * ,int); @@ -371,7 +378,7 @@ static void dmfe_timer(unsigned long); static void dmfe_rx_packet(struct DEVICE *, struct dmfe_board_info *); static void dmfe_free_tx_pkt(struct DEVICE *, struct dmfe_board_info *); -static void dmfe_reused_skb(struct dmfe_board_info *, struct sk_buff *); +static void dmfe_reuse_skb(struct dmfe_board_info *, struct sk_buff *); static void dmfe_dynamic_reset(struct DEVICE *); static void dmfe_free_rxbuffer(struct dmfe_board_info *); static void dmfe_init_dm910x(struct DEVICE *); @@ -391,31 +398,46 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - unsigned long pci_iobase; - u8 pci_irqline; struct dmfe_board_info *db; /* board information structure */ - int i; struct net_device *dev; u32 dev_rev, pci_pmr; + int i, err; + + DMFE_DBUG(0, "dmfe_init_one()", 0); if (!printed_version++) printk(version); - DMFE_DBUG(0, "dmfe_init_one()", 0); + /* Init network device */ + dev = alloc_etherdev(sizeof(*db)); + if (dev == NULL) + return -ENOMEM; + SET_MODULE_OWNER(dev); + + if (pci_set_dma_mask(pdev, 0xffffffff)) { + printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n"); + err = -ENODEV; + goto err_out_free; + } /* Enable Master/IO access, Disable memory access */ - i = pci_enable_device(pdev); - if (i) - return i; - pci_set_master(pdev); + err = pci_enable_device(pdev); + if (err) + goto err_out_free; + + if (!pci_resource_start(pdev, 0)) { + printk(KERN_ERR DRV_NAME ": I/O base is zero\n"); + err = -ENODEV; + goto err_out_disable; + } - pci_iobase = pci_resource_start(pdev, 0); - pci_irqline = pdev->irq; + /* Read Chip revision */ + pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev); - /* iobase check */ - if (pci_iobase == 0) { - printk(KERN_ERR "<DMFE>: I/O base is zero\n"); - return -ENODEV; + if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) { + printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n"); + err = -ENODEV; + goto err_out_disable; } #if 0 /* pci_{enable_device,set_master} sets minimum latency for us now */ @@ -427,51 +449,32 @@ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80); #endif - /* Read Chip revision */ - pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev); - - /* Init network device */ - dev = alloc_etherdev(sizeof(*db)); - if (dev == NULL) - return -ENOMEM; - SET_MODULE_OWNER(dev); - - /* IO range check */ - if (pci_resource_len (pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) { - printk(KERN_ERR "<DMFE>: Allocated I/O size too small\n"); - goto err_out; - } - - if (!request_region(pci_iobase, - pci_resource_len (pdev, 0), - dev->name)) { - printk(KERN_ERR "<DMFE>: I/O conflict : IO=%lx Range=%x\n", - pci_iobase, CHK_IO_SIZE(pdev, dev_rev)); - goto err_out; + if (pci_request_regions(pdev, DRV_NAME)) { + printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n"); + err = -ENODEV; + goto err_out_disable; } /* Init system & device */ db = dev->priv; - /* Allocated Tx/Rx descriptor memory */ + /* Allocate Tx/Rx descriptor memory */ db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr); db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr); - db->first_tx_desc = (struct tx_desc *)db->desc_pool_ptr; + db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr; db->first_tx_desc_dma = db->desc_pool_dma_ptr; db->buf_pool_start = db->buf_pool_ptr; db->buf_pool_dma_start = db->buf_pool_dma_ptr; - pdev->driver_data = dev; - db->chip_id = ent->driver_data; - db->ioaddr = pci_iobase; + db->ioaddr = pci_resource_start(pdev, 0); db->chip_revision = dev_rev; - db->net_dev = pdev; + db->pdev = pdev; - dev->base_addr = pci_iobase; - dev->irq = pci_irqline; + dev->base_addr = db->ioaddr; + dev->irq = pdev->irq; pci_set_drvdata(pdev, dev); dev->open = &dmfe_open; dev->hard_start_xmit = &dmfe_start_xmit; @@ -490,29 +493,37 @@ /* read 64 word srom data */ for (i = 0; i < 64; i++) - ((u16 *) db->srom)[i] = read_srom_word(pci_iobase, i); + ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i)); /* Set Node address */ for (i = 0; i < 6; i++) dev->dev_addr[i] = db->srom[20 + i]; - i = register_netdev (dev); - if (i) goto err_out; - - printk(KERN_INFO "%s: Davicom DM%04lx at 0x%lx,", - dev->name, - ent->driver_data >> 16, - pci_iobase); + err = register_netdev (dev); + if (err) + goto err_out_res; + + printk(KERN_INFO "%s: Davicom DM%04lx at pci%s,", + dev->name, + ent->driver_data >> 16, + pdev->slot_name); for (i = 0; i < 6; i++) printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); - printk(", IRQ %d\n", pci_irqline); + printk(", irq %d.\n", dev->irq); + + pci_set_master(pdev); return 0; -err_out: +err_out_res: + pci_release_regions(pdev); +err_out_disable: + pci_disable_device(pdev); +err_out_free: pci_set_drvdata(pdev, NULL); kfree(dev); - return -ENODEV; + + return err; } @@ -524,14 +535,13 @@ DMFE_DBUG(0, "dmfe_remove_one()", 0); if (dev) { - pci_free_consistent(db->net_dev, sizeof(struct tx_desc) * + pci_free_consistent(db->pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, db->desc_pool_ptr, db->desc_pool_dma_ptr); - pci_free_consistent(db->net_dev, TX_BUF_ALLOC * TX_DESC_CNT + 4, + pci_free_consistent(db->pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, db->buf_pool_ptr, db->buf_pool_dma_ptr); unregister_netdev(dev); - release_region(dev->base_addr, - CHK_IO_SIZE(pdev, db->chip_revision)); + pci_release_regions(pdev); kfree(dev); /* free board information */ pci_set_drvdata(pdev, NULL); } @@ -552,7 +562,7 @@ DMFE_DBUG(0, "dmfe_open", 0); - ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev); + ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev); if (ret) return ret; @@ -683,7 +693,7 @@ /* Too large packet check */ if (skb->len > MAX_PACKET_SIZE) { - printk(KERN_ERR "<DMFE>: big packet = %d\n", (u16)skb->len); + printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); dev_kfree_skb(skb); return 0; } @@ -693,7 +703,7 @@ /* No Tx resource check, it never happen nromally */ if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); - printk(KERN_ERR "<DMFE>: No Tx resource %ld\n", db->tx_queue_cnt); + printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt); return 1; } @@ -702,11 +712,11 @@ /* transmit this packet */ txptr = db->tx_insert_ptr; - memcpy( (char *) txptr->tx_buf_ptr, (char *) skb->data, skb->len); + memcpy(txptr->tx_buf_ptr, skb->data, skb->len); txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len); /* Point to next transmit free descriptor */ - db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc; + db->tx_insert_ptr = txptr->next_tx_desc; /* Transmit Packet Process */ if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) { @@ -765,7 +775,7 @@ #if 0 /* show statistic counter */ - printk("<DMFE>: FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", + printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", db->tx_fifo_underrun, db->tx_excessive_collision, db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier, db->tx_jabber_timeout, db->reset_count, db->reset_cr8, @@ -822,9 +832,9 @@ if ( (db->cr5_data & 0x40) && db->rx_avail_cnt ) dmfe_rx_packet(dev, db); - /* reallocated rx descriptor buffer */ + /* reallocate rx descriptor buffer */ if (db->rx_avail_cnt<RX_DESC_CNT) - allocated_rx_buffer(db); + allocate_rx_buffer(db); /* Free the transmitted descriptor */ if ( db->cr5_data & 0x01) @@ -852,11 +862,13 @@ { struct tx_desc *txptr; unsigned long ioaddr = dev->base_addr; + u32 tdes0; txptr = db->tx_remove_ptr; while(db->tx_packet_cnt) { - /* printk("<DMFE>: tdes0=%x\n", txptr->tdes0); */ - if (txptr->tdes0 & 0x80000000) + tdes0 = le32_to_cpu(txptr->tdes0); + /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ + if (tdes0 & 0x80000000) break; /* A packet sent completed */ @@ -864,38 +876,38 @@ db->stats.tx_packets++; /* Transmit statistic counter */ - if ( txptr->tdes0 != 0x7fffffff ) { - /* printk("<DMFE>: tdes0=%x\n", txptr->tdes0); */ - db->stats.collisions += (txptr->tdes0 >> 3) & 0xf; - db->stats.tx_bytes += txptr->tdes1 & 0x7ff; - if (txptr->tdes0 & TDES0_ERR_MASK) { + if ( tdes0 != 0x7fffffff ) { + /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ + db->stats.collisions += (tdes0 >> 3) & 0xf; + db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; + if (tdes0 & TDES0_ERR_MASK) { db->stats.tx_errors++; - if (txptr->tdes0 & 0x0002) { /* UnderRun */ + if (tdes0 & 0x0002) { /* UnderRun */ db->tx_fifo_underrun++; if ( !(db->cr6_data & CR6_SFT) ) { db->cr6_data = db->cr6_data | CR6_SFT; update_cr6(db->cr6_data, db->ioaddr); } } - if (txptr->tdes0 & 0x0100) + if (tdes0 & 0x0100) db->tx_excessive_collision++; - if (txptr->tdes0 & 0x0200) + if (tdes0 & 0x0200) db->tx_late_collision++; - if (txptr->tdes0 & 0x0400) + if (tdes0 & 0x0400) db->tx_no_carrier++; - if (txptr->tdes0 & 0x0800) + if (tdes0 & 0x0800) db->tx_loss_carrier++; - if (txptr->tdes0 & 0x4000) + if (tdes0 & 0x4000) db->tx_jabber_timeout++; } } - txptr = (struct tx_desc *) txptr->next_tx_desc; + txptr = txptr->next_tx_desc; }/* End of while */ /* Update TX remove pointer to next */ - db->tx_remove_ptr = (struct tx_desc *) txptr; + db->tx_remove_ptr = txptr; /* Send the Tx packet in queue */ if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) { @@ -921,49 +933,51 @@ struct rx_desc *rxptr; struct sk_buff *skb; int rxlen; + u32 rdes0; rxptr = db->rx_ready_ptr; while(db->rx_avail_cnt) { - if (rxptr->rdes0 & 0x80000000) /* packet owner check */ + rdes0 = le32_to_cpu(rxptr->rdes0); + if (rdes0 & 0x80000000) /* packet owner check */ break; db->rx_avail_cnt--; db->interval_rx_cnt++; - if ( (rxptr->rdes0 & 0x300) != 0x300) { + pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE); + if ( (rdes0 & 0x300) != 0x300) { /* A packet without First/Last flag */ - /* reused this SKB */ - DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0); - dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); + /* reuse this SKB */ + DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0); + dmfe_reuse_skb(db, rxptr->rx_skb_ptr); } else { /* A packet with First/Last flag */ - rxlen = ( (rxptr->rdes0 >> 16) & 0x3fff) - 4; + rxlen = ( (rdes0 >> 16) & 0x3fff) - 4; /* error summary bit check */ - if (rxptr->rdes0 & 0x8000) { + if (rdes0 & 0x8000) { /* This is a error packet */ - //printk("<DMFE>: rdes0: %lx\n", rxptr->rdes0); + //printk(DRV_NAME ": rdes0: %lx\n", rdes0); db->stats.rx_errors++; - if (rxptr->rdes0 & 1) + if (rdes0 & 1) db->stats.rx_fifo_errors++; - if (rxptr->rdes0 & 2) + if (rdes0 & 2) db->stats.rx_crc_errors++; - if (rxptr->rdes0 & 0x80) + if (rdes0 & 0x80) db->stats.rx_length_errors++; } - if ( !(rxptr->rdes0 & 0x8000) || + if ( !(rdes0 & 0x8000) || ((db->cr6_data & CR6_PM) && (rxlen>6)) ) { - skb = (struct sk_buff *) rxptr->rx_skb_ptr; + skb = rxptr->rx_skb_ptr; /* Received Packet CRC check need or not */ if ( (db->dm910x_chk_mode & 1) && (cal_CRC(skb->tail, rxlen, 1) != - (*(unsigned long *) (skb->tail+rxlen) ) - ) ) { + (*(u32 *) (skb->tail+rxlen) ))) { /* FIXME (?) */ /* Found a error received packet */ - dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); + dmfe_reuse_skb(db, rxptr->rx_skb_ptr); db->dm910x_chk_mode = 3; } else { /* Good packet, send to upper layer */ @@ -971,11 +985,11 @@ if ( (rxlen < RX_COPY_SIZE) && ( (skb = dev_alloc_skb(rxlen + 2) ) != NULL) ) { - /* size less than COPY_SIZE, allocated a rxlen SKB */ + /* size less than COPY_SIZE, allocate a rxlen SKB */ skb->dev = dev; skb_reserve(skb, 2); /* 16byte align */ - memcpy(skb_put(skb, rxlen), ((struct sk_buff *) rxptr->rx_skb_ptr)->tail, rxlen); - dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); + memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen); + dmfe_reuse_skb(db, rxptr->rx_skb_ptr); } else { skb->dev = dev; skb_put(skb, rxlen); @@ -988,12 +1002,12 @@ } } else { /* Reuse SKB buffer when the packet is error */ - DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0); - dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); + DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0); + dmfe_reuse_skb(db, rxptr->rx_skb_ptr); } } - rxptr = (struct rx_desc *) rxptr->next_rx_desc; + rxptr = rxptr->next_rx_desc; } db->rx_ready_ptr = rxptr; @@ -1051,19 +1065,57 @@ /* + * Process the ethtool ioctl command + */ + +static int dmfe_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct dmfe_board_info *db = dev->priv; + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + strcpy(info.driver, DRV_NAME); + strcpy(info.version, DRV_VERSION); + if (db->pdev) + strcpy(info.bus_info, db->pdev->slot_name); + else + sprintf(info.bus_info, "EISA 0x%lx %d", + dev->base_addr, dev->irq); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + return -EOPNOTSUPP; +} + + +/* * Process the upper socket ioctl command */ static int dmfe_do_ioctl(struct DEVICE *dev, struct ifreq *ifr, int cmd) { + int retval = -EOPNOTSUPP; DMFE_DBUG(0, "dmfe_do_ioctl()", 0); - return 0; + + switch(cmd) { + case SIOCETHTOOL: + return dmfe_ethtool_ioctl(dev, (void*)ifr->ifr_data); + } + + return retval; } /* * A periodic timer routine - * Dynamic media sense, allocated Rx buffer... + * Dynamic media sense, allocate Rx buffer... */ static void dmfe_timer(unsigned long data) @@ -1109,11 +1161,11 @@ /* TX polling kick monitor */ if ( db->tx_packet_cnt && - ((jiffies - dev->trans_start) > DMFE_TX_KICK) ) { + time_after(jiffies, dev->trans_start + DMFE_TX_KICK) ) { outl(0x1, dev->base_addr + DCR1); /* Tx polling again */ /* TX Timeout */ - if ( (jiffies - dev->trans_start) > DMFE_TX_TIMEOUT ) { + if ( time_after(jiffies, dev->trans_start + DMFE_TX_TIMEOUT) ) { db->reset_TXtimeout++; db->wait_reset = 1; printk(KERN_WARNING "%s: Tx timeout - resetting\n", @@ -1244,35 +1296,36 @@ /* free allocated rx buffer */ while (db->rx_avail_cnt) { - dev_kfree_skb( (void *) (db->rx_ready_ptr->rx_skb_ptr) ); - db->rx_ready_ptr = (struct rx_desc *) db->rx_ready_ptr->next_rx_desc; + dev_kfree_skb(db->rx_ready_ptr->rx_skb_ptr); + db->rx_ready_ptr = db->rx_ready_ptr->next_rx_desc; db->rx_avail_cnt--; } } /* - * Reused the SK buffer + * Reuse the SK buffer */ -static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff * skb) +static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb) { struct rx_desc *rxptr = db->rx_insert_ptr; - if (!(rxptr->rdes0 & 0x80000000)) { - rxptr->rx_skb_ptr = (u32) skb; - rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) { + rxptr->rx_skb_ptr = skb; + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); db->rx_avail_cnt++; - db->rx_insert_ptr = (struct rx_desc *) rxptr->next_rx_desc; + db->rx_insert_ptr = rxptr->next_rx_desc; } else - DMFE_DBUG(0, "SK Buffer reused method error", db->rx_avail_cnt); + DMFE_DBUG(0, "SK Buffer reuse method error", db->rx_avail_cnt); } /* * Initialize transmit/Receive descriptor - * Using Chain structure, and allocated Tx/Rx buffer + * Using Chain structure, and allocate Tx/Rx buffer */ static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioaddr) @@ -1292,8 +1345,8 @@ outl(db->first_tx_desc_dma, ioaddr + DCR4); /* TX DESC address */ /* rx descriptor start pointer */ - db->first_rx_desc = (struct rx_desc *) ( (u32) db->first_tx_desc + sizeof(struct rx_desc) * TX_DESC_CNT ); - db->first_rx_desc_dma = ( db->first_tx_desc_dma + sizeof(struct rx_desc) * TX_DESC_CNT); + db->first_rx_desc = (void *)db->first_tx_desc + sizeof(struct tx_desc) * TX_DESC_CNT; + db->first_rx_desc_dma = db->first_tx_desc_dma + sizeof(struct tx_desc) * TX_DESC_CNT; db->rx_insert_ptr = db->first_rx_desc; db->rx_ready_ptr = db->first_rx_desc; outl(db->first_rx_desc_dma, ioaddr + DCR3); /* RX DESC address */ @@ -1303,18 +1356,18 @@ tmp_buf_dma = db->buf_pool_dma_start; tmp_tx_dma = db->first_tx_desc_dma; for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) { - tmp_tx->tx_buf_ptr = (u32) tmp_buf; + tmp_tx->tx_buf_ptr = tmp_buf; tmp_tx->tdes0 = cpu_to_le32(0); tmp_tx->tdes1 = cpu_to_le32(0x81000000); /* IC, chain */ tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma); tmp_tx_dma += sizeof(struct tx_desc); tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma); - tmp_tx->next_tx_desc = (u32) ((u32) tmp_tx + sizeof(struct tx_desc)); - tmp_buf = (unsigned char *) ((u32) tmp_buf + TX_BUF_ALLOC); + tmp_tx->next_tx_desc = tmp_tx + 1; + tmp_buf = tmp_buf + TX_BUF_ALLOC; tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC; } (--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma); - tmp_tx->next_tx_desc = (u32) db->first_tx_desc; + tmp_tx->next_tx_desc = db->first_tx_desc; /* Init Receive descriptor chain */ tmp_rx_dma=db->first_rx_desc_dma; @@ -1323,13 +1376,13 @@ tmp_rx->rdes1 = cpu_to_le32(0x01000600); tmp_rx_dma += sizeof(struct rx_desc); tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma); - tmp_rx->next_rx_desc = (u32) ((u32) tmp_rx + sizeof(struct rx_desc)); + tmp_rx->next_rx_desc = tmp_rx + 1; } (--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma); - tmp_rx->next_rx_desc = (u32) db->first_rx_desc; + tmp_rx->next_rx_desc = db->first_rx_desc; - /* pre-allocated Rx buffer */ - allocated_rx_buffer(db); + /* pre-allocate Rx buffer */ + allocate_rx_buffer(db); } @@ -1438,7 +1491,7 @@ } /* prepare the setup frame */ - db->tx_insert_ptr = (struct tx_desc *) txptr->next_tx_desc; + db->tx_insert_ptr = txptr->next_tx_desc; txptr->tdes1 = cpu_to_le32(0x890000c0); /* Resource Check and Send the setup packet */ @@ -1457,10 +1510,10 @@ /* * Allocate rx buffer, - * As possible as allocated maxiumn Rx buffer + * As possible as allocate maxiumn Rx buffer */ -static void allocated_rx_buffer(struct dmfe_board_info *db) +static void allocate_rx_buffer(struct dmfe_board_info *db) { struct rx_desc *rxptr; struct sk_buff *skb; @@ -1470,10 +1523,11 @@ while(db->rx_avail_cnt < RX_DESC_CNT) { if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL ) break; - rxptr->rx_skb_ptr = (u32) skb; /* FIXME */ - rxptr->rdes2 = cpu_to_le32( pci_map_single(db->net_dev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + rxptr->rx_skb_ptr = skb; /* FIXME (?) */ + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); - rxptr = (struct rx_desc *) rxptr->next_rx_desc; + rxptr = rxptr->next_rx_desc; db->rx_avail_cnt++; } @@ -1540,7 +1594,7 @@ phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000; else /* DM9102/DM9102A */ phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000; - /* printk("<DMFE>: Phy_mode %x ",phy_mode); */ + /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */ switch (phy_mode) { case 0x1000: db->op_mode = DMFE_10MHF; break; case 0x2000: db->op_mode = DMFE_10MFD; break; @@ -1830,7 +1884,7 @@ if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) { /* SROM V4.01 */ /* Get NIC support media mode */ - db->NIC_capability = *(u16 *) (&srom[34]); + db->NIC_capability = le16_to_cpup(srom + 34); db->PHY_reg4 = 0; for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) { switch( db->NIC_capability & tmp_reg ) { @@ -1842,7 +1896,7 @@ } /* Media Mode Force or not check */ - dmfe_mode = *( (int *) &srom[34]) & *( (int *) &srom[36] ); + dmfe_mode = le32_to_cpup(srom + 34) & le32_to_cpup(srom + 36); switch(dmfe_mode) { case 0x4: dmfe_media_mode = DMFE_100MHF; break; /* 100MHF */ case 0x2: dmfe_media_mode = DMFE_10MFD; break; /* 10MFD */ @@ -2024,7 +2078,7 @@ MODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)"); MODULE_PARM_DESC(mode, "Davicom DM9xxx: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA"); MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function (bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)"); - + /* Description: * when user used insmod to add module, system invoked init_module() * to initilize and register. diff -u --recursive --new-file v2.4.14/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.4.14/linux/drivers/net/eepro.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/net/eepro.c Fri Nov 9 13:45:35 2001 @@ -8,7 +8,7 @@ according to the terms of the GNU General Public License, incorporated herein by reference. - The author may be reached at bao.ha@srs.gov + The author may be reached at bao.ha@srs.gov or 418 Hastings Place, Martinez, GA 30907. Things remaining to do: @@ -23,26 +23,29 @@ This is a compatibility hardware problem. Versions: + 0.12d fixing a problem with single card detected as eight eth devices + fixing a problem with sudden drop in card performance + (chris (asdn@go2.pl), 10/29/2001) 0.12c fixing some problems with old cards (aris, 01/08/2001) 0.12b misc fixes (aris, 06/26/2000) 0.12a port of version 0.12a of 2.2.x kernels to 2.3.x (aris (aris@conectiva.com.br), 05/19/2000) 0.11e some tweaks about multiple cards support (PdP, jul/aug 1999) 0.11d added __initdata, __init stuff; call spin_lock_init - in eepro_probe1. Replaced "eepro" by dev->name. Augmented - the code protected by spin_lock in interrupt routine + in eepro_probe1. Replaced "eepro" by dev->name. Augmented + the code protected by spin_lock in interrupt routine (PdP, 12/12/1998) - 0.11c minor cleanup (PdP, RMC, 09/12/1998) - 0.11b Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module - under 2.1.xx. Debug messages are flagged as KERN_DEBUG to - avoid console flooding. Added locking at critical parts. Now + 0.11c minor cleanup (PdP, RMC, 09/12/1998) + 0.11b Pascal Dupuis (dupuis@lei.ucl.ac.be): works as a module + under 2.1.xx. Debug messages are flagged as KERN_DEBUG to + avoid console flooding. Added locking at critical parts. Now the dawn thing is SMP safe. 0.11a Attempt to get 2.1.xx support up (RMC) 0.11 Brian Candler added support for multiple cards. Tested as a module, no idea if it works when compiled into kernel. 0.10e Rick Bressler notified me that ifconfig up;ifconfig down fails - because the irq is lost somewhere. Fixed that by moving + because the irq is lost somewhere. Fixed that by moving request_irq and free_irq to eepro_open and eepro_close respectively. 0.10d Ugh! Now Wakeup works. Was seriously broken in my first attempt. I'll need to find a way to specify an ioport other than @@ -50,8 +53,8 @@ And, yes, this is not the only reason. 0.10c PnP Wakeup Test for 595FX. uncomment #define PnPWakeup; to use. - 0.10b Should work now with (some) Pro/10+. At least for - me (and my two cards) it does. _No_ guarantee for + 0.10b Should work now with (some) Pro/10+. At least for + me (and my two cards) it does. _No_ guarantee for function with non-Pro/10+ cards! (don't have any) (RMC, 9/11/96) @@ -75,7 +78,7 @@ 0.07a Fix a stat report which counts every packet as a heart-beat failure. (BCH, 6/3/95) - 0.07 Modified to support all other 82595-based lan cards. + 0.07 Modified to support all other 82595-based lan cards. The IRQ vector of the EtherExpress Pro will be set according to the value saved in the EEPROM. For other cards, I will do autoirq_request() to grab the next @@ -85,14 +88,14 @@ print out format. (BCH, 3/9/95 and 3/14/95) 0.06 First stable release that I am comfortable with. (BCH, - 3/2/95) + 3/2/95) - 0.05 Complete testing of multicast. (BCH, 2/23/95) + 0.05 Complete testing of multicast. (BCH, 2/23/95) - 0.04 Adding multicast support. (BCH, 2/14/95) + 0.04 Adding multicast support. (BCH, 2/14/95) - 0.03 First widely alpha release for public testing. - (BCH, 2/14/95) + 0.03 First widely alpha release for public testing. + (BCH, 2/14/95) */ @@ -104,18 +107,18 @@ /* Sources: - This driver wouldn't have been written without the availability - of the Crynwr's Lan595 driver source code. It helps me to - familiarize with the 82595 chipset while waiting for the Intel - documentation. I also learned how to detect the 82595 using + This driver wouldn't have been written without the availability + of the Crynwr's Lan595 driver source code. It helps me to + familiarize with the 82595 chipset while waiting for the Intel + documentation. I also learned how to detect the 82595 using the packet driver's technique. This driver is written by cutting and pasting the skeleton.c driver provided by Donald Becker. I also borrowed the EEPROM routine from Donald Becker's 82586 driver. - Datasheet for the Intel 82595 (including the TX and FX version). It - provides just enough info that the casual reader might think that it + Datasheet for the Intel 82595 (including the TX and FX version). It + provides just enough info that the casual reader might think that it documents the i82595. The User Manual for the 82595. It provides a lot of the missing @@ -157,7 +160,7 @@ /* A zero-terminated list of I/O addresses to be probed. */ static unsigned int eepro_portlist[] compat_init_data = { 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0}; -/* note: 0x300 is default, the 595FX supports ALL IO Ports +/* note: 0x300 is default, the 595FX supports ALL IO Ports from 0x000 to 0x3F0, some of which are reserved in PCs */ /* To try the (not-really PnP Wakeup: */ @@ -194,7 +197,7 @@ version of the 82595 chip. */ int stepping; - spinlock_t lock; /* Serializing lock */ + spinlock_t lock; /* Serializing lock */ }; /* The station (ethernet) address prefix, used for IDing the board. */ @@ -244,7 +247,7 @@ /* Word 5: */ #define ee_BNC_TPE 0 /* 0=TPE */ #define ee_BootType 1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */ -#define ee_BootTypeMask 0x3 +#define ee_BootTypeMask 0x3 #define ee_NumConn 3 /* Number of Connections 0= One or Two */ #define ee_FlashSock 4 /* Presence of Flash Socket 0= Present */ #define ee_PortTPE 5 @@ -323,10 +326,10 @@ network traffics, the ring linked list should improve performance by allowing up to 8K worth of packets to be queued. -The sizes of the receive and transmit buffers can now be changed via lilo +The sizes of the receive and transmit buffers can now be changed via lilo or insmod. Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0" where rx-buffer is in KB unit. Modules uses the parameter mem which is -also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer." +also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer." The receive buffer has to be more than 3K or less than 29K. Otherwise, it is reset to the default of 24K, and, hence, 8K for the trasnmit buffer (transmit-buffer = 32K - receive-buffer). @@ -369,9 +372,9 @@ #define XMT_CHAIN 0x04 #define XMT_COUNT 0x06 -#define BANK0_SELECT 0x00 -#define BANK1_SELECT 0x40 -#define BANK2_SELECT 0x80 +#define BANK0_SELECT 0x00 +#define BANK1_SELECT 0x40 +#define BANK2_SELECT 0x80 /* Bank 0 registers */ #define COMMAND_REG 0x00 /* Register 0 */ @@ -440,7 +443,7 @@ #define REG13 0x0d #define FDX 0x00 #define A_N_ENABLE 0x02 - + #define I_ADD_REG0 0x04 #define I_ADD_REG1 0x05 #define I_ADD_REG2 0x06 @@ -536,13 +539,13 @@ int __init eepro_probe(struct net_device *dev) { int i; - int base_addr = dev->base_addr; + int base_addr = dev ? dev->base_addr : 0; SET_MODULE_OWNER(dev); #ifdef PnPWakeup /* XXXX for multiple cards should this only be run once? */ - + /* Wakeup: */ #define WakeupPort 0x279 #define WakeupSeq {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\ @@ -568,7 +571,6 @@ } #endif - if (base_addr > 0x1ff) /* Check a single specified location. */ return eepro_probe1(dev, base_addr); @@ -601,7 +603,7 @@ printk(KERN_DEBUG "Word0:\n"); printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP)); printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 ); - printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg)); + printk(KERN_DEBUG " AutoNegotiation: %d\n",GetBit(Word,ee_AutoNeg)); printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4); if (net_debug>4) { @@ -660,15 +662,15 @@ ID_REG (register 2 of bank 0) */ id=inb(ioaddr + ID_REG); - + if (((id) & ID_REG_MASK) == ID_REG_SIG) { /* We seem to have the 82595 signature, let's play with its counter (last 2 bits of register 2 of bank 0) to be sure. */ - - counter = (id & R_ROBIN_BITS); - if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS) == + + counter = (id & R_ROBIN_BITS); + if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS) == (counter + 0x40)) { /* Yes, the 82595 has been found */ @@ -702,40 +704,40 @@ station_addr[0] = read_eeprom(ioaddr, 2, dev); } - + station_addr[1] = read_eeprom(ioaddr, 3, dev); station_addr[2] = read_eeprom(ioaddr, 4, dev); if (eepro) { printk("%s: Intel EtherExpress 10 ISA\n at %#x,", dev->name, ioaddr); - } else if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) { + } else if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) { /* int to IRQ Mask */ eepro = 2; - printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", + printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", dev->name, ioaddr); } else if (station_addr[2] == 0x00aa) { eepro = 1; - printk("%s: Intel EtherExpress Pro/10 ISA at %#x,", + printk("%s: Intel EtherExpress Pro/10 ISA at %#x,", dev->name, ioaddr); } else { eepro = 0; - printk("%s: Intel 82595-based lan card at %#x,", + printk("%s: Intel 82595-based lan card at %#x,", dev->name, ioaddr); } /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; - + for (i=0; i < 6; i++) { dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); } - + dev->mem_start = (RCV_LOWER_LIMIT << 8); - + if ((dev->mem_end & 0x3f) < 3 || /* RX buffer must be more than 3K */ (dev->mem_end & 0x3f) > 29) /* and less than 29K */ dev->mem_end = (RCV_UPPER_LIMIT << 8); @@ -745,15 +747,15 @@ rcv_ram = dev->mem_end - (RCV_LOWER_LIMIT << 8); } - /* From now on, dev->mem_end - dev->mem_start contains - * the actual size of rx buffer + /* From now on, dev->mem_end - dev->mem_start contains + * the actual size of rx buffer */ - + if (net_debug > 3) printk(", %dK RCV buffer", (int)(dev->mem_end - dev->mem_start)/1024); - - + + /* ............... */ if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE)) @@ -767,7 +769,7 @@ i = read_eeprom(ioaddr, 1, dev); irqMask = read_eeprom(ioaddr, 7, dev); i &= 0x07; /* Mask off INT number */ - + for (j=0; ((j<16) && (i>=0)); j++) { if ((irqMask & (1<<j))!=0) { if (i==0) { @@ -781,18 +783,18 @@ printk(" Duh! illegal interrupt vector stored in EEPROM.\n"); kfree(dev->priv); return -ENODEV; - } else - + } else + if (dev->irq==2) dev->irq = 9; } - + if (dev->irq > 2) { printk(", IRQ %d, %s.\n", dev->irq, ifmap[dev->if_port]); } else printk(", %s.\n", ifmap[dev->if_port]); - + if ((dev->mem_start & 0xf) > 0) /* I don't know if this is */ net_debug = dev->mem_start & 7; /* still useful or not */ @@ -803,7 +805,7 @@ dev->name); } - if (net_debug) + if (net_debug) printk(version); /* Grab the region so we can find another board if autoIRQ fails. */ @@ -854,15 +856,15 @@ { int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12, 0 }; int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr; - + eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */ /* Enable the interrupt line. */ eepro_en_intline(ioaddr); - + /* be CAREFUL, BANK 0 now */ eepro_sw2bank0(ioaddr); - + /* clear all interrupts */ eepro_clear_int(ioaddr); @@ -882,7 +884,7 @@ autoirq_setup(0); eepro_diag(ioaddr); /* RESET the 82595 */ - + if (*irqp == autoirq_report(2)) /* It's a good IRQ line */ break; @@ -920,38 +922,38 @@ irqMask = read_eeprom(ioaddr,7,dev); if (lp->eepro == LAN595FX_10ISA) { - if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n"); + if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n"); } else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */ { lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */ - if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n"); + if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n"); } else if ((dev->dev_addr[0] == SA_ADDR0 && dev->dev_addr[1] == SA_ADDR1 && dev->dev_addr[2] == SA_ADDR2)) - { + { lp->eepro = 1; - if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n"); + if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 1;\n"); } /* Yes, an Intel EtherExpress Pro/10 */ else lp->eepro = 0; /* No, it is a generic 82585 lan card */ - /* Get the interrupt vector for the 82595 */ + /* Get the interrupt vector for the 82595 */ if (dev->irq < 2 && eepro_grab_irq(dev) == 0) { printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } - + if (request_irq(dev->irq , &eepro_interrupt, 0, dev->name, dev)) { printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq); return -EAGAIN; } - + #ifdef irq2dev_map if (((irq2dev_map[dev->irq] != 0) - || (irq2dev_map[dev->irq] = dev) == 0) && + || (irq2dev_map[dev->irq] = dev) == 0) && (irq2dev_map[dev->irq]!=dev)) { /* printk("%s: IRQ map wrong\n", dev->name); */ free_irq(dev->irq, dev); @@ -965,18 +967,18 @@ temp_reg = inb(ioaddr + eeprom_reg); lp->stepping = temp_reg >> 5; /* Get the stepping number of the 595 */ - + if (net_debug > 3) printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping); if (temp_reg & 0x10) /* Check the TurnOff Enable bit */ outb(temp_reg & 0xef, ioaddr + eeprom_reg); - for (i=0; i < 6; i++) - outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); - + for (i=0; i < 6; i++) + outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); + temp_reg = inb(ioaddr + REG1); /* Setup Transmit Chaining */ outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */ - | RCV_Discard_BadFrame, ioaddr + REG1); + | RCV_Discard_BadFrame, ioaddr + REG1); temp_reg = inb(ioaddr + REG2); /* Match broadcast */ outb(temp_reg | 0x14, ioaddr + REG2); @@ -987,11 +989,11 @@ /* Set the receiving mode */ eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */ - /* Set the interrupt vector */ + /* Set the interrupt vector */ temp_reg = inb(ioaddr + INT_NO_REG); if (lp->eepro == 2 || lp->eepro == LAN595FX_10ISA) outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG); - else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); + else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); temp_reg = inb(ioaddr + INT_NO_REG); @@ -1004,8 +1006,8 @@ /* Initialize the RCV and XMT upper and lower limits */ - outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); - outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); + outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); + outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); outb(XMT_LOWER_LIMIT, ioaddr + xmt_lower_limit_reg); outb(XMT_UPPER_LIMIT, ioaddr + xmt_upper_limit_reg); @@ -1022,12 +1024,12 @@ eepro_clear_int(ioaddr); /* Initialize RCV */ - outw(RCV_LOWER_LIMIT << 8, ioaddr + RCV_BAR); + outw(RCV_LOWER_LIMIT << 8, ioaddr + RCV_BAR); lp->rx_start = (RCV_LOWER_LIMIT << 8) ; - outw((RCV_UPPER_LIMIT << 8) | 0xfe, ioaddr + RCV_STOP); + outw((RCV_UPPER_LIMIT << 8) | 0xfe, ioaddr + RCV_STOP); /* Initialize XMT */ - outw(XMT_LOWER_LIMIT << 8, ioaddr + xmt_bar); + outw(XMT_LOWER_LIMIT << 8, ioaddr + xmt_bar); /* Check for the i82595TX and i82595FX */ old8 = inb(ioaddr + 8); @@ -1044,7 +1046,7 @@ old9 = inb(ioaddr + 9); /*outb(~old9, ioaddr + 9); if (((temp_reg = inb(ioaddr + 9)) == ( (~old9)&0xff) )) {*/ - + if (irqMask==ee_FX_INT2IRQ) { enum iftype { AUI=0, BNC=1, TPE=2 }; @@ -1070,7 +1072,7 @@ printk(KERN_DEBUG "i82595TX detected!\n"); } } - + eepro_sel_reset(ioaddr); SLOW_DOWN; SLOW_DOWN; @@ -1078,7 +1080,7 @@ lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; lp->tx_last = 0; - netif_start_queue(dev); + netif_start_queue(dev); if (net_debug > 3) printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name); @@ -1097,7 +1099,7 @@ /* if (net_debug > 1) */ printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name, "network cable problem"); - /* This is not a duplicate. One message for the console, + /* This is not a duplicate. One message for the console, one for the the log file */ printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name, "network cable problem"); @@ -1109,10 +1111,10 @@ { struct eepro_local *lp = (struct eepro_local *)dev->priv; unsigned long flags; - + if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name); - + netif_stop_queue (dev); spin_lock_irqsave(&lp->lock, flags); @@ -1138,7 +1140,7 @@ printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name); spin_unlock_irqrestore(&lp->lock, flags); - + return 0; } @@ -1163,17 +1165,17 @@ if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name); - + ioaddr = dev->base_addr; while (((status = inb(ioaddr + STATUS_REG)) & 0x06) && (boguscount--)) { - switch (status & (RX_INT | TX_INT)) { + #ifdef ANSWER_TX_AND_RX + switch (status & (RX_INT | TX_INT)) { case (RX_INT | TX_INT): eepro_ack_rxtx(ioaddr); break; -#endif case RX_INT: eepro_ack_rx(ioaddr); break; @@ -1181,20 +1183,24 @@ eepro_ack_tx(ioaddr); break; } +#endif if (status & RX_INT) { if (net_debug > 4) printk(KERN_DEBUG "%s: packet received interrupt.\n", dev->name); - /* Get the received packets */ - eepro_rx(dev); #ifndef ANSWER_TX_AND_RX - continue; + eepro_ack_rx(ioaddr); #endif + /* Get the received packets */ + eepro_rx(dev); } if (status & TX_INT) { if (net_debug > 4) printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name); +#ifndef ANSWER_TX_AND_RX + eepro_ack_tx(ioaddr); +#endif /* Process the status of transmitted packets */ eepro_transmit_interrupt(dev); } @@ -1219,12 +1225,12 @@ /* Disable the physical interrupt line. */ temp_reg = inb(ioaddr + REG1); - outb(temp_reg & 0x7f, ioaddr + REG1); + outb(temp_reg & 0x7f, ioaddr + REG1); eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */ /* Flush the Tx and disable Rx. */ - outb(STOP_RCV_CMD, ioaddr); + outb(STOP_RCV_CMD, ioaddr); lp->tx_start = lp->tx_end = (XMT_LOWER_LIMIT << 8); lp->tx_last = 0; @@ -1269,7 +1275,7 @@ unsigned short mode; struct dev_mc_list *dmi=dev->mc_list; - if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63) + if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || dev->mc_count > 63) { /* * We must make the kernel realise we had to move @@ -1277,18 +1283,18 @@ * the cable. If it was a promisc request the * flag is already set. If not we assert it. */ - dev->flags|=IFF_PROMISC; + dev->flags|=IFF_PROMISC; eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); - outb(mode | PRMSC_Mode, ioaddr + REG2); + outb(mode | PRMSC_Mode, ioaddr + REG2); mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ printk("%s: promiscuous mode enabled.\n", dev->name); } - - else if (dev->mc_count==0 ) + + else if (dev->mc_count==0 ) { eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); @@ -1297,12 +1303,12 @@ outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ } - - else + + else { unsigned short status, *eaddrs; int i, boguscount = 0; - + /* Disable RX and TX interrupts. Necessary to avoid corruption of the HOST_ADDRESS_REG by interrupt service routines. */ @@ -1310,7 +1316,7 @@ eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */ mode = inb(ioaddr + REG2); - outb(mode | Multi_IA, ioaddr + REG2); + outb(mode | Multi_IA, ioaddr + REG2); mode = inb(ioaddr + REG3); outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */ eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */ @@ -1319,8 +1325,8 @@ outw(0, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(6*(dev->mc_count + 1), ioaddr + IO_PORT); - - for (i = 0; i < dev->mc_count; i++) + + for (i = 0; i < dev->mc_count; i++) { eaddrs=(unsigned short *)dmi->dmi_addr; dmi=dmi->next; @@ -1328,7 +1334,7 @@ outw(*eaddrs++, ioaddr + IO_PORT); outw(*eaddrs++, ioaddr + IO_PORT); } - + eaddrs = (unsigned short *) dev->dev_addr; outw(eaddrs[0], ioaddr + IO_PORT); outw(eaddrs[1], ioaddr + IO_PORT); @@ -1338,10 +1344,10 @@ /* Update the transmit queue */ i = lp->tx_end + XMT_HEADER + 6*(dev->mc_count + 1); - - if (lp->tx_start != lp->tx_end) + + if (lp->tx_start != lp->tx_end) { - /* update the next address and the chain bit in the + /* update the next address and the chain bit in the last packet */ outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); outw(i, ioaddr + IO_PORT); @@ -1358,13 +1364,13 @@ do { /* We should be doing this in the eepro_interrupt()! */ SLOW_DOWN; SLOW_DOWN; - if (inb(ioaddr + STATUS_REG) & 0x08) + if (inb(ioaddr + STATUS_REG) & 0x08) { i = inb(ioaddr); outb(0x08, ioaddr + STATUS_REG); - + if (i & 0x20) { /* command ABORTed */ - printk("%s: multicast setup failed.\n", + printk("%s: multicast setup failed.\n", dev->name); break; } else if ((i & 0x0f) == 0x03) { /* MC-Done */ @@ -1411,10 +1417,10 @@ eepro_sw2bank1(ioaddr); outb(0x00, ioaddr + STATUS_REG); } - + eepro_sw2bank2(ioaddr); outb(ctrl_val, ee_addr); - + /* Shift the read command bits out. */ for (i = 8; i >= 0; i--) { short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI @@ -1426,7 +1432,7 @@ eeprom_delay(); } outb(ctrl_val, ee_addr); - + for (i = 16; i > 0; i--) { outb(ctrl_val | EESK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0); @@ -1467,7 +1473,7 @@ tx_available = lp->tx_start - lp->tx_end; else tx_available = XMT_RAM; - if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) + if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) /* No space available ??? */ { eepro_transmit_interrupt(dev); /* Clean up the transmiting queue */ @@ -1481,19 +1487,19 @@ end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; if (end >= (XMT_UPPER_LIMIT << 8)) { /* the transmit buffer is wrapped around */ - if (((XMT_UPPER_LIMIT << 8) - last) <= XMT_HEADER) { + if (((XMT_UPPER_LIMIT << 8) - last) <= XMT_HEADER) { /* Arrrr!!!, must keep the xmt header together, several days were lost to chase this one down. */ - + last = (XMT_LOWER_LIMIT << 8); end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; } - + else end = (XMT_LOWER_LIMIT << 8) + (end - (XMT_UPPER_LIMIT <<8)); } outw(last, ioaddr + HOST_ADDRESS_REG); - outw(XMT_CMD, ioaddr + IO_PORT); + outw(XMT_CMD, ioaddr + IO_PORT); outw(0, ioaddr + IO_PORT); outw(end, ioaddr + IO_PORT); outw(length, ioaddr + IO_PORT); @@ -1508,24 +1514,24 @@ } /* A dummy read to flush the DRAM write pipeline */ - status = inw(ioaddr + IO_PORT); + status = inw(ioaddr + IO_PORT); - if (lp->tx_start == lp->tx_end) { + if (lp->tx_start == lp->tx_end) { outw(last, ioaddr + xmt_bar); outb(XMT_CMD, ioaddr); lp->tx_start = last; /* I don't like to change tx_start here */ } else { - /* update the next address and the chain bit in the + /* update the next address and the chain bit in the last packet */ - + if (lp->tx_end != last) { outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); - outw(last, ioaddr + IO_PORT); + outw(last, ioaddr + IO_PORT); } - + outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG); - status = inw(ioaddr + IO_PORT); + status = inw(ioaddr + IO_PORT); outw(status | CHAIN_BIT, ioaddr + IO_PORT); /* Continue the transmit command */ @@ -1543,7 +1549,7 @@ */ if (lp->eepro == LAN595FX_10ISA) netif_stop_queue(dev); - + /* Enable RX and TX interrupts */ eepro_en_int(ioaddr); @@ -1572,17 +1578,17 @@ /* Set the read pointer to the start of the RCV */ outw(rcv_car, ioaddr + HOST_ADDRESS_REG); - + rcv_event = inw(ioaddr + IO_PORT); while (rcv_event == RCV_DONE) { - - rcv_status = inw(ioaddr + IO_PORT); + + rcv_status = inw(ioaddr + IO_PORT); rcv_next_frame = inw(ioaddr + IO_PORT); - rcv_size = inw(ioaddr + IO_PORT); + rcv_size = inw(ioaddr + IO_PORT); if ((rcv_status & (RX_OK | RX_ERROR)) == RX_OK) { - + /* Malloc up new buffer. */ struct sk_buff *skb; @@ -1602,31 +1608,31 @@ else { /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */ unsigned short temp = inb(ioaddr + INT_MASK_REG); outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG); - insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), + insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), (rcv_size + 3) >> 2); outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG); } - - skb->protocol = eth_type_trans(skb,dev); + + skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; } - - else { /* Not sure will ever reach here, + + else { /* Not sure will ever reach here, I set the 595 to discard bad received frames */ lp->stats.rx_errors++; - + if (rcv_status & 0x0100) lp->stats.rx_over_errors++; - + else if (rcv_status & 0x0400) lp->stats.rx_frame_errors++; - + else if (rcv_status & 0x0800) lp->stats.rx_crc_errors++; - - printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n", + + printk("%s: event = %#x, status = %#x, next = %#x, size = %#x\n", dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size); } @@ -1641,10 +1647,10 @@ outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG); rcv_event = inw(ioaddr + IO_PORT); - } + } if (rcv_car == 0) rcv_car = (RCV_UPPER_LIMIT << 8) | 0xff; - + outw(rcv_car - 1, ioaddr + RCV_STOP); if (net_debug > 5) @@ -1656,9 +1662,9 @@ { struct eepro_local *lp = (struct eepro_local *)dev->priv; short ioaddr = dev->base_addr; - short boguscount = 20; + short boguscount = 20; unsigned xmt_status; - + /* if (dev->tbusy == 0) { printk("%s: transmit_interrupt called with tbusy = 0 ??\n", @@ -1667,11 +1673,11 @@ dev->name); } */ - while (lp->tx_start != lp->tx_end && boguscount) { + while (lp->tx_start != lp->tx_end && boguscount) { - outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); + outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); xmt_status = inw(ioaddr+IO_PORT); - + if ((xmt_status & TX_DONE_BIT) == 0) { if (lp->eepro == LAN595FX_10ISA) { udelay(40); @@ -1682,20 +1688,20 @@ break; } - xmt_status = inw(ioaddr+IO_PORT); + xmt_status = inw(ioaddr+IO_PORT); lp->tx_start = inw(ioaddr+IO_PORT); if (lp->eepro == LAN595FX_10ISA) { lp->tx_start = (XMT_LOWER_LIMIT << 8); lp->tx_end = lp->tx_start; - + /* yeah, black magic :( */ eepro_sw2bank0(ioaddr); eepro_en_int(ioaddr); /* disabling rx */ eepro_dis_rx(ioaddr); - + /* enabling rx */ eepro_en_rx(ioaddr); } @@ -1703,7 +1709,7 @@ netif_wake_queue (dev); if (xmt_status & 0x2000) - lp->stats.tx_packets++; + lp->stats.tx_packets++; else { lp->stats.tx_errors++; if (xmt_status & 0x0400) { @@ -1719,7 +1725,7 @@ printk(KERN_DEBUG "%s: XMT status = %#x\n", dev->name, xmt_status); } - if (lp->eepro == LAN595FX_10ISA) { + if (lp->eepro == LAN595FX_10ISA) { /* Try to restart the adaptor. */ /* We are supposed to wait for 2 us after a SEL_RESET */ eepro_sel_reset(ioaddr); @@ -1727,7 +1733,7 @@ /* first enable interrupts */ eepro_sw2bank0(ioaddr); outb(ALL_MASK & ~(RX_INT | TX_INT), ioaddr + STATUS_REG); - + /* enabling rx */ eepro_en_rx(ioaddr); } @@ -1735,7 +1741,7 @@ if (xmt_status & 0x000f) { lp->stats.collisions += (xmt_status & 0x000f); } - + if ((xmt_status & 0x0040) == 0x0) { lp->stats.tx_heartbeat_errors++; } @@ -1778,7 +1784,7 @@ MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)"); MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)"); -int +int init_module(void) { int i; @@ -1790,23 +1796,25 @@ else if (autodetect) { /* if autodetect is set then we must force detection */ io[0] = 0; - + printk("eepro_init_module: Auto-detecting boards (May God protect us...)\n"); - } + } for (i = 0; i < MAX_EEPRO; i++) { struct net_device *d = &dev_eepro[n_eepro]; d->mem_end = mem[n_eepro]; - d->base_addr = io[0]; + d->base_addr = io[n_eepro]; d->irq = irq[n_eepro]; d->init = eepro_probe; - if (register_netdev(d) == 0) - n_eepro++; - else - break; + if (io[n_eepro]>0) { + if (register_netdev(d) == 0) + n_eepro++; + else + break; + } } - + return n_eepro ? 0 : -ENODEV; } @@ -1814,7 +1822,7 @@ cleanup_module(void) { int i; - + for (i=0; i<n_eepro; i++) { struct net_device *d = &dev_eepro[i]; unregister_netdev(d); @@ -1824,7 +1832,7 @@ /* If we don't do this, we can't re-insmod it later. */ release_region(d->base_addr, EEPRO_IO_EXTENT); - + } } #endif /* MODULE */ diff -u --recursive --new-file v2.4.14/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.4.14/linux/drivers/net/eepro100.c Tue Oct 9 17:06:51 2001 +++ linux/drivers/net/eepro100.c Fri Nov 9 13:45:35 2001 @@ -108,10 +108,12 @@ #include <asm/bitops.h> #include <asm/io.h> +#include <asm/uaccess.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <linux/ethtool.h> #include <linux/delay.h> MODULE_AUTHOR("Maintainer: Andrey V. Savochkin <saw@saw.sw.com.sg>"); @@ -1913,6 +1915,35 @@ return &sp->stats; } +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + struct speedo_private *sp = dev->priv; + + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + strncpy(info.driver, "eepro100", sizeof(info.driver)-1); + strncpy(info.version, version, sizeof(info.version)-1); + if (sp && sp->pdev) + strcpy(info.bus_info, sp->pdev->slot_name); + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + + } + + return -EOPNOTSUPP; +} + + + + + static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct speedo_private *sp = (struct speedo_private *)dev->priv; @@ -1952,6 +1983,8 @@ add_timer(&sp->timer); /* may be set to the past --SAW */ pci_set_power_state(sp->pdev, saved_acpi); return 0; + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); default: return -EOPNOTSUPP; } diff -u --recursive --new-file v2.4.14/linux/drivers/net/fealnx.c linux/drivers/net/fealnx.c --- v2.4.14/linux/drivers/net/fealnx.c Tue Oct 23 22:48:51 2001 +++ linux/drivers/net/fealnx.c Fri Nov 9 13:45:35 2001 @@ -1815,7 +1815,7 @@ return 0; } -static struct pci_device_id fealnx_pci_tbl[] = __devinitdata { +static struct pci_device_id fealnx_pci_tbl[] __devinitdata = { {0x1516, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x1516, 0x0803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, {0x1516, 0x0891, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, diff -u --recursive --new-file v2.4.14/linux/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c --- v2.4.14/linux/drivers/net/irda/irda-usb.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/net/irda/irda-usb.c Fri Nov 9 14:22:17 2001 @@ -279,7 +279,7 @@ purb->timeout = MSECS_TO_JIFFIES(100); if ((ret = usb_submit_urb(purb))) { - IRDA_DEBUG(0, __FUNCTION__ "(), failed Speed URB\n"); + WARNING(__FUNCTION__ "(), failed Speed URB\n"); } spin_unlock_irqrestore(&self->lock, flags); } @@ -296,14 +296,14 @@ /* We should always have a context */ if (self == NULL) { - IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n"); + WARNING(__FUNCTION__ "(), Bug : self == NULL\n"); return; } /* Check for timeout and other USB nasties */ if(purb->status != USB_ST_NOERROR) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); /* Don't do anything here, that might confuse the USB layer. * Instead, we will wait for irda_usb_net_timeout(), the @@ -452,7 +452,7 @@ /* Ask USB to send the packet */ if ((res = usb_submit_urb(purb))) { - IRDA_DEBUG(0, __FUNCTION__ "(), failed Tx URB\n"); + WARNING(__FUNCTION__ "(), failed Tx URB\n"); self->stats.tx_errors++; /* Let USB recover : We will catch that in the watchdog */ /*netif_start_queue(netdev);*/ @@ -481,7 +481,7 @@ /* We should always have a context */ if (self == NULL) { - IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n"); + WARNING(__FUNCTION__ "(), Bug : self == NULL\n"); return; } @@ -492,7 +492,7 @@ /* Check for timeout and other USB nasties */ if(purb->status != USB_ST_NOERROR) { /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags); /* Don't do anything here, that might confuse the USB layer, * and we could go in recursion and blow the kernel stack... @@ -514,7 +514,7 @@ /* If we need to change the speed or xbofs, do it now */ if ((self->new_speed != -1) || (self->new_xbofs != -1)) { - IRDA_DEBUG(0, __FUNCTION__ "(), Changing speed now...\n"); + IRDA_DEBUG(1, __FUNCTION__ "(), Changing speed now...\n"); irda_usb_change_speed_xbofs(self); } else { /* Otherwise, allow the stack to send more packets */ @@ -548,7 +548,7 @@ /* Check speed URB */ purb = &(self->speed_urb); if (purb->status != USB_ST_NOERROR) { - WARNING("%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); + IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); switch (purb->status) { case USB_ST_URB_PENDING: /* -EINPROGRESS == -115 */ @@ -575,7 +575,7 @@ if (purb->status != USB_ST_NOERROR) { struct sk_buff *skb = purb->context; - WARNING("%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); + IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags); /* Increase error count */ self->stats.tx_errors++; @@ -694,7 +694,7 @@ /* Check that we have an urb */ if (!purb) { - IRDA_DEBUG(0, __FUNCTION__ "(), Bug : purb == NULL\n"); + WARNING(__FUNCTION__ "(), Bug : purb == NULL\n"); return; } @@ -704,7 +704,7 @@ if (!skb) { /* If this ever happen, we are in deep s***. * Basically, the Rx path will stop... */ - IRDA_DEBUG(0, __FUNCTION__ "(), Failed to allocate Rx skb\n"); + WARNING(__FUNCTION__ "(), Failed to allocate Rx skb\n"); return; } } else { @@ -734,7 +734,7 @@ if (ret) { /* If this ever happen, we are in deep s***. * Basically, the Rx path will stop... */ - IRDA_DEBUG(0, __FUNCTION__ "(), Failed to submit Rx URB %d\n", ret); + WARNING(__FUNCTION__ "(), Failed to submit Rx URB %d\n", ret); } } @@ -775,13 +775,13 @@ self->stats.rx_crc_errors++; break; case -ECONNRESET: /* -104 */ - WARNING(__FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags); /* uhci_cleanup_unlink() is going to kill the Rx * URB just after we return. No problem, at this * point the URB will be idle ;-) - Jean II */ break; default: - WARNING(__FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags); + IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags); break; } goto done; @@ -893,7 +893,7 @@ */ static int irda_usb_net_init(struct net_device *dev) { - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); /* Set up to be a normal IrDA network device driver */ irda_device_setup(dev); @@ -917,7 +917,7 @@ char hwname[16]; int i; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; @@ -977,7 +977,7 @@ struct irda_usb_cb *self; int i; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(netdev != NULL, return -1;); self = (struct irda_usb_cb *) netdev->priv; @@ -1142,7 +1142,7 @@ struct net_device *netdev; int err; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); spin_lock_init(&self->lock); @@ -1197,7 +1197,7 @@ */ static inline int irda_usb_close(struct irda_usb_cb *self) { - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(self != NULL, return -1;); @@ -1326,39 +1326,43 @@ */ static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) { - struct usb_interface_descriptor *interface; - struct irda_class_desc *desc, *ptr; + struct irda_class_desc *desc; int ret; - - desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL); + + desc = kmalloc(sizeof (*desc), GFP_KERNEL); if (desc == NULL) return NULL; - memset(desc, 0, sizeof(struct irda_class_desc)); - - ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc)); - IRDA_DEBUG(0, __FUNCTION__ "(), ret=%d\n", ret); - if (ret) { - WARNING("usb-irda: usb_get_class_descriptor failed (0x%x)\n", ret); - } + memset(desc, 0, sizeof(*desc)); - /* Check if we found it? */ - if (desc->bDescriptorType == USB_DT_IRDA) - return desc; + /* USB-IrDA class spec 1.0: + * 6.1.3: Standard "Get Descriptor" Device Request is not + * appropriate to retrieve class-specific descriptor + * 6.2.5: Class Specific "Get Class Descriptor" Interface Request + * is mandatory and returns the USB-IrDA class descriptor + */ - IRDA_DEBUG(0, __FUNCTION__ "(), parsing extra descriptors ...\n"); + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), + IU_REQ_GET_CLASS_DESC, + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500)); - /* Check if the class descriptor is interleaved with standard descriptors */ - interface = &dev->actconfig->interface[ifnum].altsetting[0]; - ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr); - if (ret) { - kfree(desc); - return NULL; + IRDA_DEBUG(1, __FUNCTION__ "(), ret=%d\n", ret); + if (ret < sizeof(*desc)) { + WARNING("usb-irda: class_descriptor read %s (%d)\n", + (ret<0) ? "failed" : "too short", ret); + } + else if (desc->bDescriptorType != USB_DT_IRDA) { + WARNING("usb-irda: bad class_descriptor type\n"); } - *desc = *ptr; + else { #ifdef IU_DUMP_CLASS_DESC - irda_usb_dump_class_desc(desc); + irda_usb_dump_class_desc(desc); #endif /* IU_DUMP_CLASS_DESC */ - return desc; + + return desc; + } + kfree(desc); + return NULL; } /*********************** USB DEVICE CALLBACKS ***********************/ @@ -1389,9 +1393,9 @@ * don't need to check if the dongle is really ours. * Jean II */ - IRDA_DEBUG(0, "Vendor: %x, Product: %x\n", dev->descriptor.idVendor, dev->descriptor.idProduct); - - MESSAGE("IRDA-USB found at address %d\n", dev->devnum); + MESSAGE("IRDA-USB found at address %d, Vendor: %x, Product: %x\n", + dev->devnum, dev->descriptor.idVendor, + dev->descriptor.idProduct); /* Try to cleanup all instance that have a pending disconnect * Instance will be in this state is the disconnect() occurs @@ -1416,7 +1420,7 @@ } } if(self == NULL) { - IRDA_DEBUG(0, "Too many USB IrDA devices !!! (max = %d)\n", + WARNING("Too many USB IrDA devices !!! (max = %d)\n", NIRUSB); return NULL; } @@ -1436,7 +1440,7 @@ * specify an alternate, but very few driver do like this. * Jean II */ ret = usb_set_interface(dev, ifnum, 0); - IRDA_DEBUG(0, "usb-irda: set interface %d result %d\n", ifnum, ret); + IRDA_DEBUG(1, "usb-irda: set interface %d result %d\n", ifnum, ret); switch (ret) { case USB_ST_NOERROR: /* 0 */ break; @@ -1485,7 +1489,7 @@ struct irda_usb_cb *self = (struct irda_usb_cb *) ptr; int i; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); /* Oups ! We are not there any more */ self->present = 0; diff -u --recursive --new-file v2.4.14/linux/drivers/net/irda/vlsi_ir.c linux/drivers/net/irda/vlsi_ir.c --- v2.4.14/linux/drivers/net/irda/vlsi_ir.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/net/irda/vlsi_ir.c Fri Nov 9 13:41:42 2001 @@ -1238,7 +1238,7 @@ } printk(KERN_INFO "%s: registered device %s\n", drivername, ndev->name); - pdev->driver_data = ndev; + pci_set_drvdata(pdev, ndev); return 0; @@ -1247,13 +1247,13 @@ out_disable: pci_disable_device(pdev); out: - pdev->driver_data = NULL; + pci_set_drvdata(pdev, NULL); return -ENODEV; } static void __devexit vlsi_irda_remove(struct pci_dev *pdev) { - struct net_device *ndev = pdev->driver_data; + struct net_device *ndev = pci_get_drvdata(pdev); if (ndev) { printk(KERN_INFO "%s: unregister device %s\n", @@ -1267,7 +1267,7 @@ } else printk(KERN_CRIT "%s: lost netdevice?\n", drivername); - pdev->driver_data = NULL; + pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); printk(KERN_INFO "%s: %s disabled\n", drivername, pdev->name); diff -u --recursive --new-file v2.4.14/linux/drivers/net/natsemi.c linux/drivers/net/natsemi.c --- v2.4.14/linux/drivers/net/natsemi.c Mon Nov 5 15:55:30 2001 +++ linux/drivers/net/natsemi.c Fri Nov 9 13:45:35 2001 @@ -1,6 +1,7 @@ /* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP8381x series. */ /* Written/copyright 1999-2001 by Donald Becker. + Portions copyright (c) 2001 Sun Microsystems (thockin@sun.com) This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. @@ -95,6 +96,9 @@ * MDIO Cleanup (Tim Hockin) * Reformat register offsets/bits (jgarzik) + version 1.0.12: + * ETHTOOL_* further support (Tim Hockin) + TODO: * big endian support with CFG:BEM instead of cpu_to_le32 * support for an external PHY @@ -102,7 +106,7 @@ */ #define DRV_NAME "natsemi" -#define DRV_VERSION "1.07+LK1.0.11" +#define DRV_VERSION "1.07+LK1.0.12" #define DRV_RELDATE "Oct 19, 2001" /* Updated to recommendations in pci-skeleton v2.03. */ @@ -162,6 +166,9 @@ #define NATSEMI_HW_TIMEOUT 400 #define NATSEMI_TIMER_FREQ 3*HZ +#define NATSEMI_PG0_NREGS 64 +#define NATSEMI_PG1_NREGS 4 +#define NATSEMI_NREGS (NATSEMI_PG0_NREGS + NATSEMI_PG1_NREGS) #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ @@ -647,6 +654,7 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd); static void enable_wol_mode(struct net_device *dev, int enable_intr); static int netdev_close(struct net_device *dev); +static int netdev_get_regs(struct net_device *dev, u32 *buf); static int __devinit natsemi_probe1 (struct pci_dev *pdev, @@ -789,7 +797,7 @@ chip_config & CfgAnegFull ? "full" : "half"); } printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", - dev->name, (int)mdio_read(dev, 1, MII_BMSR), + dev->name, mdio_read(dev, 1, MII_BMSR), np->advertising); /* save the silicon revision for later querying */ @@ -1647,8 +1655,12 @@ printk(KERN_NOTICE "%s: Link wake-up event %8.8x\n", dev->name, wol_status); } - if (intr_status & RxStatusFIFOOver && debug) { - printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", dev->name); + if (intr_status & RxStatusFIFOOver) { + if (debug >= 2) { + printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", + dev->name); + } + np->stats.rx_fifo_errors++; } /* Hmmmmm, it's not clear how to recover from PCI faults. */ if (intr_status & IntrPCIErr) { @@ -1794,22 +1806,28 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { struct netdev_private *np = dev->priv; - struct ethtool_cmd ecmd; - - if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) + u32 cmd; + + if (get_user(cmd, (u32 *)useraddr)) return -EFAULT; - switch (ecmd.cmd) { + switch (cmd) { + /* get driver info */ case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; - strcpy(info.driver, DRV_NAME); - strcpy(info.version, DRV_VERSION); - strcpy(info.bus_info, np->pci_dev->slot_name); + strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN); + strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN); + info.fw_version[0] = '\0'; + strncpy(info.bus_info, np->pci_dev->slot_name, + ETHTOOL_BUSINFO_LEN); + info.regdump_len = NATSEMI_NREGS; if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0; } + /* get settings */ case ETHTOOL_GSET: { + struct ethtool_cmd ecmd = { ETHTOOL_GSET }; spin_lock_irq(&np->lock); netdev_get_ecmd(dev, &ecmd); spin_unlock_irq(&np->lock); @@ -1817,7 +1835,9 @@ return -EFAULT; return 0; } + /* set settings */ case ETHTOOL_SSET: { + struct ethtool_cmd ecmd; int r; if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) return -EFAULT; @@ -1826,6 +1846,7 @@ spin_unlock_irq(&np->lock); return r; } + /* get wake-on-lan */ case ETHTOOL_GWOL: { struct ethtool_wolinfo wol = {ETHTOOL_GWOL}; spin_lock_irq(&np->lock); @@ -1836,6 +1857,7 @@ return -EFAULT; return 0; } + /* set wake-on-lan */ case ETHTOOL_SWOL: { struct ethtool_wolinfo wol; int r; @@ -1847,6 +1869,71 @@ spin_unlock_irq(&np->lock); return r; } + /* get registers */ + case ETHTOOL_GREGS: { + struct ethtool_regs regs; + u32 regbuf[NATSEMI_NREGS]; + int r; + + if (copy_from_user(®s, useraddr, sizeof(regs))) + return -EFAULT; + + if (regs.len > NATSEMI_NREGS) { + regs.len = NATSEMI_NREGS; + } + regs.version = 0; + if (copy_to_user(useraddr, ®s, sizeof(regs))) + return -EFAULT; + + useraddr += offsetof(struct ethtool_regs, data); + + spin_lock_irq(&np->lock); + r = netdev_get_regs(dev, regbuf); + spin_unlock_irq(&np->lock); + + if (r) + return r; + if (copy_to_user(useraddr, regbuf, regs.len*sizeof(u32))) + return -EFAULT; + return 0; + } + /* get message-level */ + case ETHTOOL_GMSGLVL: { + struct ethtool_value edata = {ETHTOOL_GMSGLVL}; + edata.data = debug; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + /* set message-level */ + case ETHTOOL_SMSGLVL: { + struct ethtool_value edata; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + debug = edata.data; + return 0; + } + /* restart autonegotiation */ + case ETHTOOL_NWAY_RST: { + int tmp; + int r = -EINVAL; + /* if autoneg is off, it's an error */ + tmp = mdio_read(dev, 1, MII_BMCR); + if (tmp & BMCR_ANENABLE) { + tmp |= (BMCR_ANRESTART); + mdio_write(dev, 1, MII_BMCR, tmp); + r = 0; + } + return r; + } + /* get link status */ + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + edata.data = (mdio_read(dev, 1, MII_BMSR)&BMSR_LSTATUS) ? 1:0; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } } @@ -2082,6 +2169,33 @@ } mdio_write(dev, 1, MII_BMCR, tmp); } + return 0; +} + +static int netdev_get_regs(struct net_device *dev, u32 *buf) +{ + int i; + + /* read all of page 0 of registers */ + for (i = 0; i < NATSEMI_PG0_NREGS; i++) { + buf[i] = readl(dev->base_addr + i*4); + } + + /* read only the 'magic' registers from page 1 */ + writew(1, dev->base_addr + PGSEL); + buf[i++] = readw(dev->base_addr + PMDCSR); + buf[i++] = readw(dev->base_addr + TSTDAT); + buf[i++] = readw(dev->base_addr + DSPCFG); + buf[i++] = readw(dev->base_addr + SDCFG); + writew(0, dev->base_addr + PGSEL); + + /* the interrupt status is clear-on-read - see if we missed any */ + if (buf[4] & buf[5]) { + printk(KERN_WARNING + "%s: shoot, we dropped an interrupt (0x%x)\n", + dev->name, buf[4] & buf[5]); + } + return 0; } diff -u --recursive --new-file v2.4.14/linux/drivers/net/ns83820.c linux/drivers/net/ns83820.c --- v2.4.14/linux/drivers/net/ns83820.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/net/ns83820.c Fri Nov 9 13:45:35 2001 @@ -1465,7 +1465,7 @@ static int __init ns83820_init(void) { - printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/100 driver.\n"); + printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/1000 driver.\n"); return pci_module_init(&driver); } diff -u --recursive --new-file v2.4.14/linux/drivers/net/pcmcia/xircom_cb.c linux/drivers/net/pcmcia/xircom_cb.c --- v2.4.14/linux/drivers/net/pcmcia/xircom_cb.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/net/pcmcia/xircom_cb.c Fri Nov 9 13:41:42 2001 @@ -319,7 +319,7 @@ */ static void __devexit xircom_remove(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *card; enter(); diff -u --recursive --new-file v2.4.14/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c --- v2.4.14/linux/drivers/net/pcmcia/xircom_tulip_cb.c Mon Nov 5 15:55:30 2001 +++ linux/drivers/net/pcmcia/xircom_tulip_cb.c Fri Nov 9 13:41:42 2001 @@ -1701,7 +1701,7 @@ #ifdef CONFIG_PM static int xircom_suspend(struct pci_dev *pdev, u32 state) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *tp = dev->priv; printk(KERN_INFO "xircom_suspend(%s)\n", dev->name); if (tp->open) @@ -1712,7 +1712,7 @@ static int xircom_resume(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct xircom_private *tp = dev->priv; printk(KERN_INFO "xircom_resume(%s)\n", dev->name); @@ -1734,7 +1734,7 @@ static void __devexit xircom_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); printk(KERN_INFO "xircom_remove_one(%s)\n", dev->name); unregister_netdev(dev); diff -u --recursive --new-file v2.4.14/linux/drivers/net/pppoe.c linux/drivers/net/pppoe.c --- v2.4.14/linux/drivers/net/pppoe.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/net/pppoe.c Fri Nov 9 14:02:24 2001 @@ -5,7 +5,7 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.8 + * Version: 0.6.9 * * 030700 : Fixed connect logic to allow for disconnect. * 270700 : Fixed potential SMP problems; we must protect against @@ -29,6 +29,8 @@ * the original skb that was passed in on success, never on * failure. Delete the copy of the skb on failure to avoid * a memory leak. + * 081001 : Misc. cleanup (licence string, non-blocking, prevent + * reference of device on close). * * Author: Michal Ostrowski <mostrows@speakeasy.net> * Contributors: @@ -349,7 +351,7 @@ if (relay_po == NULL) goto abort_kfree; - + if ((relay_po->sk->state & PPPOX_CONNECTED) == 0) goto abort_put; @@ -543,13 +545,12 @@ po = sk->protinfo.pppox; if (po->pppoe_pa.sid) { delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote); - po->pppoe_pa.sid = 0 ; } if (po->pppoe_dev) - dev_put(po->pppoe_dev); + dev_put(po->pppoe_dev); - po->pppoe_dev = NULL ; + po->pppoe_dev = NULL; sock_orphan(sk); sock->sk = NULL; @@ -944,7 +945,8 @@ goto end; } - skb = skb_recv_datagram(sk, flags, 0, &error); + skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + flags & MSG_DONTWAIT, &error); if (error < 0) { goto end; @@ -1077,3 +1079,7 @@ module_init(pppoe_init); module_exit(pppoe_exit); + +MODULE_AUTHOR("Michal Ostrowski <mostrows@speakeasy.net>"); +MODULE_DESCRIPTION("PPP over Ethernet driver"); +MODULE_LICENSE("GPL"); diff -u --recursive --new-file v2.4.14/linux/drivers/net/pppox.c linux/drivers/net/pppox.c --- v2.4.14/linux/drivers/net/pppox.c Wed Jul 25 17:10:21 2001 +++ linux/drivers/net/pppox.c Fri Nov 9 14:02:24 2001 @@ -158,3 +158,7 @@ module_init(pppox_init); module_exit(pppox_exit); + +MODULE_AUTHOR("Michal Ostrowski <mostrows@speakeasy.net>"); +MODULE_DESCRIPTION("PPP over Ethernet driver (generic socket layer)"); +MODULE_LICENSE("GPL"); diff -u --recursive --new-file v2.4.14/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c --- v2.4.14/linux/drivers/net/rrunner.c Wed Jul 25 17:10:21 2001 +++ linux/drivers/net/rrunner.c Fri Nov 9 13:45:35 2001 @@ -826,7 +826,7 @@ case E_RX_IDLE: printk(KERN_WARNING "%s: RX data not moving\n", dev->name); - break; + goto drop; case E_WATCHDOG: printk(KERN_INFO "%s: The watchdog is here to see " "us\n", dev->name); @@ -912,15 +912,43 @@ case E_RX_PAR_ERR: printk(KERN_WARNING "%s: Receive parity error\n", dev->name); - break; + goto drop; case E_RX_LLRC_ERR: printk(KERN_WARNING "%s: Receive LLRC error\n", dev->name); - break; + goto drop; case E_PKT_LN_ERR: printk(KERN_WARNING "%s: Receive packet length " "error\n", dev->name); - break; + goto drop; + case E_DTA_CKSM_ERR: + printk(KERN_WARNING "%s: Data checksum error\n", + dev->name); + goto drop; + case E_SHT_BST: + printk(KERN_WARNING "%s: Unexpected short burst " + "error\n", dev->name); + goto drop; + case E_STATE_ERR: + printk(KERN_WARNING "%s: Recv. state transition" + " error\n", dev->name); + goto drop; + case E_UNEXP_DATA: + printk(KERN_WARNING "%s: Unexpected data error\n", + dev->name); + goto drop; + case E_LST_LNK_ERR: + printk(KERN_WARNING "%s: Link lost error\n", + dev->name); + goto drop; + case E_FRM_ERR: + printk(KERN_WARNING "%s: Framming Error\n", + dev->name); + goto drop; + case E_FLG_SYN_ERR: + printk(KERN_WARNING "%s: Flag sync. lost during" + "packet\n", dev->name); + goto drop; case E_RX_INV_BUF: printk(KERN_ERR "%s: Invalid receive buffer " "address\n", dev->name); @@ -942,6 +970,23 @@ ®s->HostCtrl); wmb(); break; + drop: + /* Label packet to be dropped. + * Actual dropping occurs in rx + * handling. + * + * The index of packet we get to drop is + * the index of the packet following + * the bad packet. -kbf + */ + { + u16 index = rrpriv->evt_ring[eidx].index; + index = (index + (RX_RING_ENTRIES - 1)) % + RX_RING_ENTRIES; + rrpriv->rx_ring[index].mode |= + (PACKET_BAD | PACKET_END); + } + break; default: printk(KERN_WARNING "%s: Unhandled event 0x%02x\n", dev->name, rrpriv->evt_ring[eidx].code); @@ -968,6 +1013,11 @@ printk("len %x, mode %x\n", pkt_len, rrpriv->rx_ring[index].mode); #endif + if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){ + rrpriv->stats.rx_dropped++; + goto defer; + } + if (pkt_len > 0){ struct sk_buff *skb; @@ -1046,6 +1096,15 @@ printk("%s: interrupt, prodidx = %i, eidx = %i\n", dev->name, prodidx, rrpriv->info->evt_ctrl.pi); #endif + /* + * Order here is important. We must handle events + * before doing anything else in order to catch + * such things as LLRC errors, etc -kbf + */ + + eidx = rrpriv->info->evt_ctrl.pi; + if (prodidx != eidx) + eidx = rr_handle_event(dev, prodidx, eidx); rxindex = rrpriv->cur_rx; if (rxindex != rxlimit) @@ -1054,15 +1113,19 @@ txcon = rrpriv->dirty_tx; if (txcsmr != txcon) { do { - rrpriv->stats.tx_packets++; - rrpriv->stats.tx_bytes +=rrpriv->tx_skbuff[txcon]->len; - dev_kfree_skb_irq(rrpriv->tx_skbuff[txcon]); - - rrpriv->tx_skbuff[txcon] = NULL; - rrpriv->tx_ring[txcon].size = 0; - set_rraddr(&rrpriv->tx_ring[txcon].addr, 0); - rrpriv->tx_ring[txcon].mode = 0; - + /* Due to occational firmware TX producer/consumer out + * of sync. error need to check entry in ring -kbf + */ + if(rrpriv->tx_skbuff[txcon]){ + rrpriv->stats.tx_packets++; + rrpriv->stats.tx_bytes +=rrpriv->tx_skbuff[txcon]->len; + dev_kfree_skb_irq(rrpriv->tx_skbuff[txcon]); + + rrpriv->tx_skbuff[txcon] = NULL; + rrpriv->tx_ring[txcon].size = 0; + set_rraddr(&rrpriv->tx_ring[txcon].addr, 0); + rrpriv->tx_ring[txcon].mode = 0; + } txcon = (txcon + 1) % TX_RING_ENTRIES; } while (txcsmr != txcon); wmb(); @@ -1077,10 +1140,6 @@ } } - eidx = rrpriv->info->evt_ctrl.pi; - if (prodidx != eidx) - eidx = rr_handle_event(dev, prodidx, eidx); - eidx |= ((txcsmr << 8) | (rxlimit << 16)); writel(eidx, ®s->EvtCon); wmb(); @@ -1238,7 +1297,7 @@ index, cons); if (rrpriv->tx_skbuff[index]){ - len = min(0x80, rrpriv->tx_skbuff[index]->len); + len = min_t(int, 0x80, rrpriv->tx_skbuff[index]->len); printk("skbuff for index %i is valid - dumping data (0x%x bytes - DMA len 0x%x)\n", index, len, rrpriv->tx_ring[index].size); for (i = 0; i < len; i++){ if (!(i & 7)) @@ -1249,7 +1308,7 @@ } if (rrpriv->tx_skbuff[cons]){ - len = min(0x80, rrpriv->tx_skbuff[cons]->len); + len = min_t(int, 0x80, rrpriv->tx_skbuff[cons]->len); printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len); printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08lx), skbuff-addr %08lx, truesize 0x%x\n", rrpriv->tx_ring[cons].mode, diff -u --recursive --new-file v2.4.14/linux/drivers/net/rrunner.h linux/drivers/net/rrunner.h --- v2.4.14/linux/drivers/net/rrunner.h Mon Dec 11 13:01:04 2000 +++ linux/drivers/net/rrunner.h Fri Nov 9 13:45:35 2001 @@ -478,6 +478,7 @@ * Mode bits */ +#define PACKET_BAD 0x01 /* Packet had link-layer error */ #define INTERRUPT 0x02 #define TX_IP_CKSUM 0x04 #define PACKET_END 0x08 diff -u --recursive --new-file v2.4.14/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v2.4.14/linux/drivers/net/slhc.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/net/slhc.c Fri Nov 9 14:02:24 2001 @@ -797,4 +797,4 @@ EXPORT_SYMBOL(slhc_toss); #endif /* CONFIG_INET */ -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -u --recursive --new-file v2.4.14/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.4.14/linux/drivers/net/strip.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/net/strip.c Fri Nov 9 14:02:24 2001 @@ -2871,7 +2871,7 @@ MODULE_AUTHOR("Stuart Cheshire <cheshire@cs.stanford.edu>"); MODULE_DESCRIPTION("Starmode Radio IP (STRIP) Device Driver"); -MODULE_LICENSE("BSD without advertisement clause"); +MODULE_LICENSE("Dual BSD/GPL"); MODULE_SUPPORTED_DEVICE("Starmode Radio IP (STRIP) modem"); diff -u --recursive --new-file v2.4.14/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c --- v2.4.14/linux/drivers/net/tokenring/ibmtr.c Sun Sep 23 11:40:58 2001 +++ linux/drivers/net/tokenring/ibmtr.c Fri Nov 9 14:02:24 2001 @@ -1230,6 +1230,7 @@ ti->open_action = RESTART; outb(0, dev->base_addr + ADAPTRESET); ibmtr_reset_timer(&(ti->tr_timer), dev);/*BMS try to reopen*/ + spin_unlock(&(ti->lock)); return; } if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) diff -u --recursive --new-file v2.4.14/linux/drivers/net/tokenring/lanstreamer.c linux/drivers/net/tokenring/lanstreamer.c --- v2.4.14/linux/drivers/net/tokenring/lanstreamer.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/net/tokenring/lanstreamer.c Fri Nov 9 13:41:42 2001 @@ -299,7 +299,7 @@ streamer_priv->streamer_ring_speed = ringspeed[card_no]; streamer_priv->streamer_message_level = message_level[card_no]; - pdev->driver_data=dev; + pci_set_drvdata(pdev, dev); spin_lock_init(&streamer_priv->streamer_lock); @@ -329,7 +329,7 @@ } static void __devexit streamer_remove_one(struct pci_dev *pdev) { - struct net_device *dev=pdev->driver_data; + struct net_device *dev=pci_get_drv_data(pdev); struct streamer_private *streamer_priv; #if STREAMER_DEBUG @@ -373,7 +373,7 @@ release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev,0)); release_mem_region(pci_resource_start(pdev, 1), pci_resource_len(pdev,1)); kfree(dev); - pdev->driver_data=NULL; + pci_set_drvdata(pdev, NULL); } @@ -1704,7 +1704,7 @@ for(sdev=dev_streamer; sdev; sdev=sdev->next) { pci_device=sdev->pci_dev; - dev=pci_device->driver_data; + dev=pci_get_drvdata(pci_device); size = sprintf_info(buffer + len, dev); len += size; diff -u --recursive --new-file v2.4.14/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c --- v2.4.14/linux/drivers/net/tokenring/olympic.c Sun Sep 23 11:40:58 2001 +++ linux/drivers/net/tokenring/olympic.c Fri Nov 9 13:46:29 2001 @@ -737,7 +737,7 @@ } else { if (buffer_cnt == 1) { - skb = dev_alloc_skb(olympic_priv->pkt_buf_sz) ; + skb = dev_alloc_skb(max_t(int, olympic_priv->pkt_buf_sz,length)) ; } else { skb = dev_alloc_skb(length) ; } @@ -1684,7 +1684,7 @@ static void __devexit olympic_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data ; + struct net_device *dev = pci_get_drvdata(pdev) ; struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; if (olympic_priv->olympic_network_monitor) { @@ -1722,4 +1722,4 @@ module_init(olympic_pci_init) ; module_exit(olympic_pci_cleanup) ; -MODULE_LICENSE("GPL"); \ No newline at end of file +MODULE_LICENSE("GPL"); diff -u --recursive --new-file v2.4.14/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c --- v2.4.14/linux/drivers/net/tulip/21142.c Wed Jul 25 17:10:22 2001 +++ linux/drivers/net/tulip/21142.c Fri Nov 9 13:45:35 2001 @@ -106,10 +106,6 @@ dev->if_port = 0; tp->nway = tp->mediasense = 1; tp->nwayset = tp->lpar = 0; - if (tp->chip_id == PNIC2) { - tp->csr6 = 0x01000000 | (tp->sym_advertise & 0x0040 ? FullDuplex : 0); - return; - } if (tulip_debug > 1) printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%8.8x.\n", dev->name, csr14); @@ -127,23 +123,6 @@ } -void pnic2_lnk_change(struct net_device *dev, int csr5) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr12 = inl(ioaddr + CSR12); - - if (tulip_debug > 1) - printk(KERN_INFO"%s: PNIC-2 link status changed, CSR5/12/14 %8.8x" - " %8.8x, %8.8x.\n", - dev->name, csr12, csr5, (int)inl(ioaddr + CSR14)); - dev->if_port = 5; - tp->lpar = csr12 >> 16; - tp->nwayset = 1; - tp->csr6 = 0x01000000 | (tp->csr6 & 0xffff); - outl(tp->csr6, ioaddr + CSR6); - -} void t21142_lnk_change(struct net_device *dev, int csr5) { diff -u --recursive --new-file v2.4.14/linux/drivers/net/tulip/ChangeLog linux/drivers/net/tulip/ChangeLog --- v2.4.14/linux/drivers/net/tulip/ChangeLog Wed Jul 25 17:10:22 2001 +++ linux/drivers/net/tulip/ChangeLog Fri Nov 9 13:45:35 2001 @@ -1,3 +1,24 @@ +2001-11-06 Richard Mortimer <richm@oldelvet.netscapeonline.co.uk> + + * tulip_core.c: Correct set of values to mask out of csr0, + for DM9102A chips. Limit burst/alignment of DM9102A chips + on Sparcs. + +2001-11-06 Jun Sun <jsun@mvista.com> + + * tulip_core.c: Support finding MAC address on + two MIPS boards, DDB5476 and DDB5477. + +2001-11-06 Kevin B. Hendricks <khendricks@ivey.uwo.ca> + + * Makefile, tulip.h, tulip_core.c, pnic2.c, 21142.c: + Fixes for PNIC II support. + +2001-11-06 David S. Miller <davem@redhat.com> + + * tulip_core.c: Support reading MAC address from + Sparc OBP property local-mac-address. + 2001-07-17 Erik A. Hendriks <hendriks@lanl.gov> * 21142.c: Merge fix from tulip.c 0.92w which prevents the diff -u --recursive --new-file v2.4.14/linux/drivers/net/tulip/Makefile linux/drivers/net/tulip/Makefile --- v2.4.14/linux/drivers/net/tulip/Makefile Tue Apr 3 10:19:43 2001 +++ linux/drivers/net/tulip/Makefile Fri Nov 9 13:45:35 2001 @@ -11,7 +11,7 @@ obj-y := eeprom.o interrupt.o media.o \ timer.o tulip_core.o \ - 21142.o pnic.o + 21142.o pnic.o pnic2.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.14/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c --- v2.4.14/linux/drivers/net/tulip/interrupt.c Tue Oct 23 22:48:51 2001 +++ linux/drivers/net/tulip/interrupt.c Fri Nov 9 13:45:35 2001 @@ -28,8 +28,8 @@ #define MIT_SIZE 15 unsigned int mit_table[MIT_SIZE+1] = { - /* CRS11 21143 hardware Mitigation Control Interrupt - We use only RX mitigation we other techniques for + /* CRS11 21143 hardware Mitigation Control Interrupt + We use only RX mitigation we other techniques for TX intr. mitigation. 31 Cycle Size (timer control) @@ -39,7 +39,7 @@ 19:17 RX No pkts before Int. 16 Continues Mode (CM) */ - + 0x0, /* IM disabled */ 0x80150000, /* RX time = 1, RX pkts = 2, CM = 1 */ 0x80150000, @@ -110,7 +110,7 @@ #ifdef CONFIG_NET_HW_FLOWCONTROL int drop = 0, mit_sel = 0; -/* that one buffer is needed for mit activation; or might be a +/* that one buffer is needed for mit activation; or might be a bug in the ring buffer code; check later -- JHS*/ if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--; @@ -210,7 +210,7 @@ } skb->protocol = eth_type_trans(skb, dev); #ifdef CONFIG_NET_HW_FLOWCONTROL - mit_sel = + mit_sel = #endif netif_rx(skb); @@ -258,34 +258,34 @@ /* We use this simplistic scheme for IM. It's proven by real life installations. We can have IM enabled - continuesly but this would cause unnecessary latency. - Unfortunely we can't use all the NET_RX_* feedback here. - This would turn on IM for devices that is not contributing - to backlog congestion with unnecessary latency. + continuesly but this would cause unnecessary latency. + Unfortunely we can't use all the NET_RX_* feedback here. + This would turn on IM for devices that is not contributing + to backlog congestion with unnecessary latency. We monitor the the device RX-ring and have: HW Interrupt Mitigation either ON or OFF. - ON: More then 1 pkt received (per intr.) OR we are dropping + ON: More then 1 pkt received (per intr.) OR we are dropping OFF: Only 1 pkt received - + Note. We only use min and max (0, 15) settings from mit_table */ if( tp->flags & HAS_INTR_MITIGATION) { - if((received > 1 || mit_sel == NET_RX_DROP) - && tp->mit_sel != 15 ) { - tp->mit_sel = 15; + if((received > 1 || mit_sel == NET_RX_DROP) + && tp->mit_sel != 15 ) { + tp->mit_sel = 15; tp->mit_change = 1; /* Force IM change */ } if((received <= 1 && mit_sel != NET_RX_DROP) && tp->mit_sel != 0 ) { - tp->mit_sel = 0; + tp->mit_sel = 0; tp->mit_change = 1; /* Force IM change */ } } - return RX_RING_SIZE+1; /* maxrx+1 */ + return RX_RING_SIZE+1; /* maxrx+1 */ #else return received; #endif diff -u --recursive --new-file v2.4.14/linux/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c --- v2.4.14/linux/drivers/net/tulip/pnic.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/tulip/pnic.c Fri Nov 9 13:45:35 2001 @@ -62,7 +62,7 @@ dev->name, phy_reg, csr5); if (inl(ioaddr + CSR5) & TPLnkFail) { outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); - /* If we use an external MII, then we mustn't use the + /* If we use an external MII, then we mustn't use the * internal negotiation. */ if (tulip_media_cap[dev->if_port] & MediaIsMII) @@ -92,7 +92,7 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; - + if(!inl(ioaddr + CSR7)) { /* the timer was called due to a work overflow * in the interrupt handler. Skip the connection diff -u --recursive --new-file v2.4.14/linux/drivers/net/tulip/pnic2.c linux/drivers/net/tulip/pnic2.c --- v2.4.14/linux/drivers/net/tulip/pnic2.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tulip/pnic2.c Fri Nov 9 13:45:35 2001 @@ -0,0 +1,407 @@ +/* + drivers/net/tulip/pnic2.c + + Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> + Copyright 2000,2001 The Linux Kernel Team + Written/copyright 1994-2001 by Donald Becker. + Modified to hep support PNIC_II by Kevin B. Hendricks + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + Please refer to Documentation/DocBook/tulip.{pdf,ps,html} + for more information on this driver, or visit the project + Web page at http://sourceforge.net/projects/tulip/ + +*/ + + +/* Understanding the PNIC_II - everything is this file is based + * on the PNIC_II_PDF datasheet which is sorely lacking in detail + * + * As I understand things, here are the registers and bits that + * explain the masks and constants used in this file that are + * either different from the 21142/3 or important for basic operation. + * + * + * CSR 6 (mask = 0xfe3bd1fd of bits not to change) + * ----- + * Bit 24 - SCR + * Bit 23 - PCS + * Bit 22 - TTM (Trasmit Threshold Mode) + * Bit 18 - Port Select + * Bit 13 - Start - 1, Stop - 0 Transmissions + * Bit 11:10 - Loop Back Operation Mode + * Bit 9 - Full Duplex mode (Advertise 10BaseT-FD is CSR14<7> is set) + * Bit 1 - Start - 1, Stop - 0 Receive + * + * + * CSR 14 (mask = 0xfff0ee39 of bits not to change) + * ------ + * Bit 19 - PAUSE-Pause + * Bit 18 - Advertise T4 + * Bit 17 - Advertise 100baseTx-FD + * Bit 16 - Advertise 100baseTx-HD + * Bit 12 - LTE - Link Test Enable + * Bit 7 - ANE - Auto Negotiate Enable + * Bit 6 - HDE - Advertise 10baseT-HD + * Bit 2 - Reset to Power down - kept as 1 for normal operation + * Bit 1 - Loop Back enable for 10baseT MCC + * + * + * CSR 12 + * ------ + * Bit 25 - Partner can do T4 + * Bit 24 - Partner can do 100baseTx-FD + * Bit 23 - Partner can do 100baseTx-HD + * Bit 22 - Partner can do 10baseT-FD + * Bit 21 - Partner can do 10baseT-HD + * Bit 15 - LPN is 1 if all above bits are valid other wise 0 + * Bit 14:12 - autonegotiation state (write 001 to start autonegotiate) + * Bit 3 - Autopolarity state + * Bit 2 - LS10B - link state of 10baseT 0 - good, 1 - failed + * Bit 1 - LS100B - link state of 100baseT 0 - good, 1- faild + * + * + * Data Port Selection Info + *------------------------- + * + * CSR14<7> CSR6<18> CSR6<22> CSR6<23> CSR6<24> MODE/PORT + * 1 0 0 (X) 0 (X) 1 NWAY + * 0 0 1 0 (X) 0 10baseT + * 0 1 0 1 1 (X) 100baseT + * + * + */ + + + +#include "tulip.h" +#include <linux/pci.h> +#include <linux/delay.h> + + +void pnic2_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 3) + printk(KERN_INFO"%s: PNIC2 negotiation status %8.8x.\n", + dev->name,inl(ioaddr + CSR12)); + + if (next_tick) { + mod_timer(&tp->timer, RUN_AT(next_tick)); + } +} + + +void pnic2_start_nway(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr14; + int csr12; + + /* set up what to advertise during the negotiation */ + + /* load in csr14 and mask off bits not to touch + * comment at top of file explains mask value + */ + csr14 = (inl(ioaddr + CSR14) & 0xfff0ee39); + + /* bit 17 - advetise 100baseTx-FD */ + if (tp->sym_advertise & 0x0100) csr14 |= 0x00020000; + + /* bit 16 - advertise 100baseTx-HD */ + if (tp->sym_advertise & 0x0080) csr14 |= 0x00010000; + + /* bit 6 - advertise 10baseT-HD */ + if (tp->sym_advertise & 0x0020) csr14 |= 0x00000040; + + /* Now set bit 12 Link Test Enable, Bit 7 Autonegotiation Enable + * and bit 0 Don't PowerDown 10baseT + */ + csr14 |= 0x00001184; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, " + "csr14=%8.8x.\n", dev->name, csr14); + + /* tell pnic2_lnk_change we are doing an nway negotiation */ + dev->if_port = 0; + tp->nway = tp->mediasense = 1; + tp->nwayset = tp->lpar = 0; + + /* now we have to set up csr6 for NWAY state */ + + tp->csr6 = inl(ioaddr + CSR6); + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: On Entry to Nway, " + "csr6=%8.8x.\n", dev->name, tp->csr6); + + /* mask off any bits not to touch + * comment at top of file explains mask value + */ + tp->csr6 = tp->csr6 & 0xfe3bd1fd; + + /* don't forget that bit 9 is also used for advertising */ + /* advertise 10baseT-FD for the negotiation (bit 9) */ + if (tp->sym_advertise & 0x0040) tp->csr6 |= 0x00000200; + + /* set bit 24 for nway negotiation mode ... + * see Data Port Selection comment at top of file + * and "Stop" - reset both Transmit (bit 13) and Receive (bit 1) + */ + tp->csr6 |= 0x01000000; + outl(csr14, ioaddr + CSR14); + outl(tp->csr6, ioaddr + CSR6); + udelay(100); + + /* all set up so now force the negotiation to begin */ + + /* read in current values and mask off all but the + * Autonegotiation bits 14:12. Writing a 001 to those bits + * should start the autonegotiation + */ + csr12 = (inl(ioaddr + CSR12) & 0xffff8fff); + csr12 |= 0x1000; + outl(csr12, ioaddr + CSR12); +} + + + +void pnic2_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr14; + + /* read the staus register to find out what is up */ + int csr12 = inl(ioaddr + CSR12); + + if (tulip_debug > 1) + printk(KERN_INFO"%s: PNIC2 link status interrupt %8.8x, " + " CSR5 %x, %8.8x.\n", dev->name, csr12, + csr5, inl(ioaddr + CSR14)); + + /* If NWay finished and we have a negotiated partner capability. + * check bits 14:12 for bit pattern 101 - all is good + */ + if (tp->nway && !tp->nwayset) { + + /* we did an auto negotiation */ + + if ((csr12 & 0x7000) == 0x5000) { + + /* negotiation ended successfully */ + + /* get the link partners reply and mask out all but + * bits 24-21 which show the partners capabilites + * and match those to what we advertised + * + * then begin to interpret the results of the negotiation. + * Always go in this order : (we are ignoring T4 for now) + * 100baseTx-FD, 100baseTx-HD, 10baseT-FD, 10baseT-HD + */ + + int negotiated = ((csr12 >> 16) & 0x01E0) & tp->sym_advertise; + tp->lpar = (csr12 >> 16); + tp->nwayset = 1; + + if (negotiated & 0x0100) dev->if_port = 5; + else if (negotiated & 0x0080) dev->if_port = 3; + else if (negotiated & 0x0040) dev->if_port = 4; + else if (negotiated & 0x0020) dev->if_port = 0; + else { + if (tulip_debug > 1) + printk(KERN_INFO "%s: funny autonegotiate result " + "csr12 %8.8x advertising %4.4x\n", + dev->name, csr12, tp->sym_advertise); + tp->nwayset = 0; + /* so check if 100baseTx link state is okay */ + if ((csr12 & 2) == 0 && (tp->sym_advertise & 0x0180)) + dev->if_port = 3; + } + + /* now record the duplex that was negotiated */ + tp->full_duplex = 0; + if ((dev->if_port == 4) || (dev->if_port == 5)) + tp->full_duplex = 1; + + if (tulip_debug > 1) { + if (tp->nwayset) + printk(KERN_INFO "%s: Switching to %s based on link " + "negotiation %4.4x & %4.4x = %4.4x.\n", + dev->name, medianame[dev->if_port], + tp->sym_advertise, tp->lpar, negotiated); + } + + /* remember to turn off bit 7 - autonegotiate + * enable so we can properly end nway mode and + * set duplex (ie. use csr6<9> again) + */ + csr14 = (inl(ioaddr + CSR14) & 0xffffff7f); + outl(csr14,ioaddr + CSR14); + + + /* now set the data port and operating mode + * (see the Data Port Selection comments at + * the top of the file + */ + + /* get current csr6 and mask off bits not to touch */ + /* see comment at top of file */ + + tp->csr6 = (inl(ioaddr + CSR6) & 0xfe3bd1fd); + + /* so if using if_port 3 or 5 then select the 100baseT + * port else select the 10baseT port. + * See the Data Port Selection table at the top + * of the file which was taken from the PNIC_II.PDF + * datasheet + */ + if (dev->if_port & 1) tp->csr6 |= 0x01840000; + else tp->csr6 |= 0x00400000; + + /* now set the full duplex bit appropriately */ + if (tp->full_duplex) tp->csr6 |= 0x00000200; + + outl(1, ioaddr + CSR13); + + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 " + "%8.8x.\n", dev->name, tp->csr6, + inl(ioaddr + CSR6), inl(ioaddr + CSR12)); + + /* now the following actually writes out the + * new csr6 values + */ + tulip_start_rxtx(tp); + + return; + + } else { + printk(KERN_INFO "%s: Autonegotiation failed, " + "using %s, link beat status %4.4x.\n", + dev->name, medianame[dev->if_port], csr12); + + /* remember to turn off bit 7 - autonegotiate + * enable so we don't forget + */ + csr14 = (inl(ioaddr + CSR14) & 0xffffff7f); + outl(csr14,ioaddr + CSR14); + + /* what should we do when autonegotiate fails? + * should we try again or default to baseline + * case. I just don't know. + * + * for now default to some baseline case + */ + + dev->if_port = 0; + tp->nway = 0; + tp->nwayset = 1; + + /* set to 10baseTx-HD - see Data Port Selection + * comment given at the top of the file + */ + tp->csr6 = (inl(ioaddr + CSR6) & 0xfe3bd1fd); + tp->csr6 |= 0x00400000; + + tulip_restart_rxtx(tp); + + return; + + } + } + + if ((tp->nwayset && (csr5 & 0x08000000) + && (dev->if_port == 3 || dev->if_port == 5) + && (csr12 & 2) == 2) || (tp->nway && (csr5 & (TPLnkFail)))) { + + /* Link blew? Maybe restart NWay. */ + + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Ugh! Link blew?\n", dev->name); + + del_timer_sync(&tp->timer); + pnic2_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + + return; + } + + + if (dev->if_port == 3 || dev->if_port == 5) { + + /* we are at 100mb and a potential link change occurred */ + + if (tulip_debug > 1) + printk(KERN_INFO"%s: PNIC2 %s link beat %s.\n", + dev->name, medianame[dev->if_port], + (csr12 & 2) ? "failed" : "good"); + + /* check 100 link beat */ + + tp->nway = 0; + tp->nwayset = 1; + + /* if failed then try doing an nway to get in sync */ + if ((csr12 & 2) && ! tp->medialock) { + del_timer_sync(&tp->timer); + pnic2_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } + + return; + } + + if (dev->if_port == 0 || dev->if_port == 4) { + + /* we are at 10mb and a potential link change occurred */ + + if (tulip_debug > 1) + printk(KERN_INFO"%s: PNIC2 %s link beat %s.\n", + dev->name, medianame[dev->if_port], + (csr12 & 4) ? "failed" : "good"); + + + tp->nway = 0; + tp->nwayset = 1; + + /* if failed, try doing an nway to get in sync */ + if ((csr12 & 4) && ! tp->medialock) { + del_timer_sync(&tp->timer); + pnic2_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } + + return; + } + + + if (tulip_debug > 1) + printk(KERN_INFO"%s: PNIC2 Link Change Default?\n",dev->name); + + /* if all else fails default to trying 10baseT-HD */ + dev->if_port = 0; + + /* make sure autonegotiate enable is off */ + csr14 = (inl(ioaddr + CSR14) & 0xffffff7f); + outl(csr14,ioaddr + CSR14); + + /* set to 10baseTx-HD - see Data Port Selection + * comment given at the top of the file + */ + tp->csr6 = (inl(ioaddr + CSR6) & 0xfe3bd1fd); + tp->csr6 |= 0x00400000; + + tulip_restart_rxtx(tp); +} + diff -u --recursive --new-file v2.4.14/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h --- v2.4.14/linux/drivers/net/tulip/tulip.h Tue Jul 3 17:08:20 2001 +++ linux/drivers/net/tulip/tulip.h Fri Nov 9 13:45:35 2001 @@ -118,7 +118,7 @@ }; /* register offset and bits for CFDD PCI config reg */ -enum pci_cfg_driver_reg { +enum pci_cfg_driver_reg { CFDD = 0x40, CFDD_Sleep = (1 << 31), CFDD_Snooze = (1 << 30), @@ -405,6 +405,12 @@ void t21142_timer(unsigned long data); void t21142_start_nway(struct net_device *dev); void t21142_lnk_change(struct net_device *dev, int csr5); + + +/* PNIC2.c */ +void pnic2_lnk_change(struct net_device *dev, int csr5); +void pnic2_timer(unsigned long data); +void pnic2_start_nway(struct net_device *dev); void pnic2_lnk_change(struct net_device *dev, int csr5); /* eeprom.c */ diff -u --recursive --new-file v2.4.14/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.4.14/linux/drivers/net/tulip/tulip_core.c Tue Oct 23 22:48:51 2001 +++ linux/drivers/net/tulip/tulip_core.c Fri Nov 9 13:45:35 2001 @@ -15,8 +15,8 @@ */ #define DRV_NAME "tulip" -#define DRV_VERSION "0.9.15-pre8" -#define DRV_RELDATE "Oct 11, 2001" +#define DRV_VERSION "0.9.15-pre9" +#define DRV_RELDATE "Nov 6, 2001" #include <linux/config.h> #include <linux/module.h> @@ -30,6 +30,10 @@ #include <asm/unaligned.h> #include <asm/uaccess.h> +#ifdef __sparc__ +#include <asm/pbm.h> +#endif + static char version[] __devinitdata = "Linux Tulip driver version " DRV_VERSION " (" DRV_RELDATE ")\n"; @@ -165,7 +169,7 @@ /* PNIC2 */ { "Lite-On PNIC-II", 256, 0x0801fbff, - HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, t21142_timer }, + HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, pnic2_timer }, /* COMET */ { "ADMtek Comet", 256, 0x0001abef, @@ -261,7 +265,7 @@ if (tmp != newtmp) pci_write_config_dword (tp->pdev, CFDD, newtmp); } - + } @@ -297,14 +301,6 @@ tp->cur_rx = tp->cur_tx = 0; tp->dirty_rx = tp->dirty_tx = 0; - if (tp->chip_id == PNIC2) { - u32 addr_high = (dev->dev_addr[1]<<8) + (dev->dev_addr[0]<<0); - /* This address setting does not appear to impact chip operation?? */ - outl((dev->dev_addr[5]<<8) + dev->dev_addr[4] + - (dev->dev_addr[3]<<24) + (dev->dev_addr[2]<<16), - ioaddr + 0xB0); - outl(addr_high + (addr_high<<16), ioaddr + 0xB8); - } if (tp->flags & MC_HASH_ONLY) { u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); @@ -420,7 +416,12 @@ } else t21142_start_nway(dev); } else if (tp->chip_id == PNIC2) { - t21142_start_nway(dev); + /* for initial startup advertise 10/100 Full and Half */ + tp->sym_advertise = 0x01E0; + /* enable autonegotiate end interrupt */ + outl(inl(ioaddr+CSR5)| 0x00008010, ioaddr + CSR5); + outl(inl(ioaddr+CSR7)| 0x00008010, ioaddr + CSR7); + pnic2_start_nway(dev); } else if (tp->chip_id == LC82C168 && ! tp->medialock) { if (tp->mii_cnt) { dev->if_port = 11; @@ -901,7 +902,7 @@ { struct tulip_private *np = dev->priv; u32 ethcmd; - + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) return -EFAULT; @@ -917,7 +918,7 @@ } } - + return -EOPNOTSUPP; } @@ -971,7 +972,7 @@ case 4: /* Advertised value, bogus 10baseTx-FD value from CSR6. */ data->val_out = - ((inl(ioaddr + CSR6) >> 3) & 0x0040) + + ((inl(ioaddr + CSR6) >> 3) & 0x0040) + ((csr14 >> 1) & 0x20) + 1; if (tp->chip_id != DC21041) data->val_out |= ((csr14 >> 9) & 0x03C0); @@ -1007,8 +1008,13 @@ if (data->phy_id == 32 && (tp->flags & HAS_NWAY)) { u16 value = data->val_in; if (regnum == 0) { - if ((value & 0x1200) == 0x1200) - t21142_start_nway (dev); + if ((value & 0x1200) == 0x1200) { + if (tp->chip_id == PNIC2) { + pnic2_start_nway (dev); + } else { + t21142_start_nway (dev); + } + } } else if (regnum == 4) tp->sym_advertise = value; } else { @@ -1257,7 +1263,7 @@ u8 cache; u16 pci_command, new_command; u32 csr0; - + if (tulip_debug > 3) printk(KERN_DEBUG "%s: tulip_mwi_config()\n", pdev->slot_name); @@ -1283,7 +1289,7 @@ /* if we have any cache line size at all, we can do MRM */ csr0 |= MRM; - + /* ...and barring hardware bugs, MWI */ if (!(tp->chip_id == DC21143 && tp->revision == 65)) csr0 |= MWI; @@ -1321,7 +1327,7 @@ tp->csr0 = csr0; goto out; - + early_out: if (csr0 & MWI) { pci_command &= ~PCI_COMMAND_INVALIDATE; @@ -1369,16 +1375,16 @@ * Lan media wire a tulip chip to a wan interface. Needs a very * different driver (lmc driver) */ - + if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) { printk (KERN_ERR PFX "skipping LMC card.\n"); return -ENODEV; } - + /* * Early DM9100's need software CRC and the DMFE driver */ - + if (pdev->vendor == 0x1282 && pdev->device == 0x9100) { u32 dev_rev; @@ -1390,17 +1396,17 @@ return -ENODEV; } } - + /* - * Looks for early PCI chipsets where people report hangs + * Looks for early PCI chipsets where people report hangs * without the workarounds being on. */ - - /* Intel Saturn. Switch to 8 long words burst, 8 long word cache aligned + + /* Intel Saturn. Switch to 8 long words burst, 8 long word cache aligned Aries might need this too. The Saturn errata are not pretty reading but thankfully its an old 486 chipset. */ - + if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL)) { csr0 = MRL | MRM | (8 << BurstLenShift) | (1 << CALShift); force_csr0 = 1; @@ -1410,25 +1416,31 @@ csr0 = MRL | MRM | (8 << BurstLenShift) | (1 << CALShift); force_csr0 = 1; } - + /* bugfix: the ASIX must have a burst limit or horrible things happen. */ if (chip_idx == AX88140) { if ((csr0 & 0x3f00) == 0) csr0 |= 0x2000; } - + /* PNIC doesn't have MWI/MRL/MRM... */ if (chip_idx == LC82C168) csr0 &= ~0xfff10000; /* zero reserved bits 31:20, 16 */ - /* DM9102A has troubles with MRM, clear bit 24 too. */ + /* DM9102A has troubles with MRM & clear reserved bits 24:22, 20, 16, 7:1 */ if (pdev->vendor == 0x1282 && pdev->device == 0x9102) - csr0 &= ~0x01200000; + csr0 &= ~0x01f100ff; + +#if defined(__sparc__) + /* DM9102A needs 32-dword alignment/burst length on sparc - chip bug? */ + if (pdev->vendor == 0x1282 && pdev->device == 0x9102) + csr0 = (csr0 & ~0xff00) | 0xe000; +#endif /* * And back to business */ - + i = pci_enable_device(pdev); if (i) { printk (KERN_ERR PFX @@ -1575,6 +1587,22 @@ sa_offset = 2; /* Grrr, damn Matrox boards. */ multiport_cnt = 4; } +#ifdef CONFIG_DDB5476 + if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 6)) { + /* DDB5476 MAC address in first EEPROM locations. */ + sa_offset = 0; + /* No media table either */ + tp->flags &= ~HAS_MEDIA_TABLE; + } +#endif +#ifdef CONFIG_DDB5477 + if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 4)) { + /* DDB5477 MAC address in first EEPROM locations. */ + sa_offset = 0; + /* No media table either */ + tp->flags &= ~HAS_MEDIA_TABLE; + } +#endif for (i = 0; i < 6; i ++) { dev->dev_addr[i] = ee_data[i + sa_offset]; sum += ee_data[i + sa_offset]; @@ -1590,14 +1618,26 @@ } /* On the Zynx 315 Etherarray and other multiport boards only the first Tulip has an EEPROM. + On Sparc systems the mac address is held in the OBP property + "local-mac-address". The addresses of the subsequent ports are derived from the first. Many PCI BIOSes also incorrectly report the IRQ line, so we correct that here as well. */ if (sum == 0 || sum == 6*0xff) { +#if defined(__sparc__) + struct pcidev_cookie *pcp = pdev->sysdata; +#endif eeprom_missing = 1; for (i = 0; i < 5; i++) dev->dev_addr[i] = last_phys_addr[i]; dev->dev_addr[i] = last_phys_addr[i] + 1; +#if defined(__sparc__) + if ((pcp != NULL) && prom_getproplen(pcp->prom_node, + "local-mac-address") == 6) { + prom_getproperty(pcp->prom_node, "local-mac-address", + dev->dev_addr, 6); + } +#endif #if defined(__i386__) /* Patch up x86 BIOS bug. */ if (last_irq) irq = last_irq; @@ -1690,10 +1730,10 @@ printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]); printk(", IRQ %d.\n", irq); - if ((tp->flags & HAS_NWAY) || tp->chip_id == DC21041) - tp->link_change = t21142_lnk_change; - else if (tp->chip_id == PNIC2) + if (tp->chip_id == PNIC2) tp->link_change = pnic2_lnk_change; + else if ((tp->flags & HAS_NWAY) || tp->chip_id == DC21041) + tp->link_change = t21142_lnk_change; else if (tp->flags & HAS_PNICNWAY) tp->link_change = pnic_lnk_change; @@ -1719,7 +1759,6 @@ outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); break; case DC21142: - case PNIC2: if (tp->mii_cnt || tulip_media_cap[dev->if_port] & MediaIsMII) { outl(csr6_mask_defstate, ioaddr + CSR6); outl(0x0000, ioaddr + CSR13); @@ -1727,6 +1766,11 @@ outl(csr6_mask_hdcap, ioaddr + CSR6); } else t21142_start_nway(dev); + break; + case PNIC2: + /* just do a reset for sanity sake */ + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); break; case LC82C168: if ( ! tp->mii_cnt) { diff -u --recursive --new-file v2.4.14/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.4.14/linux/drivers/net/via-rhine.c Tue Oct 23 22:48:51 2001 +++ linux/drivers/net/via-rhine.c Fri Nov 9 13:45:36 2001 @@ -73,6 +73,9 @@ - David Woodhouse: Set dev->base_addr before the first time we call wait_for_reset(). It's a lot happier that way. Free np->tx_bufs only if we actually allocated it. + + LK1.1.12: + - Martin Eriksson: Allow Memory-Mapped IO to be enabled. */ @@ -155,7 +158,7 @@ /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = -KERN_INFO "via-rhine.c:v1.10-LK1.1.11 20/08/2001 Written by Donald Becker\n" +KERN_INFO "via-rhine.c:v1.10-LK1.1.12 03/11/2001 Written by Donald Becker\n" KERN_INFO " http://www.scyld.com/network/via-rhine.html\n"; static char shortname[] __devinitdata = "via-rhine"; @@ -163,9 +166,8 @@ /* This driver was written to use PCI memory space, however most versions of the Rhine only work correctly with I/O space accesses. */ -#if defined(VIA_USE_MEMORY) -#warning Many adapters using the VIA Rhine chip are not configured to work -#warning with PCI memory space accesses. +#ifdef CONFIG_VIA_RHINE_MMIO +#define USE_MEM #else #define USE_IO #undef readb @@ -318,12 +320,10 @@ CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4, ReqTxAlign=0x10, HasWOL=0x20, }; -#if defined(VIA_USE_MEMORY) +#ifdef USE_MEM #define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1) -#define RHINEII_IOSIZE 4096 #else #define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR0) -#define RHINEII_IOSIZE 256 #endif /* directly indexed by enum via_rhine_chips, above */ @@ -331,7 +331,7 @@ { { "VIA VT86C100A Rhine", RHINE_IOTYPE, 128, CanHaveMII | ReqTxAlign }, - { "VIA VT6102 Rhine-II", RHINE_IOTYPE, RHINEII_IOSIZE, + { "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256, CanHaveMII | HasWOL }, { "VIA VT3043 Rhine", RHINE_IOTYPE, 128, CanHaveMII | ReqTxAlign } @@ -355,10 +355,19 @@ RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54, MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74, - Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E, + ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B, + RxMissed=0x7C, RxCRCErrs=0x7E, StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC, }; +#ifdef USE_MEM +/* Registers we check that mmio and reg are the same. */ +int mmio_verify_registers[] = { + RxConfig, TxConfig, IntrEnable, ConfigA, ConfigB, ConfigC, ConfigD, + 0 +}; +#endif + /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020, @@ -505,6 +514,31 @@ name, 5*i); } +#ifdef USE_MEM +static void __devinit enable_mmio(long ioaddr, int chip_id) +{ + int n; + if (chip_id == VT3043 || chip_id == VT86C100A) { + /* More recent docs say that this bit is reserved ... */ + n = inb(ioaddr + ConfigA) | 0x20; + outb(n, ioaddr + ConfigA); + } else if (chip_id == VT6102) { + n = inb(ioaddr + ConfigD) | 0x80; + outb(n, ioaddr + ConfigD); + } +} +#endif + +static void __devinit reload_eeprom(long ioaddr) +{ + int i; + outb(0x20, ioaddr + MACRegEEcsr); + /* Typically 2 cycles to reload. */ + for (i = 0; i < 150; i++) + if (! (inb(ioaddr + MACRegEEcsr) & 0x20)) + break; +} + static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -514,8 +548,12 @@ int chip_id = (int) ent->driver_data; static int card_idx = -1; long ioaddr; + long memaddr; int io_size; int pci_flags; +#ifdef USE_MEM + long ioaddr0; +#endif /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -545,8 +583,9 @@ goto err_out; } - ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1); - + ioaddr = pci_resource_start (pdev, 0); + memaddr = pci_resource_start (pdev, 1); + if (pci_flags & PCI_USES_MASTER) pci_set_master (pdev); @@ -560,14 +599,29 @@ if (pci_request_regions(pdev, shortname)) goto err_out_free_netdev; -#ifndef USE_IO - ioaddr = (long) ioremap (ioaddr, io_size); +#ifdef USE_MEM + ioaddr0 = ioaddr; + enable_mmio(ioaddr0, chip_id); + + ioaddr = (long) ioremap (memaddr, io_size); if (!ioaddr) { - printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n", - pdev->slot_name, io_size, - pci_resource_start (pdev, 1)); + printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%lX\n", + pdev->slot_name, io_size, memaddr); goto err_out_free_res; } + + /* Check that selected MMIO registers match the PIO ones */ + i = 0; + while (mmio_verify_registers[i]) { + int reg = mmio_verify_registers[i++]; + unsigned char a = inb(ioaddr0+reg); + unsigned char b = readb(ioaddr+reg); + if (a != b) { + printk (KERN_ERR "MMIO do not match PIO [%02x] (%02x != %02x)\n", + reg, a, b); + goto err_out_unmap; + } + } #endif /* D-Link provided reset code (with comment additions) */ @@ -595,11 +649,16 @@ wait_for_reset(dev, shortname); /* Reload the station address from the EEPROM. */ - writeb(0x20, ioaddr + MACRegEEcsr); - /* Typically 2 cycles to reload. */ - for (i = 0; i < 150; i++) - if (! (readb(ioaddr + MACRegEEcsr) & 0x20)) - break; +#ifdef USE_IO + reload_eeprom(ioaddr); +#else + reload_eeprom(ioaddr0); + /* Reloading from eeprom overwrites cfgA-D, so we must re-enable MMIO. + If reload_eeprom() was done first this could be avoided, but it is + not known if that still works with the "win98-reboot" problem. */ + enable_mmio(ioaddr0, chip_id); +#endif + for (i = 0; i < 6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); @@ -660,7 +719,9 @@ goto err_out_unmap; printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, via_rhine_chip_info[chip_id].name, ioaddr); + dev->name, via_rhine_chip_info[chip_id].name, + (pci_flags & PCI_USES_IO) ? ioaddr : memaddr); + for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq); @@ -711,7 +772,7 @@ return 0; err_out_unmap: -#ifndef USE_IO +#ifdef USE_MEM iounmap((void *)ioaddr); err_out_free_res: #endif @@ -1587,18 +1648,17 @@ static void __devexit via_rhine_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct netdev_private *np = dev->priv; unregister_netdev(dev); pci_release_regions(pdev); -#ifndef USE_IO +#ifdef USE_MEM iounmap((char *)(dev->base_addr)); #endif kfree(dev); - + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } diff -u --recursive --new-file v2.4.14/linux/drivers/net/wan/dscc4.c linux/drivers/net/wan/dscc4.c --- v2.4.14/linux/drivers/net/wan/dscc4.c Sun Sep 23 11:40:59 2001 +++ linux/drivers/net/wan/dscc4.c Fri Nov 9 13:41:42 2001 @@ -672,7 +672,6 @@ ppriv->root = dev; ppriv->pdev = pdev; spin_lock_init(&ppriv->lock); - pdev->driver_data = ppriv; pci_set_drvdata(pdev, ppriv); return 0; diff -u --recursive --new-file v2.4.14/linux/drivers/net/wan/farsync.c linux/drivers/net/wan/farsync.c --- v2.4.14/linux/drivers/net/wan/farsync.c Sun Sep 23 11:40:59 2001 +++ linux/drivers/net/wan/farsync.c Fri Nov 9 13:41:42 2001 @@ -1746,7 +1746,7 @@ } /* Record driver data for later use */ - pdev->driver_data = card; + pci_set_drvdata(pdev, card); /* Remainder of card setup */ fst_init_card ( card ); @@ -1785,7 +1785,7 @@ struct fst_card_info *card; int i; - card = pdev->driver_data; + card = pci_get_drvdata(pdev); for ( i = 0 ; i < card->nports ; i++ ) { diff -u --recursive --new-file v2.4.14/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c --- v2.4.14/linux/drivers/net/wan/z85230.c Sun Sep 23 11:40:59 2001 +++ linux/drivers/net/wan/z85230.c Fri Nov 9 14:03:11 2001 @@ -4,8 +4,8 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * (c) Copyright 1998 Building Number Three Ltd - * (c) Copyright 2000 Red Hat Software + * (c) Copyright 1998 Alan Cox <alan@lxorguk.ukuu.org.uk> + * (c) Copyright 2000, 2001 Red Hat Inc * * Development of this driver was funded by Equiinet Ltd * http://www.equiinet.com @@ -18,6 +18,8 @@ * DMA now uses get_free_page as kmalloc buffers may span a 64K * boundary. * + * Modified for SMP safety and SMP locking by Alan Cox <alan@redhat.com> + * * Performance * * Z85230: @@ -53,8 +55,6 @@ #include "z85230.h" -static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED; - /** * z8530_read_port - Architecture specific interface function * @p: port to read @@ -116,21 +116,14 @@ * * Most of the Z8530 registers are indexed off the control registers. * A read is done by writing to the control register and reading the - * register back. We do the locking needed to protect this - * operation. + * register back. The caller must hold the lock */ static inline u8 read_zsreg(struct z8530_channel *c, u8 reg) { - u8 r; - unsigned long flags; - save_flags(flags); - cli(); if(reg) z8530_write_port(c->ctrlio, reg); - r=z8530_read_port(c->ctrlio); - restore_flags(flags); - return r; + return z8530_read_port(c->ctrlio); } /** @@ -154,7 +147,7 @@ * @reg: Register number * @val: Value to write * - * Write a value to an indexed register. Perform the locking needed + * Write a value to an indexed register. The caller must hold the lock * to honour the irritating delay rules. We know about register 0 * being fast to access. */ @@ -162,12 +155,14 @@ static inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) { unsigned long flags; - save_flags(flags); - cli(); + + spin_lock_irqsave(c->lock, flags); + if(reg) z8530_write_port(c->ctrlio, reg); z8530_write_port(c->ctrlio, val); - restore_flags(flags); + + spin_unlock_irqrestore(c->lock, flags); } /** @@ -299,7 +294,7 @@ * @set: 1 to set, 0 to clear * * Sets or clears DTR/RTS on the requested line. All locking is handled - * for the caller. For now we assume all boards use the actual RTS/DTR + * by the caller. For now we assume all boards use the actual RTS/DTR * on the chip. Apparently one or two don't. We'll scream about them * later. */ @@ -333,12 +328,14 @@ * do it yourself but consider medical assistance first. This non DMA * synchronous mode is portable code. The DMA mode assumes PCI like * ISA DMA + * + * Called with the device lock held */ static void z8530_rx(struct z8530_channel *c) { u8 ch,stat; - + while(1) { /* FIFO empty ? */ @@ -382,6 +379,10 @@ } else { + /* + * Drop the lock for RX processing, or + * there are deadlocks + */ z8530_rx_done(c); write_zsctrl(c, RES_Rx_CRC); } @@ -407,8 +408,7 @@ static void z8530_tx(struct z8530_channel *c) { - while(c->txcount) - { + while(c->txcount) { /* FIFO full ? */ if(!(read_zsreg(c, R0)&4)) break; @@ -424,8 +424,8 @@ write_zsctrl(c, RES_EOM_L); write_zsreg(c, R10, c->regs[10]&~ABUNDER); } - return; } + /* * End of frame TX - fire another one @@ -434,7 +434,6 @@ write_zsctrl(c, RES_Tx_P); z8530_tx_done(c); -/* write_zsreg(c, R8, *c->tx_ptr++); */ write_zsctrl(c, RES_H_IUS); } @@ -451,8 +450,10 @@ static void z8530_status(struct z8530_channel *chan) { - u8 status=read_zsreg(chan, R0); - u8 altered=chan->status^status; + u8 status, altered; + + status=read_zsreg(chan, R0); + altered=chan->status^status; chan->status=status; @@ -512,11 +513,12 @@ { /* Special condition check only */ u8 status; - + read_zsreg(chan, R7); read_zsreg(chan, R6); status=read_zsreg(chan, R1); + if(status&END_FR) { z8530_rx_done(chan); /* Fire up the next one */ @@ -565,16 +567,20 @@ static void z8530_dma_status(struct z8530_channel *chan) { - unsigned long flags; - u8 status=read_zsreg(chan, R0); - u8 altered=chan->status^status; + u8 status, altered; + + status=read_zsreg(chan, R0); + altered=chan->status^status; chan->status=status; + if(chan->dma_tx) { if(status&TxEOM) { + unsigned long flags; + flags=claim_dma_lock(); disable_dma(chan->txdma); clear_dma_ff(chan->txdma); @@ -706,6 +712,10 @@ * the channel specific call backs for each channel that has events. * We have to use callback functions because the two channels can be * in different modes. + * + * Locking is done for the handlers. Note that locking is done + * at the chip level (the 5uS delay issue is per chip not per + * channel). c->lock for both channels points to dev->lock */ void z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -714,6 +724,7 @@ u8 intr; static volatile int locker=0; int work=0; + struct z8530_irqhandler *irqs=dev->chanA.irqs; if(locker) { @@ -721,11 +732,12 @@ return; } locker=1; - + + spin_lock(&dev->lock); + while(++work<5000) { - struct z8530_irqhandler *irqs=dev->chanA.irqs; - + intr = read_zsreg(&dev->chanA, R3); if(!(intr & (CHARxIP|CHATxIP|CHAEXT|CHBRxIP|CHBTxIP|CHBEXT))) break; @@ -758,6 +770,7 @@ irqs->status(&dev->chanB); } } + spin_unlock(&dev->lock); if(work==5000) printk(KERN_ERR "%s: interrupt jammed - abort(0x%X)!\n", dev->name, intr); /* Ok all done */ @@ -786,12 +799,17 @@ int z8530_sync_open(struct net_device *dev, struct z8530_channel *c) { + unsigned long flags; + + spin_lock_irqsave(c->lock, flags); + c->sync = 1; c->mtu = dev->mtu+64; c->count = 0; c->skb = NULL; c->skb2 = NULL; c->irqs = &z8530_sync; + /* This loads the double buffer up */ z8530_rx_done(c); /* Load the frame ring */ z8530_rx_done(c); /* Load the backup frame */ @@ -800,6 +818,8 @@ c->regs[R1]|=TxINT_ENAB; write_zsreg(c, R1, c->regs[R1]); write_zsreg(c, R3, c->regs[R3]|RxENABLE); + + spin_unlock_irqrestore(c->lock, flags); return 0; } @@ -818,7 +838,9 @@ int z8530_sync_close(struct net_device *dev, struct z8530_channel *c) { u8 chk; + unsigned long flags; + spin_lock_irqsave(c->lock, flags); c->irqs = &z8530_nop; c->max = 0; c->sync = 0; @@ -826,6 +848,8 @@ chk=read_zsreg(c,R0); write_zsreg(c, R3, c->regs[R3]); z8530_rtsdtr(c,0); + + spin_unlock_irqrestore(c->lock, flags); return 0; } @@ -887,6 +911,8 @@ /* * Enable DMA control mode */ + + spin_lock_irqsave(c->lock, flags); /* * TX DMA via DIR/REQ @@ -945,6 +971,8 @@ c->irqs = &z8530_dma_sync; z8530_rtsdtr(c,1); write_zsreg(c, R3, c->regs[R3]|RxENABLE); + + spin_unlock_irqrestore(c->lock, flags); return 0; } @@ -986,6 +1014,8 @@ c->txdma_on = 0; c->tx_dma_used = 0; + spin_lock_irqsave(c->lock, flags); + /* * Disable DMA control mode */ @@ -1011,6 +1041,9 @@ chk=read_zsreg(c,R0); write_zsreg(c, R3, c->regs[R3]); z8530_rtsdtr(c,0); + + spin_unlock_irqrestore(c->lock, flags); + return 0; } @@ -1038,20 +1071,6 @@ c->skb2 = NULL; /* - * Load the PIO receive ring - */ - - z8530_rx_done(c); - z8530_rx_done(c); - - /* - * Load the DMA interfaces up - */ - - c->rxdma_on = 0; - c->txdma_on = 0; - - /* * Allocate the DMA flip buffers. Limit by page size. * Everyone runs 1500 mtu or less on wan links so this * should be fine. @@ -1066,6 +1085,23 @@ c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE/2; + + spin_lock_irqsave(c->lock, flags); + + /* + * Load the PIO receive ring + */ + + z8530_rx_done(c); + z8530_rx_done(c); + + /* + * Load the DMA interfaces up + */ + + c->rxdma_on = 0; + c->txdma_on = 0; + c->tx_dma_used=0; c->dma_num=0; c->dma_ready=1; @@ -1106,10 +1142,9 @@ c->tx_dma_used = 1; c->irqs = &z8530_txdma_sync; - printk("Loading RX\n"); z8530_rtsdtr(c,1); - printk("Rx interrupts ON\n"); write_zsreg(c, R3, c->regs[R3]|RxENABLE); + spin_unlock_irqrestore(c->lock, flags); return 0; } @@ -1129,6 +1164,9 @@ { unsigned long flags; u8 chk; + + + spin_lock_irqsave(c->lock, flags); c->irqs = &z8530_nop; c->max = 0; @@ -1208,25 +1246,11 @@ EXPORT_SYMBOL(z8530_describe); -/** - * z8530_init - Initialise a Z8530 device - * @dev: Z8530 device to initialise. - * - * Configure up a Z8530/Z85C30 or Z85230 chip. We check the device - * is present, identify the type and then program it to hopefully - * keep quite and behave. This matters a lot, a Z8530 in the wrong - * state will sometimes get into stupid modes generating 10Khz - * interrupt streams and the like. - * - * We set the interrupt handler up to discard any events, in case - * we get them during reset or setp. - * - * Return 0 for success, or a negative value indicating the problem - * in errno form. +/* + * Locked operation part of the z8530 init code */ - -int z8530_init(struct z8530_dev *dev) +static int do_z8530_init(struct z8530_dev *dev) { /* NOP the interrupt handlers first - we might get a floating IRQ transition when we reset the chip */ @@ -1234,6 +1258,12 @@ dev->chanB.irqs=&z8530_nop; dev->chanA.dcdcheck=DCD; dev->chanB.dcdcheck=DCD; + + /* Set up the chip level lock */ + spin_lock_init(&dev->lock); + dev->chanA.lock = &dev->lock; + dev->chanB.lock = &dev->lock; + /* Reset the chip */ write_zsreg(&dev->chanA, R9, 0xC0); udelay(200); @@ -1287,6 +1317,40 @@ return 0; } +/** + * z8530_init - Initialise a Z8530 device + * @dev: Z8530 device to initialise. + * + * Configure up a Z8530/Z85C30 or Z85230 chip. We check the device + * is present, identify the type and then program it to hopefully + * keep quite and behave. This matters a lot, a Z8530 in the wrong + * state will sometimes get into stupid modes generating 10Khz + * interrupt streams and the like. + * + * We set the interrupt handler up to discard any events, in case + * we get them during reset or setp. + * + * Return 0 for success, or a negative value indicating the problem + * in errno form. + */ + +int z8530_init(struct z8530_dev *dev) +{ + unsigned long flags; + int ret; + + /* Set up the chip level lock */ + spin_lock_init(&dev->lock); + dev->chanA.lock = &dev->lock; + dev->chanB.lock = &dev->lock; + + spin_lock_irqsave(&dev->lock, flags); + ret = do_z8530_init(dev); + spin_unlock_irqrestore(&dev->lock, flags); + + return ret; +} + EXPORT_SYMBOL(z8530_init); @@ -1297,15 +1361,22 @@ * We set the interrupt handlers to silence any interrupts. We then * reset the chip and wait 100uS to be sure the reset completed. Just * in case the caller then tries to do stuff. + * + * This is called without the lock held */ int z8530_shutdown(struct z8530_dev *dev) { + unsigned long flags; /* Reset the chip */ + + spin_lock_irqsave(&dev->lock, flags); dev->chanA.irqs=&z8530_nop; dev->chanB.irqs=&z8530_nop; write_zsreg(&dev->chanA, R9, 0xC0); + /* We must lock the udelay, the chip is offlimits here */ udelay(100); + spin_unlock_irqrestore(&dev->lock, flags); return 0; } @@ -1324,6 +1395,10 @@ int z8530_channel_load(struct z8530_channel *c, u8 *rtable) { + unsigned long flags; + + spin_lock_irqsave(c->lock, flags); + while(*rtable!=255) { int reg=*rtable++; @@ -1344,6 +1419,8 @@ c->status=read_zsreg(c, R0); c->sync=1; write_zsreg(c, R3, c->regs[R3]|RxENABLE); + + spin_unlock_irqrestore(c->lock, flags); return 0; } @@ -1360,6 +1437,8 @@ * * Note: We are handling this code path in the interrupt path, keep it * fast or bad things will happen. + * + * Called with the lock held. */ static void z8530_tx_begin(struct z8530_channel *c) @@ -1430,8 +1509,7 @@ } else { - save_flags(flags); - cli(); + /* ABUNDER off */ write_zsreg(c, R10, c->regs[10]); write_zsctrl(c, RES_Tx_CRC); @@ -1442,7 +1520,7 @@ write_zsreg(c, R8, *c->tx_ptr++); c->txcount--; } - restore_flags(flags); + } } } @@ -1454,25 +1532,22 @@ * This is called when we complete a packet send. We wake the queue, * start the next packet going and then free the buffer of the existing * packet. This code is fairly timing sensitive. + * + * Called with the register lock held. */ static void z8530_tx_done(struct z8530_channel *c) { - unsigned long flags; struct sk_buff *skb; - spin_lock_irqsave(&z8530_buffer_lock, flags); netif_wake_queue(c->netdevice); /* Actually this can happen.*/ if(c->tx_skb==NULL) - { - spin_unlock_irqrestore(&z8530_buffer_lock, flags); return; - } + skb=c->tx_skb; c->tx_skb=NULL; z8530_tx_begin(c); - spin_unlock_irqrestore(&z8530_buffer_lock, flags); c->stats.tx_packets++; c->stats.tx_bytes+=skb->len; dev_kfree_skb_irq(skb); @@ -1489,7 +1564,7 @@ void z8530_null_rx(struct z8530_channel *c, struct sk_buff *skb) { - kfree_skb(skb); + dev_kfree_skb_any(skb); } EXPORT_SYMBOL(z8530_null_rx); @@ -1503,6 +1578,8 @@ * ESCC mode, but on the older chips we have no choice. We flip to the * new buffer immediately in DMA mode so that the DMA of the next * frame can occur while we are copying the previous buffer to an sk_buff + * + * Called with the lock held */ static void z8530_rx_done(struct z8530_channel *c) @@ -1673,6 +1750,9 @@ * hard to hit interrupt latencies for the Z85230 per packet * even in DMA mode we do the flip to DMA buffer if needed here * not in the IRQ. + * + * Called from the network code. The lock is not held at this + * point. */ int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb) @@ -1711,9 +1791,9 @@ c->tx_next_skb=skb; RT_UNLOCK; - spin_lock_irqsave(&z8530_buffer_lock, flags); + spin_lock_irqsave(c->lock, flags); z8530_tx_begin(c); - spin_unlock_irqrestore(&z8530_buffer_lock, flags); + spin_unlock_irqrestore(c->lock, flags); netif_wake_queue(c->netdevice); return 0; @@ -1727,6 +1807,9 @@ * * Get the statistics block. We keep the statistics in software as * the chip doesn't do it for us. + * + * Locking is ignored here - we could lock for a copy but its + * not likely to be that big an issue */ struct net_device_stats *z8530_get_stats(struct z8530_channel *c) diff -u --recursive --new-file v2.4.14/linux/drivers/net/wan/z85230.h linux/drivers/net/wan/z85230.h --- v2.4.14/linux/drivers/net/wan/z85230.h Tue Feb 13 13:15:05 2001 +++ linux/drivers/net/wan/z85230.h Fri Nov 9 14:03:11 2001 @@ -368,6 +368,8 @@ unsigned char tx_active; /* character is being xmitted */ unsigned char tx_stopped; /* output is suspended */ + + spinlock_t *lock; /* Devicr lock */ }; /* @@ -386,6 +388,7 @@ int irq; /* Interrupt for the device */ int active; /* Soft interrupt enable - the Mac doesn't always have a hard disable on its 8530s... */ + spinlock_t lock; }; diff -u --recursive --new-file v2.4.14/linux/drivers/net/wireless/airo.c linux/drivers/net/wireless/airo.c --- v2.4.14/linux/drivers/net/wireless/airo.c Tue Oct 23 22:48:51 2001 +++ linux/drivers/net/wireless/airo.c Fri Nov 9 13:41:42 2001 @@ -3214,17 +3214,19 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pent) { - pdev->driver_data = init_airo_card(pdev->irq, - pdev->resource[2].start, 0); - if (!pdev->driver_data) { + struct net_device *dev; + + dev = init_airo_card(pdev->irq, pdev->resource[2].start, 0); + if (!dev) return -ENODEV; - } + + pci_set_drvdata(pdev, dev); return 0; } static void __devexit airo_pci_remove(struct pci_dev *pdev) { - stop_airo_card(pdev->driver_data, 1); + stop_airo_card(pci_get_drvdata(pdev), 1); } #endif diff -u --recursive --new-file v2.4.14/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog --- v2.4.14/linux/drivers/parport/ChangeLog Mon Nov 5 15:55:31 2001 +++ linux/drivers/parport/ChangeLog Fri Nov 9 14:30:55 2001 @@ -1,3 +1,8 @@ +2001-11-01 Damian Gruszka <damian.gruszka@VisionSystems.de> + + * parport_serial.c (serial_register): Set base_baud before + calling register_serial. + 2001-10-26 Tim Waugh <twaugh@redhat.com> * parport_pc.c (parport_irq_probe): When ECR programmable IRQ diff -u --recursive --new-file v2.4.14/linux/drivers/parport/parport_serial.c linux/drivers/parport/parport_serial.c --- v2.4.14/linux/drivers/parport/parport_serial.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/parport/parport_serial.c Fri Nov 9 14:30:55 2001 @@ -217,6 +217,7 @@ if (get_pci_port (dev, board, &serial_req, k)) break; serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; + serial_req.baud_base = base_baud; line = register_serial (&serial_req); if (line < 0) { printk (KERN_DEBUG diff -u --recursive --new-file v2.4.14/linux/drivers/pci/names.c linux/drivers/pci/names.c --- v2.4.14/linux/drivers/pci/names.c Sun Sep 23 11:40:59 2001 +++ linux/drivers/pci/names.c Fri Nov 9 14:03:11 2001 @@ -52,7 +52,7 @@ #define VENDORS (sizeof(pci_vendor_list)/sizeof(struct pci_vendor_info)) -void __init pci_name_device(struct pci_dev *dev) +void __devinit pci_name_device(struct pci_dev *dev) { const struct pci_vendor_info *vendor_p = pci_vendor_list; int i = VENDORS; diff -u --recursive --new-file v2.4.14/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids --- v2.4.14/linux/drivers/pci/pci.ids Mon Nov 5 15:55:31 2001 +++ linux/drivers/pci/pci.ids Fri Nov 9 14:03:11 2001 @@ -540,6 +540,11 @@ 7411 AMD-765 [Viper] IDE 7413 AMD-765 [Viper] ACPI 7414 AMD-765 [Viper] USB + 7440 AMD-768 [??] ISA + 7441 AMD-768 [??] IDE + 7443 AMD-768 [??] ACPI + 7448 AMD-768 [??] PCI + 7449 AMD-768 [??] USB 1023 Trident Microsystems 0194 82C194 2000 4DWave DX @@ -1094,6 +1099,8 @@ 4d33 20246 4d38 20262 4d68 20268 + 6268 20268R + 4d69 20269 5300 DC5300 105b Foxconn International, Inc. 105c Wipro Infotech Limited @@ -1370,6 +1377,7 @@ 0650 PBC0650A 0670 USB0670 0673 USB0673 + 0680 PCI0680 1096 Alacron 1097 Appian Technology 1098 Quantum Designs (H.K.) Ltd @@ -4186,7 +4194,7 @@ 14e4 0007 NetXtreme BCM5701 1000BaseSX 14e4 0008 NetXtreme BCM5701 1000BaseTX 14e4 8008 NetXtreme BCM5701 1000BaseTX - 1647 NetXtreme BCM5701 Gigabit Ethernet + 1647 NetXtreme BCM5703 Gigabit Ethernet 5820 BCM5820 Crypto Accelerator 14e5 Pixelfusion Ltd 14e6 SHINING Technology Inc diff -u --recursive --new-file v2.4.14/linux/drivers/pcmcia/Config.in linux/drivers/pcmcia/Config.in --- v2.4.14/linux/drivers/pcmcia/Config.in Mon Nov 5 15:55:31 2001 +++ linux/drivers/pcmcia/Config.in Fri Nov 9 14:03:11 2001 @@ -17,7 +17,7 @@ if [ "$CONFIG_PCI" != "n" ]; then bool ' CardBus support' CONFIG_CARDBUS fi - bool ' i82092 compatible bridge support' CONFIG_I82092 + dep_bool ' i82092 compatible bridge support' CONFIG_I82092 $CONFIG_PCI bool ' i82365 compatible bridge support' CONFIG_I82365 bool ' Databook TCIC host bridge support' CONFIG_TCIC if [ "$CONFIG_HD64465" = "y" ]; then diff -u --recursive --new-file v2.4.14/linux/drivers/pcmcia/i82092.c linux/drivers/pcmcia/i82092.c --- v2.4.14/linux/drivers/pcmcia/i82092.c Mon Nov 5 15:55:31 2001 +++ linux/drivers/pcmcia/i82092.c Fri Nov 9 13:45:35 2001 @@ -795,7 +795,7 @@ mem->card_start = ( (unsigned long)(i & 0x3fff)<12) + mem->sys_start; mem->card_start &= 0x3ffffff; - printk("Card %i is from %x to %x \n",sock,mem->sys_start,mem->sys_stop); + printk("Card %i is from %lx to %lx \n",sock,mem->sys_start,mem->sys_stop); leave("i82092aa_get_mem_map"); return 0; @@ -819,7 +819,7 @@ if ( (mem->card_start > 0x3ffffff) || (mem->sys_start > mem->sys_stop) || (mem->speed > 1000) ) { leave("i82092aa_set_mem_map: invalid address / speed"); - printk("invalid mem map for socket %i : %x to %x with a start of %x \n",sock,mem->sys_start, mem->sys_stop, mem->card_start); + printk("invalid mem map for socket %i : %lx to %lx with a start of %x \n",sock,mem->sys_start, mem->sys_stop, mem->card_start); return -EINVAL; } @@ -895,7 +895,6 @@ static void i82092aa_module_exit(void) { - int i; enter("i82092aa_module_exit"); pci_unregister_driver(&i82092aa_pci_drv); unregister_ss_entry(&i82092aa_operations); diff -u --recursive --new-file v2.4.14/linux/drivers/pcmcia/pci_socket.c linux/drivers/pcmcia/pci_socket.c --- v2.4.14/linux/drivers/pcmcia/pci_socket.c Tue Jul 3 17:08:20 2001 +++ linux/drivers/pcmcia/pci_socket.c Fri Nov 9 13:41:42 2001 @@ -177,13 +177,13 @@ memset(socket, 0, sizeof(*socket)); socket->dev = dev; socket->op = ops; - dev->driver_data = socket; + pci_set_drvdata(dev, socket); spin_lock_init(&socket->event_lock); err = socket->op->open(socket); if(err) { socket->dev = NULL; - dev->driver_data = NULL; + pci_set_drvdata(dev, NULL); } return err; } @@ -210,24 +210,24 @@ static void __devexit cardbus_remove (struct pci_dev *dev) { - pci_socket_t *socket = (pci_socket_t *) dev->driver_data; + pci_socket_t *socket = pci_get_drvdata(dev); pcmcia_unregister_socket (socket->pcmcia_socket); if (socket->op && socket->op->close) socket->op->close(socket); - dev->driver_data = 0; + pci_set_drvdata(dev, NULL); } static int cardbus_suspend (struct pci_dev *dev, u32 state) { - pci_socket_t *socket = (pci_socket_t *) dev->driver_data; + pci_socket_t *socket = pci_get_drvdata(dev); pcmcia_suspend_socket (socket->pcmcia_socket); return 0; } static int cardbus_resume (struct pci_dev *dev) { - pci_socket_t *socket = (pci_socket_t *) dev->driver_data; + pci_socket_t *socket = pci_get_drvdata(dev); pcmcia_resume_socket (socket->pcmcia_socket); return 0; } diff -u --recursive --new-file v2.4.14/linux/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c --- v2.4.14/linux/drivers/s390/block/dasd.c Mon Nov 5 15:55:31 2001 +++ linux/drivers/s390/block/dasd.c Fri Nov 9 14:05:02 2001 @@ -117,6 +117,8 @@ /* SECTION: Constant definitions to be used within this file */ #define PRINTK_HEADER DASD_NAME":" +#undef DASD_PROFILE /* fill profile information - used for */ + /* statistics and perfomance */ #define DASD_MIN_SIZE_FOR_QUEUE 32 #undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE @@ -525,6 +527,8 @@ val = simple_strtoul (buffer, &buffer, 16); /* check for features - e.g. (ro) ; the '\0', ')' and '-' stops check */ + *features = DASD_DEFAULT_FEATURES; + if (temp[i]=='(') { while (temp[i]!='\0' && temp[i]!=')'&&temp[i]!='-') { @@ -561,7 +565,7 @@ { char *temp; int from, to; - int features = 0; + int features; int rc = 0; if (*str) { @@ -1008,6 +1012,7 @@ static dasd_profile_info_t dasd_global_profile; +#ifdef DASD_PROFILE /* * macro: dasd_profile_add_counter * increments counter in global and local profiling structures @@ -1032,13 +1037,20 @@ void dasd_profile_add (ccw_req_t * cqr) { - long strtime, irqtime, endtime, tottime; + long strtime, irqtime, endtime, tottime; /* in microsecnds*/ long tottimeps, sectors; dasd_device_t *device = cqr->device; if (!cqr->req) /* safeguard against abnormal cqrs */ return; - sectors = ((struct request *) (cqr->req))->nr_sectors; + + if ((!cqr->buildclk) || + (!cqr->startclk) || + (!cqr->stopclk ) || + (!cqr->endclk ) || + (!(sectors = ((struct request *) (cqr->req))->nr_sectors))) + return; + strtime = ((cqr->startclk - cqr->buildclk) >> 12); irqtime = ((cqr->stopclk - cqr->startclk) >> 12); endtime = ((cqr->endclk - cqr->stopclk) >> 12); @@ -1064,7 +1076,7 @@ dasd_profile_add_counter (irqtime / sectors, dasd_io_time2ps, device); dasd_profile_add_counter (endtime, dasd_io_time3, device); } - +#endif /* SECTION: All the gendisk stuff */ @@ -1506,6 +1518,11 @@ dasd_get_queue (kdev_t kdev) { dasd_device_t *device = dasd_device_from_kdev (kdev); + + if (!device) { + return NULL; + } + return device->request_queue; } @@ -1544,7 +1561,9 @@ asm volatile ("STCK %0":"=m" (cqr->endclk)); if (cqr->req) { +#ifdef DASD_PROFILE dasd_profile_add (cqr); +#endif dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE)); /* free request if nobody is waiting on it */ dasd_free_request (cqr, cqr->device); @@ -2294,18 +2313,6 @@ rc = put_user(ver, (int *) data); break; } - case BLKGETSIZE:{ /* Return device size */ - unsigned long blocks = major_info->gendisk.sizes - [MINOR (inp->i_rdev)] << 1; - rc = put_user(blocks, (unsigned long *) data); - break; - } - case BLKGETSIZE64:{ - u64 blocks = major_info->gendisk.sizes - [MINOR (inp->i_rdev)]; - rc = put_user(blocks << 10, (u64 *) data); - break; - } case BLKRRPART:{ if (!capable (CAP_SYS_ADMIN)) { rc = -EACCES; @@ -2501,6 +2508,8 @@ break; } #endif /* 0 */ + case BLKGETSIZE: + case BLKGETSIZE64: case BLKSSZGET: case BLKROSET: case BLKROGET: @@ -2577,7 +2586,7 @@ } spin_lock_irqsave(&discipline_lock,flags); device = dasd_device_from_kdev (inp->i_rdev); - if (device == NULL ) { + if (!device) { printk (KERN_WARNING PRINTK_HEADER "No device registered as (%d:%d)\n", MAJOR (inp->i_rdev), @@ -2618,7 +2627,7 @@ goto out; } device = dasd_device_from_kdev (inp->i_rdev); - if (device == NULL) { + if (!device) { printk (KERN_WARNING PRINTK_HEADER "No device registered as %d:%d\n", MAJOR (inp->i_rdev), @@ -2638,6 +2647,7 @@ invalidate_buffers (inp->i_rdev); if ( device->discipline->owner ) __MOD_DEC_USE_COUNT(device->discipline->owner); + MOD_DEC_USE_COUNT; } else if ( count == -1 ) { /* paranoia only */ atomic_set (&device->open_count,0); printk (KERN_WARNING PRINTK_HEADER @@ -2661,7 +2671,11 @@ dasd_fillgeo(int kdev,struct hd_geometry *geo) { dasd_device_t *device = dasd_device_from_kdev (kdev); - if (!device->discipline->fill_geometry) + + if (!device) + return -EINVAL; + + if (!device->discipline->fill_geometry) return -EINVAL; device->discipline->fill_geometry (device, geo); @@ -3094,8 +3108,10 @@ #endif } goto out; +#ifdef CONFIG_ARCH_S390X noidal: free_page ((long) device->lowmem_ccws); +#endif noccw: kfree(device); out: @@ -3308,16 +3324,16 @@ int rc = 0; unsigned long flags; - if ( device->init_cqr != NULL ) { + s390irq_spin_lock_irqsave (device->devinfo.irq, flags); + if ( device->init_cqr != NULL && atomic_read(&dasd_init_pending) != 0 ) { if ( device->discipline->term_IO == NULL ) BUG(); - s390irq_spin_lock_irqsave (device->devinfo.irq, flags); device->discipline->term_IO (device->init_cqr); - s390irq_spin_unlock_irqrestore(device->devinfo.irq, flags); atomic_dec (&dasd_init_pending); dasd_free_request (device->init_cqr, device); device->init_cqr = NULL; } + s390irq_spin_unlock_irqrestore(device->devinfo.irq, flags); memset(&device->sizes,0,sizeof(dasd_sizes_t)); device->level = DASD_STATE_ACCEPT; return rc; @@ -3632,19 +3648,30 @@ for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) { dasd_device_t *device; int devno = dasd_devno_from_devindex(index+i); + int features; + if ( devno == -ENODEV ) continue; + + features = dasd_features_from_devno(devno); + if (features < DASD_DEFAULT_FEATURES) + features = DASD_DEFAULT_FEATURES; + device = temp->dasd_device[i]; if (device) { + len += sprintf (info->data + len, - "%04x(%s) at (%3d:%3d) is %7s:", + "%04x(%s) at (%3d:%3d) is %-7s%4s: ", device->devinfo.devno, device->discipline ? device-> discipline->name : "none", temp->gendisk.major, i << DASD_PARTN_BITS, - device->name); + device->name, + (features & DASD_FEATURE_READONLY) ? + "(ro)" : " "); + switch (device->level) { case DASD_STATE_NEW: len += @@ -3709,10 +3736,12 @@ "%04x",devno); } len += sprintf (info->data + len, - "(none) at (%3d:%3d) is %7s: unknown", + "(none) at (%3d:%3d) is %-7s%4s: unknown", temp->gendisk.major, i << DASD_PARTN_BITS, - buffer); + buffer, + (features & DASD_FEATURE_READONLY) ? + "(ro)" : " "); } if ( dasd_probeonly ) len += sprintf(info->data + len,"(probeonly)"); @@ -3753,7 +3782,7 @@ int off = 0; char *temp; dasd_range_t range; - int features = 0; + int features; if (buffer == NULL) return -ENOMEM; @@ -3906,7 +3935,7 @@ } len += sprintf (info->data + len, "\n"); - len += sprintf (info->data + len, "Histogram of I/O times\n"); + len += sprintf (info->data + len, "Histogram of I/O times (microseconds)\n"); for (i = 0; i < 16; i++) { len += sprintf (info->data + len, "%7d ", dasd_global_profile.dasd_io_times[i] >> shift); diff -u --recursive --new-file v2.4.14/linux/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c --- v2.4.14/linux/drivers/s390/block/dasd_3990_erp.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/s390/block/dasd_3990_erp.c Fri Nov 9 14:05:02 2001 @@ -55,7 +55,7 @@ while (loop_cqr != NULL) { DASD_MESSAGE (KERN_ERR, device, - "(%s) ERP chain report for req: %p\n", + "(%s) ERP chain report for req: %p", caller == 0 ? "EXAMINE" : "ACTION", loop_cqr); @@ -66,7 +66,7 @@ DASD_MESSAGE (KERN_ERR, device, "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", + "%02x%02x%02x%02x %02x%02x%02x%02x", nl, nl[0], nl[1], nl[2], nl[3], nl[4], nl[5], nl[6], nl[7], @@ -80,13 +80,13 @@ if (loop_cqr->cplength > 40) { /* log only parts of the CP */ DASD_MESSAGE (KERN_ERR, device, "%s", - "Start of channel program:\n"); + "Start of channel program:"); for (i = 0; i < 20; i += 2) { DASD_MESSAGE (KERN_ERR, device, "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", + "%02x%02x%02x%02x %02x%02x%02x%02x", nl, nl[0], nl[1], nl[2], nl[3], nl[4], nl[5], nl[6], nl[7], @@ -97,7 +97,7 @@ } DASD_MESSAGE (KERN_ERR, device, "%s", - "End of channel program:\n"); + "End of channel program:"); nl = (char *) loop_cqr->cpaddr; nl += ((loop_cqr->cplength - 10) * 8); @@ -106,7 +106,7 @@ DASD_MESSAGE (KERN_ERR, device, "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", + "%02x%02x%02x%02x %02x%02x%02x%02x", nl, nl[0], nl[1], nl[2], nl[3], nl[4], nl[5], nl[6], nl[7], @@ -119,13 +119,13 @@ } else { /* log the whole CP */ DASD_MESSAGE (KERN_ERR, device, "%s", - "Channel program (complete):\n"); + "Channel program (complete):"); for (i = 0; i < (loop_cqr->cplength + 4); i += 2) { DASD_MESSAGE (KERN_ERR, device, "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", + "%02x%02x%02x%02x %02x%02x%02x%02x", nl, nl[0], nl[1], nl[2], nl[3], nl[4], nl[5], nl[6], nl[7], @@ -151,14 +151,14 @@ nl -= 10*8; /* start some bytes before */ DASD_MESSAGE (KERN_ERR, device, - "Failed CCW (%p) (area):\n", + "Failed CCW (%p) (area):", (void *)(long)cpa); for (i = 0; i < 20; i += 2) { DASD_MESSAGE (KERN_ERR, device, "%p: %02x%02x%02x%02x %02x%02x%02x%02x " - "%02x%02x%02x%02x %02x%02x%02x%02x\n", + "%02x%02x%02x%02x %02x%02x%02x%02x", nl, nl[0], nl[1], nl[2], nl[3], nl[4], nl[5], nl[6], nl[7], @@ -171,7 +171,7 @@ } else { DASD_MESSAGE (KERN_ERR, device, - "Failed CCW (%p) already logged\n", + "Failed CCW (%p) already logged", (void *)(long)cpa); } } diff -u --recursive --new-file v2.4.14/linux/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c --- v2.4.14/linux/drivers/s390/block/dasd_eckd.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/s390/block/dasd_eckd.c Fri Nov 9 14:05:02 2001 @@ -631,7 +631,7 @@ } } if (device->sizes.bp_block == 0) { - DASD_MESSAGE (KERN_WARNING, device, "%s\n", + DASD_MESSAGE (KERN_WARNING, device, "%s", "Volume has incompatible disk layout"); return -EMEDIUMTYPE; } @@ -746,7 +746,7 @@ (fdata->start_unit / private->rdc_data.no_cyl) % (private->rdc_data.no_cyl / 20))) { DASD_MESSAGE (KERN_INFO, device, - "Format Cylinder: %d Flags: %d\n", + "Format Cylinder: %d Flags: %d", fdata->start_unit / private->rdc_data.trk_per_cyl, fdata->intensity); } if ((fdata->intensity & ~0x8) & 0x04) { diff -u --recursive --new-file v2.4.14/linux/drivers/s390/char/tape34xx.c linux/drivers/s390/char/tape34xx.c --- v2.4.14/linux/drivers/s390/char/tape34xx.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/s390/char/tape34xx.c Fri Nov 9 14:05:02 2001 @@ -1631,7 +1631,7 @@ tapestate_set (ti, TS_DONE); ti->rc = 0; ti->wanna_wakeup=1; - wake_up_interruptible (&ti->wq); + wake_up (&ti->wq); } void @@ -2050,8 +2050,13 @@ return; case 0x38: // Physical end of tape. A read/write operation reached the physical end of tape. - if (tapestate_get(ti)==TS_WRI_INIT) { + if (tapestate_get(ti)==TS_WRI_INIT || + tapestate_get(ti)==TS_DSE_INIT || + tapestate_get(ti)==TS_EGA_INIT || + tapestate_get(ti)==TS_WTM_INIT){ tape34xx_error_recovery_has_failed(ti,ENOSPC); + } else { + tape34xx_error_recovery_has_failed(ti,EIO); } return; case 0x39: diff -u --recursive --new-file v2.4.14/linux/drivers/s390/char/tapechar.c linux/drivers/s390/char/tapechar.c --- v2.4.14/linux/drivers/s390/char/tapechar.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/s390/char/tapechar.c Fri Nov 9 14:05:02 2001 @@ -704,7 +704,7 @@ long lockflags; tape_info_t *ti,*lastti; ccw_req_t *cqr = NULL; - int rc; + int rc = 0; ti = first_tape_info; while ((ti != NULL) && (ti->rew_minor != MINOR (inode->i_rdev)) && (ti->nor_minor != MINOR (inode->i_rdev))) @@ -718,13 +718,14 @@ lastti->next=ti->next; } kfree(ti); - return 0; + goto out; } if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) { #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:notidle!"); #endif - return -ENXIO; /* error in tape_release */ + rc = -ENXIO; /* error in tape_release */ + goto out; } #ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"c:release:"); @@ -750,8 +751,9 @@ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); tapestate_set (ti, TS_UNUSED); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); +out: #ifdef MODULE MOD_DEC_USE_COUNT; #endif /* MODULE */ - return 0; + return rc; } diff -u --recursive --new-file v2.4.14/linux/drivers/s390/misc/chandev.c linux/drivers/s390/misc/chandev.c --- v2.4.14/linux/drivers/s390/misc/chandev.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/s390/misc/chandev.c Fri Nov 9 14:05:02 2001 @@ -2428,8 +2428,7 @@ else if(ints[0]==2) ints[3]=ints[2]; chandev_add_parms(ints[1],ints[2],ints[3],currstr); -// currstr=currstr+strlen(currstr)+1; - continue; + goto NextOption; } else goto BadArgs; @@ -2696,6 +2695,7 @@ } else goto BadArgs; + NextOption: if(cnt<strcnt) { /* eat up stuff till next string */ diff -u --recursive --new-file v2.4.14/linux/drivers/s390/s390mach.c linux/drivers/s390/s390mach.c --- v2.4.14/linux/drivers/s390/s390mach.c Sun Aug 12 13:28:00 2001 +++ linux/drivers/s390/s390mach.c Fri Nov 9 14:05:02 2001 @@ -170,7 +170,7 @@ static int s390_machine_check_handler( void *parm) { struct semaphore *sem = parm; - int flags; + unsigned long flags; mache_t *pmache; int found = 0; diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/3w-xxxx.c linux/drivers/scsi/3w-xxxx.c --- v2.4.14/linux/drivers/scsi/3w-xxxx.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/scsi/3w-xxxx.c Fri Nov 9 14:05:02 2001 @@ -4,6 +4,7 @@ Written By: Adam Radford <linux@3ware.com> Modifications By: Joel Jacobson <linux@3ware.com> Arnaldo Carvalho de Melo <acme@conectiva.com.br> + Brad Strand <linux@3ware.com> Copyright (C) 1999-2001 3ware Inc. @@ -100,6 +101,11 @@ Fix possible null pointer dereference in tw_aen_drain_queue() during initialization. Clear pci parity errors during initialization and during io. + 1.02.00.009 - Remove redundant increment in tw_state_request_start(). + Add ioctl support for direct ATA command passthru. + Add entire aen code string list. + 1.02.00.010 - Cleanup queueing code, fix jbod thoughput. + Fix get_param for specific units. */ #include <linux/module.h> @@ -147,7 +153,7 @@ }; /* Globals */ -char *tw_driver_version="1.02.00.008"; +char *tw_driver_version="1.02.00.010"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -169,23 +175,18 @@ dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen); /* Print some useful info when certain aen codes come out */ - switch (aen & 0x0ff) { - case TW_AEN_APORT_TIMEOUT: - printk(KERN_WARNING "3w-xxxx: scsi%d: Received drive timeout AEN on port %d, check drive and drive cables.\n", tw_dev->host->host_no, aen >> 8); - break; - case TW_AEN_DRIVE_ERROR: - printk(KERN_WARNING "3w-xxxx: scsi%d: Received drive error AEN on port %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, aen >> 8); - break; - case TW_AEN_SMART_FAIL: - printk(KERN_WARNING "3w-xxxx: scsi%d: Received S.M.A.R.T. threshold AEN on port %d, check drive/cooling, or possible bad drive.\n", tw_dev->host->host_no, aen >> 8); - break; - case TW_AEN_SBUF_FAIL: - printk(KERN_WARNING "3w-xxxx: scsi%d: Received SBUF integrity check failure AEN, reseat card or bad card.\n", tw_dev->host->host_no); - break; - default: - printk(KERN_WARNING "3w-xxxx: Received AEN 0x%x\n", aen); + if (aen == 0x0ff) { + printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: AEN queue overflow.\n", tw_dev->host->host_no); + } else { + if ((aen & 0x0ff) < TW_AEN_STRING_MAX) { + if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { + printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8); + } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]); + } + } else + printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen); } - tw_dev->aen_count++; /* Now queue the code */ @@ -235,7 +236,7 @@ response_que_addr = tw_dev->registers.response_que_addr; if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) { - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count); + dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count); return 1; } @@ -291,7 +292,7 @@ mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -308,7 +309,8 @@ if (command_packet->status != 0) { if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) { /* Bad response */ - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } else { /* We know this is a 3w-1x00, and doesn't support aen's */ @@ -428,7 +430,7 @@ status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -525,11 +527,11 @@ int tw_check_bits(u32 status_reg_value) { if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) { - printk(KERN_WARNING "3w-xxxx: tw_check_bits(): No expected bits (0x%x).\n", status_reg_value); + dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): No expected bits (0x%x).\n", status_reg_value); return 1; } if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) { - printk(KERN_WARNING "3w-xxxx: tw_check_bits(): Found unexpected bits (0x%x).\n", status_reg_value); + dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): Found unexpected bits (0x%x).\n", status_reg_value); return 1; } @@ -633,8 +635,12 @@ case 0x51: printk(KERN_WARNING "3w-xxxx: scsi%d: Unrecoverable drive error on unit %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, unit); break; + default: + printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit); } break; + default: + printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit); } } /* End tw_decode_error() */ @@ -660,7 +666,7 @@ status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 1.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 1.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -669,7 +675,7 @@ response_que_value = inl(response_que_addr); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 2.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 2.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -817,9 +823,20 @@ continue; } - /* Calculate max cmds per lun */ - if (tw_dev->num_units > 0) - tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units; + /* Calculate max cmds per lun, and setup queues */ + if (tw_dev->num_units > 0) { + if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) { + tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-1)/tw_dev->num_units; + tw_dev->free_head = TW_Q_START; + tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1; + tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1; + } else { + tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units; + tw_dev->free_head = TW_Q_START; + tw_dev->free_tail = TW_Q_LENGTH - 1; + tw_dev->free_wrap = TW_Q_LENGTH - 1; + } + } /* Register the card with the kernel SCSI layer */ host = scsi_register(tw_host, sizeof(TW_Device_Extension)); @@ -889,7 +906,7 @@ } if (numcards == 0) - printk(KERN_WARNING "3w-xxxx: tw_findcards(): No cards found.\n"); + printk(KERN_WARNING "3w-xxxx: No cards with valid units found.\n"); else register_reboot_notifier(&tw_notifier); @@ -899,18 +916,19 @@ /* This function will free up device extension resources */ void tw_free_device_extension(TW_Device_Extension *tw_dev) { - int i, imax; - imax = TW_Q_LENGTH; + int i; dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n"); /* Free command packet and generic buffer memory */ - for (i=0;i<imax;i++) { + for (i=0;i<TW_Q_LENGTH;i++) { if (tw_dev->command_packet_virtual_address[i]) kfree(tw_dev->command_packet_virtual_address[i]); if (tw_dev->alignment_virtual_address[i]) kfree(tw_dev->alignment_virtual_address[i]); + } + for (i=0;i<TW_MAX_BOUNCEBUF;i++) { if (tw_dev->bounce_buffer[i]) kfree(tw_dev->bounce_buffer[i]); } @@ -922,7 +940,7 @@ int i; for (i=0;i<tw_device_extension_count;i++) { - printk(KERN_NOTICE "3w-xxxx: Notifying card #%d\n", i); + printk(KERN_NOTICE "3w-xxxx: Shutting down card %d.\n", i); tw_shutdown_device(tw_device_extension_list[i]); } unregister_reboot_notifier(&tw_notifier); @@ -981,7 +999,7 @@ mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -995,7 +1013,8 @@ } if (command_packet->status != 0) { /* bad response */ - printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } break; /* Response was okay, so we exit */ @@ -1043,8 +1062,6 @@ tw_dev->num_units = 0; tw_dev->num_aborts = 0; tw_dev->num_resets = 0; - tw_dev->free_head = TW_Q_START; - tw_dev->free_tail = TW_Q_LENGTH - 1; tw_dev->posted_request_count = 0; tw_dev->max_posted_request_count = 0; tw_dev->max_sgl_entries = 0; @@ -1135,7 +1152,7 @@ mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -1149,7 +1166,8 @@ } if (command_packet->status != 0) { /* bad response */ - printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } found = 1; @@ -1181,7 +1199,7 @@ tw_dev->num_units = num_units; if (num_units == 0) { - printk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n"); + dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n"); return 1; } @@ -1238,7 +1256,7 @@ mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -1252,7 +1270,8 @@ } if (command_packet->status != 0) { /* bad response */ - printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } found = 1; @@ -1277,10 +1296,10 @@ /* Now allocate raid5 bounce buffers */ if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) { - for (i=0;i<TW_Q_LENGTH;i++) { + for (i=0;i<TW_MAX_BOUNCEBUF;i++) { tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*TW_MAX_SECTORS, 2); if (tw_dev->bounce_buffer[i] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bounce buffer allocation failed.\n"); + printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n"); return 1; } memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_SECTORS); @@ -1342,7 +1361,7 @@ tw_state_request_start(tw_dev, &request_id); error = tw_aen_read_queue(tw_dev, request_id); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error reading aen queue.\n"); + printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); } @@ -1354,7 +1373,7 @@ while (tw_dev->pending_request_count > 0) { request_id = tw_dev->pending_queue[tw_dev->pending_head]; if (tw_dev->state[request_id] != TW_S_PENDING) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found request id that wasn't pending.\n"); + printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no); break; } if (tw_post_command_packet(tw_dev, request_id)==0) { @@ -1382,12 +1401,12 @@ command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; error = 0; if (command_packet->status != 0) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit); tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); error = 1; } if (tw_dev->state[request_id] != TW_S_POSTED) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", request_id, command_packet->byte0.opcode); + printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode); error = 1; } if (TW_STATUS_ERRORS(status_reg_value)) { @@ -1400,24 +1419,22 @@ dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n"); error = tw_aen_complete(tw_dev, request_id); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error completing aen.\n"); + printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no); } status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); } } else { switch (tw_dev->srb[request_id]->cmnd[0]) { case READ_10: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10\n"); case READ_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_6\n"); + dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n"); break; case WRITE_10: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10\n"); case WRITE_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_6\n"); + dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n"); break; case INQUIRY: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n"); @@ -1432,7 +1449,7 @@ error = tw_ioctl_complete(tw_dev, request_id); break; default: - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unknown scsi opcode: 0x%x.\n", tw_dev->srb[request_id]->cmnd[0]); + printk(KERN_WARNING "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x.\n", tw_dev->host->host_no, tw_dev->srb[request_id]->cmnd[0]); tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); } @@ -1450,7 +1467,7 @@ tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); } } @@ -1471,6 +1488,7 @@ TW_Command *command_packet; u32 param_value; TW_Ioctl *ioctl = NULL; + TW_Passthru *passthru = NULL; int tw_aen_code; ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; @@ -1519,6 +1537,7 @@ case TW_OP_GET_PARAM: dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_GET_PARAM.\n"); command_packet->byte0.opcode = TW_OP_GET_PARAM; + command_packet->byte3.unit = ioctl->unit_index; param->table_id = ioctl->table_id; param->parameter_id = ioctl->parameter_id; param->parameter_size_bytes = ioctl->parameter_size_bytes; @@ -1562,7 +1581,26 @@ tw_dev->srb[request_id]->result = (DID_OK << 16); tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); return 0; - case TW_CMD_PACKET: + case TW_ATA_PASSTHRU: + if (ioctl->data != NULL) { + memcpy(command_packet, ioctl->data, sizeof(TW_Command)); + command_packet->request_id = request_id; + } else { + printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n"); + return 1; + } + + passthru = (TW_Passthru *)tw_dev->command_packet_virtual_address[request_id]; + passthru->sg_list[0].length = passthru->sector_count*512; + if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) { + printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%ld) too big.\n", passthru->sg_list[0].length); + return 1; + } + passthru->sg_list[0].address = virt_to_bus(tw_dev->alignment_virtual_address[request_id]); + tw_post_command_packet(tw_dev, request_id); + return 0; + case TW_CMD_PACKET: + dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET.\n"); if (ioctl->data != NULL) { memcpy(command_packet, ioctl->data, sizeof(TW_Command)); command_packet->request_id = request_id; @@ -1596,7 +1634,6 @@ command_packet->byte0.sgl_offset = 2; command_packet->size = 4; command_packet->request_id = request_id; - command_packet->byte3.unit = 0; command_packet->byte3.host_id = 0; command_packet->status = 0; command_packet->flags = 0; @@ -1614,7 +1651,10 @@ unsigned char *param_data; unsigned char *buff; TW_Param *param; + TW_Ioctl *ioctl = NULL; + TW_Passthru *passthru = NULL; + ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer; dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n"); buff = tw_dev->srb[request_id]->request_buffer; if (buff == NULL) { @@ -1622,16 +1662,23 @@ return 1; } dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen); - memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - if (param == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n"); - return 1; - } - param_data = &(param->data[0]); - - memcpy(buff, param_data, tw_dev->ioctl_size[request_id]); + ioctl = (TW_Ioctl *)buff; + switch (ioctl->opcode) { + case TW_ATA_PASSTHRU: + passthru = (TW_Passthru *)ioctl->data; + memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512); + break; + default: + memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); + param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; + if (param == NULL) { + printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Bad alignment virtual address.\n"); + return 1; + } + param_data = &(param->data[0]); + memcpy(buff, param_data, tw_dev->ioctl_size[request_id]); + } return 0; } /* End tw_ioctl_complete() */ @@ -1659,7 +1706,7 @@ status_reg_value = inl(status_reg_addr); do_gettimeofday(&timeout); if (before.tv_sec + seconds < timeout.tv_sec) { - printk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag); + dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag); return 1; } mdelay(1); @@ -1680,7 +1727,7 @@ status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); } @@ -1724,7 +1771,7 @@ imax = TW_Q_LENGTH; if (tw_reset_sequence(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_reset_device_extension(): Reset sequence failed for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no); return 1; } @@ -1772,14 +1819,14 @@ error = tw_aen_drain_queue(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): No attention interrupt for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Card not responding, retrying.\n", tw_dev->host->host_no); tries++; continue; } /* Check for controller errors */ if (tw_check_errors(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Controller errors found, soft resetting card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors found, retrying.\n", tw_dev->host->host_no); tries++; continue; } @@ -1787,7 +1834,7 @@ /* Empty the response queue again */ error = tw_empty_response_que(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Couldn't empty response queue for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Couldn't empty response queue, retrying.\n", tw_dev->host->host_no); tries++; continue; } @@ -1797,13 +1844,13 @@ } if (tries >= TW_MAX_RESET_TRIES) { - printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Controller error or no attention interrupt: giving up for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors, card not responding, check all cabling.\n", tw_dev->host->host_no); return 1; } error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Couldn't initconnection for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Connection initialization failed.\n", tw_dev->host->host_no); return 1; } @@ -1893,14 +1940,14 @@ for (i=0;i<TW_Q_LENGTH;i++) { if (tw_dev->srb[i] == SCpnt) { if (tw_dev->state[i] == TW_S_STARTED) { - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort succeeded for started Scsi_Cmnd 0x%x\n", (u32)tw_dev->srb[i]); + printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, (u32)SCpnt); tw_dev->state[i] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, i); spin_unlock(&tw_dev->tw_lock); return (SUCCESS); } if (tw_dev->state[i] == TW_S_PENDING) { - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort succeeded for pending Scsi_Cmnd 0x%x\n", (u32)tw_dev->srb[i]); + printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, (u32)SCpnt); if (tw_dev->pending_head == TW_Q_LENGTH-1) { tw_dev->pending_head = TW_Q_START; } else { @@ -1916,10 +1963,9 @@ } /* If the command has already been posted, we have to reset the card */ - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort failed for unknown Scsi_Cmnd 0x%x, resetting card %d.\n", (u32)SCpnt, tw_dev->host->host_no); - + printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt); if (tw_reset_device_extension(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no); + dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no); spin_unlock(&tw_dev->tw_lock); return (FAILED); } @@ -1956,11 +2002,11 @@ /* Now reset the card and some of the device extension data */ if (tw_reset_device_extension(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Reset failed for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no); spin_unlock(&tw_dev->tw_lock); return (FAILED); } - printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Reset succeeded for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Reset succeeded.\n", tw_dev->host->host_no); spin_unlock(&tw_dev->tw_lock); return (SUCCESS); @@ -2073,13 +2119,10 @@ switch (*command) { case READ_10: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_10.\n"); case READ_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_6.\n"); case WRITE_10: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught WRITE_10.\n"); case WRITE_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught WRITE_6.\n"); + dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ/WRITE.\n"); error = tw_scsiop_read_write(tw_dev, request_id); break; case TEST_UNIT_READY: @@ -2103,7 +2146,7 @@ error = tw_ioctl(tw_dev, request_id); break; default: - printk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): Unknown scsi opcode: 0x%x\n", *command); + printk(KERN_NOTICE "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x\n", tw_dev->host->host_no, *command); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); SCpnt->result = (DID_BAD_TARGET << 16); @@ -2569,7 +2612,7 @@ mdelay(5); status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { - printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n"); tw_decode_bits(tw_dev, status_reg_value); return 1; } @@ -2583,7 +2626,8 @@ } if (command_packet->status != 0) { /* bad response */ - printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); return 1; } break; /* Response was okay, so we exit */ @@ -2603,7 +2647,7 @@ error = request_irq(tw_dev->tw_pci_dev->irq, tw_interrupt, SA_SHIRQ, device, tw_dev); if (error < 0) { - printk(KERN_WARNING "3w-xxxx: tw_setup_irq(): Error requesting IRQ: %d for card %d.\n", tw_dev->tw_pci_dev->irq, tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Error requesting IRQ: %d.\n", tw_dev->host->host_no, tw_dev->tw_pci_dev->irq); return 1; } return 0; @@ -2621,9 +2665,9 @@ /* poke the board */ error = tw_initconnection(tw_dev, 1); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_shutdown_device(): Couldn't initconnection for card %d.\n", tw_dev->host->host_no); + printk(KERN_WARNING "3w-xxxx: scsi%d: Connection shutdown failed.\n", tw_dev->host->host_no); } else { - printk(KERN_NOTICE "3w-xxxx shutdown succeeded\n"); + printk(KERN_NOTICE "3w-xxxx: Shutdown complete.\n"); } /* Re-enable interrupts */ @@ -2654,7 +2698,7 @@ dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish()\n"); do { - if (tw_dev->free_tail == TW_Q_LENGTH-1) { + if (tw_dev->free_tail == tw_dev->free_wrap) { tw_dev->free_tail = TW_Q_START; } else { tw_dev->free_tail = tw_dev->free_tail + 1; @@ -2678,23 +2722,14 @@ /* Obtain next free request_id */ do { - if (tw_dev->free_head == TW_Q_LENGTH - 1) { + if (tw_dev->free_head == tw_dev->free_wrap) { tw_dev->free_head = TW_Q_START; } else { tw_dev->free_head = tw_dev->free_head + 1; } - } while ((tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == TW_S_STARTED) || - (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == TW_S_POSTED) || - (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == TW_S_PENDING) || - (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == TW_S_COMPLETED)); + } while (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] & TW_START_MASK); id = tw_dev->free_queue[tw_dev->free_head]; - - if (tw_dev->free_head == TW_Q_LENGTH - 1) { - tw_dev->free_head = TW_Q_START; - } else { - tw_dev->free_head = tw_dev->free_head + 1; - } dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id); *request_id = id; diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/3w-xxxx.h linux/drivers/scsi/3w-xxxx.h --- v2.4.14/linux/drivers/scsi/3w-xxxx.h Sun Sep 23 11:40:59 2001 +++ linux/drivers/scsi/3w-xxxx.h Fri Nov 9 14:05:02 2001 @@ -4,6 +4,7 @@ Written By: Adam Radford <linux@3ware.com> Modifications By: Joel Jacobson <linux@3ware.com> Arnaldo Carvalho de Melo <acme@conectiva.com.br> + Brad Strand <linux@3ware.com> Copyright (C) 1999-2001 3ware Inc. @@ -57,6 +58,43 @@ #include <linux/types.h> #include <linux/kdev_t.h> +/* AEN strings */ +static char *tw_aen_string[] = { + "AEN queue empty", // 0x000 + "Soft reset occurred", // 0x001 + "Mirorr degraded: Unit #", // 0x002 + "Controller error", // 0x003 + "Rebuild failed: Unit #", // 0x004 + "Rebuild complete: Unit #", // 0x005 + "Incomplete unit detected: Unit #", // 0x006 + "Initialization complete: Unit #", // 0x007 + "Unclean shutdown detected: Unit #", // 0x008 + "ATA port timeout: Port #", // 0x009 + "Drive error: Port #", // 0x00A + "Rebuild started: Unit #", // 0x00B + "Initialization started: Unit #", // 0x00C + "Logical unit deleted: Unit #", // 0x00D + NULL, // 0x00E unused + "SMART threshold exceeded: Port #", // 0x00F + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, // 0x010-0x020 unused + "ATA UDMA downgrade: Port #", // 0x021 + "ATA UDMA upgrade: Port #", // 0x022 + "Sector repair occurred: Port #", // 0x023 + "SBUF integrity check failure", // 0x024 + "Lost cached write: Port #", // 0x025 + "Drive ECC error detected: Port #", // 0x026 + "DCB checksum error: Port #", // 0x027 + "DCB unsupported version: Port #", // 0x028 + "Verify started: Unit #", // 0x029 + "Verify failed: Port #", // 0x02A + "Verify complete: Unit #" // 0x02B +}; + +#define TW_AEN_STRING_MAX 0x02C + /* Control register bit definitions */ #define TW_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000 #define TW_CONTROL_CLEAR_ATTENTION_INTERRUPT 0x00040000 @@ -114,6 +152,7 @@ #define TW_OP_SECTOR_INFO 0x1a #define TW_OP_AEN_LISTEN 0x1c #define TW_CMD_PACKET 0x1d +#define TW_ATA_PASSTHRU 0x1e /* Asynchronous Event Notification (AEN) Codes */ #define TW_AEN_QUEUE_EMPTY 0x0000 @@ -137,7 +176,10 @@ #define TW_INIT_COMMAND_PACKET_SIZE 0x3 #define TW_POLL_MAX_RETRIES 20000 #define TW_MAX_SGL_LENGTH 62 -#define TW_Q_LENGTH 16 +#define TW_ATA_PASS_SGL_MAX 60 +#define TW_MAX_PASSTHRU_BYTES 4096 +#define TW_Q_LENGTH 256 +#define TW_MAX_BOUNCEBUF 16 #define TW_Q_START 0 #define TW_MAX_SLOT 32 #define TW_MAX_PCI_BUSES 255 @@ -225,6 +267,7 @@ unsigned short table_id; unsigned char parameter_id; unsigned char parameter_size_bytes; + unsigned char unit_index; unsigned char data[1]; } TW_Ioctl; @@ -261,14 +304,42 @@ int position; } TW_Info; -typedef enum TAG_TW_Cmd_State { - TW_S_INITIAL, /* Initial state */ - TW_S_STARTED, /* Id in use */ - TW_S_POSTED, /* Posted to the controller */ - TW_S_PENDING, /* Waiting to be posted in isr */ - TW_S_COMPLETED, /* Completed by isr */ - TW_S_FINISHED, /* I/O completely done */ -} TW_Cmd_State; +typedef int TW_Cmd_State; + +#define TW_S_INITIAL 0x1 /* Initial state */ +#define TW_S_STARTED 0x2 /* Id in use */ +#define TW_S_POSTED 0x4 /* Posted to the controller */ +#define TW_S_PENDING 0x8 /* Waiting to be posted in isr */ +#define TW_S_COMPLETED 0x10 /* Completed by isr */ +#define TW_S_FINISHED 0x20 /* I/O completely done */ +#define TW_START_MASK (TW_S_STARTED | TW_S_POSTED | TW_S_PENDING | TW_S_COMPLETED) + +/* Command header for ATA pass-thru */ +typedef struct TAG_TW_Passthru +{ + struct { + unsigned char opcode:5; + unsigned char sgloff:3; + } byte0; + unsigned char size; + unsigned char request_id; + struct { + unsigned char aport:4; + unsigned char host_id:4; + } byte3; + unsigned char status; + unsigned char flags; + unsigned short param; + unsigned short features; + unsigned short sector_count; + unsigned short sector_num; + unsigned short cylinder_lo; + unsigned short cylinder_hi; + unsigned char drive_head; + unsigned char command; + TW_SG_Entry sg_list[TW_ATA_PASS_SGL_MAX]; + unsigned char padding[12]; +} TW_Passthru; typedef struct TAG_TW_Device_Extension { TW_Registers registers; @@ -286,6 +357,7 @@ unsigned char free_queue[TW_Q_LENGTH]; unsigned char free_head; unsigned char free_tail; + unsigned char free_wrap; unsigned char pending_queue[TW_Q_LENGTH]; unsigned char pending_head; unsigned char pending_tail; @@ -304,7 +376,7 @@ u32 aen_count; struct Scsi_Host *host; spinlock_t tw_lock; - unsigned char ioctl_size[TW_Q_LENGTH]; + int ioctl_size[TW_Q_LENGTH]; unsigned short aen_queue[TW_Q_LENGTH]; unsigned char aen_head; unsigned char aen_tail; diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/README.st linux/drivers/scsi/README.st --- v2.4.14/linux/drivers/scsi/README.st Mon Aug 7 22:52:10 2000 +++ linux/drivers/scsi/README.st Fri Nov 9 13:52:21 2001 @@ -2,7 +2,7 @@ The driver is currently maintained by Kai M{kisara (email Kai.Makisara@metla.fi) -Last modified: Sat Aug 5 10:29:07 2000 by makisara@kai.makisara.local +Last modified: Thu Nov 1 22:41:59 2001 by makisara@kai.makisara.local BASICS @@ -312,6 +312,8 @@ this flag unless there are tapes using the device dependent (from the old times) (global) MT_ST_SYSV sets the SYSV sematics (mode) + MT_ST_NOWAIT enables immediate mode (i.e., don't wait for + the command to finish) for some commands (e.g., rewind) MT_ST_DEBUGGING debugging (global; debugging must be compiled into the driver) MT_ST_SETBOOLEANS @@ -341,6 +343,25 @@ known to take a long time. The default is 14000 seconds (3.9 hours). For erase this value is further multiplied by eight. + MT_ST_SET_CLN + Set the cleaning request interpretation parameters using + the lowest 24 bits of the argument. The driver can set the + generic status bit GMT_CLN if a cleaning request bit pattern + is found from the extended sense data. Many drives set one or + more bits in the extended sense data when the drive needs + cleaning. The bits are device-dependent. The driver is + given the number of the sense data byte (the lowest eight + bits of the argument; must be >= 18 (values 1 - 17 + reserved) and <= the maximum requested sense data sixe), + a mask to select the relevant bits (the bits 9-16), and the + bit pattern (bits 17-23). If the bit pattern is zero, one + or more bits under the mask indicate cleaning request. If + the pattern is non-zero, the pattern must match the masked + sense data byte. + + (The cleaning bit is set if the additional sense code and + qualifier 00h 17h are seen regardless of the setting of + MT_ST_SET_CLN.) The following ioctl uses the structure mtpos: MTIOCPOS Reads the current position from the drive. Uses diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.4.14/linux/drivers/scsi/advansys.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/scsi/advansys.c Fri Nov 9 14:05:06 2001 @@ -18680,4 +18680,4 @@ } } } -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.4.14/linux/drivers/scsi/aha152x.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/scsi/aha152x.c Fri Nov 9 14:05:06 2001 @@ -2956,7 +2956,11 @@ DO_LOCK(flags); if(HOSTDATA(shpnt)->in_intr!=0) + { + DO_UNLOCK(flags); + /* _error never returns.. */ aha152x_error(shpnt, "bottom-half already running!?"); + } HOSTDATA(shpnt)->in_intr++; DO_UNLOCK(flags); diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c --- v2.4.14/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Mon Nov 5 15:55:31 2001 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Fri Nov 9 13:41:42 2001 @@ -89,7 +89,7 @@ * the free directly, but check our * list for extra sanity. */ - ahc = (struct ahc_softc *)pdev->driver_data; + ahc = pci_get_drvdata(pdev); TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { if (list_ahc == ahc) { ahc_free(ahc); @@ -176,7 +176,7 @@ return (-error); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - pdev->driver_data = ahc; + pci_set_drvdata(pdev, ahc); if (aic7xxx_detect_complete) ahc_linux_register_host(ahc, aic7xxx_driver_template); #endif diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/dpt_i2o.c linux/drivers/scsi/dpt_i2o.c --- v2.4.14/linux/drivers/scsi/dpt_i2o.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/scsi/dpt_i2o.c Fri Nov 9 14:05:06 2001 @@ -165,6 +165,13 @@ *============================================================================ */ +static struct pci_device_id dptids[] = { + { PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + { PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci,dptids); + static int adpt_detect(Scsi_Host_Template* sht) { struct pci_dev *pDev = NULL; diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.4.14/linux/drivers/scsi/eata.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/scsi/eata.c Fri Nov 9 14:05:06 2001 @@ -2077,4 +2077,4 @@ #ifndef MODULE __setup("eata=", option_setup); #endif /* end MODULE */ -MODULE_LICENSE("BSD"); +MODULE_LICENSE("Dual BSD/GPL"); diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c --- v2.4.14/linux/drivers/scsi/gdth.c Mon Nov 5 15:55:32 2001 +++ linux/drivers/scsi/gdth.c Fri Nov 9 14:05:06 2001 @@ -799,6 +799,17 @@ return cnt; } +#if LINUX_VERSION_CODE >= 0x20363 +/* Vortex only makes RAID controllers. + * We do not really want to specify all 550 ids here, so wildcard match. + */ +static struct pci_device_id gdthtable[] = { + {PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID }, + {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID }, + {0} +}; +MODULE_DEVICE_TABLE(pci,gdthtable); +#endif GDTH_INITFUNC(static void, gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, ushort vendor, ushort device)) diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/i60uscsi.c linux/drivers/scsi/i60uscsi.c --- v2.4.14/linux/drivers/scsi/i60uscsi.c Fri Mar 2 18:38:38 2001 +++ linux/drivers/scsi/i60uscsi.c Fri Nov 9 14:05:06 2001 @@ -68,10 +68,6 @@ * 08/08/99 bv - v1.02c Use waitForPause again. **************************************************************************/ -#ifndef CVT_LINUX_VERSION -#define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S) -#endif - #include <linux/version.h> #include <linux/sched.h> #include <asm/io.h> @@ -161,12 +157,8 @@ static void waitForPause(unsigned amount) { ULONG the_time = jiffies + MS_TO_JIFFIES(amount); - -#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) - while (time_before_eq(jiffies, the_time)); -#else - while (jiffies < the_time); -#endif + while (time_before_eq(jiffies, the_time)) + cpu_relax(); } /***************************************************************************/ @@ -564,33 +556,16 @@ { /* I need Host Control Block Information */ ULONG flags; -#if 0 - printk("inia100: enter inia100_reset\n"); -#endif - -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - save_flags(flags); - cli(); -#else spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); -#endif initAFlag(pHCB); /* reset scsi bus */ ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST); if (waitSCSIRSTdone(pHCB) == FALSE) { -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); -#endif return (SCSI_RESET_ERROR); } else { -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); -#endif return (SCSI_RESET_SUCCESS); } } @@ -611,16 +586,7 @@ UCHAR i; ULONG flags; -#if 0 - printk("inia100: enter inia100_reset\n"); -#endif - -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - save_flags(flags); - cli(); -#else spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); -#endif pScb = (ORC_SCB *) NULL; pVirEscb = (ESCB *) NULL; @@ -638,19 +604,11 @@ if (i == orc_num_scb) { printk("Unable to Reset - No SCB Found\n"); -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); -#endif return (SCSI_RESET_NOT_RUNNING); } if ((pScb = orc_alloc_scb(pHCB)) == NULL) { -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); -#endif return (SCSI_RESET_NOT_RUNNING); } pScb->SCB_Opcode = ORC_BUSDEVRST; @@ -669,17 +627,13 @@ pVirEscb->SCB_Srb = (unsigned char *) SCpnt; } orc_exec_scb(pHCB, pScb); /* Start execute SCB */ -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); -#endif return SCSI_RESET_PENDING; } /***************************************************************************/ -ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp) +ORC_SCB *__orc_alloc_scb(ORC_HCS * hcsp) { ORC_SCB *pTmpScb; UCHAR Ch; @@ -688,12 +642,6 @@ UCHAR i; ULONG flags; -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - save_flags(flags); - cli(); -#else - spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); -#endif Ch = hcsp->HCS_Index; for (i = 0; i < 8; i++) { for (index = 0; index < 32; index++) { @@ -704,21 +652,22 @@ } idx = index + 32 * i; pTmpScb = (PVOID) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB))); -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else - spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (pTmpScb); } -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else - spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (NULL); } +ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp) +{ + ORC_SCB *pTmpScb; + ULONG flags; + + spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); + pTmpScb = __orc_alloc_scb(hcsp); + spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); + return (pTmpScb); +} + /***************************************************************************/ void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp) @@ -728,22 +677,13 @@ UCHAR i; UCHAR Ch; -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - save_flags(flags); - cli(); -#else spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); -#endif Ch = hcsp->HCS_Index; Index = scbp->SCB_ScbIdx; i = Index / 32; Index %= 32; hcsp->BitAllocFlag[Ch][i] |= (1 << Index); -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif } @@ -872,15 +812,7 @@ UCHAR i; ULONG flags; -#if 0 - printk("inia100: abort SRB \n"); -#endif -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - save_flags(flags); - cli(); -#else spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); -#endif pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray; @@ -888,37 +820,21 @@ pVirEscb = pVirScb->SCB_EScb; if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) { if (pVirScb->SCB_TagMsg == 0) { -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (SCSI_ABORT_BUSY); } else { if (abort_SCB(hcsp, pVirScb)) { pVirEscb->SCB_Srb = NULL; -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (SCSI_ABORT_SUCCESS); } else { -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (SCSI_ABORT_NOT_RUNNING); } } } } -#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95) - restore_flags(flags); -#else spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); -#endif return (SCSI_ABORT_NOT_RUNNING); } diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/i60uscsi.h linux/drivers/scsi/i60uscsi.h --- v2.4.14/linux/drivers/scsi/i60uscsi.h Tue Oct 23 22:48:52 2001 +++ linux/drivers/scsi/i60uscsi.h Fri Nov 9 14:05:06 2001 @@ -342,14 +342,10 @@ UBYTE ActiveTags[16][16]; /* 50 */ ORC_TCS HCS_Tcs[16]; /* 28 */ U32 BitAllocFlag[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */ -#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) spinlock_t BitAllocFlagLock; -#endif ULONG pSRB_head; ULONG pSRB_tail; -#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) spinlock_t pSRB_lock; -#endif } ORC_HCS; /* Bit Definition for HCS_Flags */ diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c --- v2.4.14/linux/drivers/scsi/ips.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/scsi/ips.c Fri Nov 9 14:05:06 2001 @@ -7566,8 +7566,10 @@ return (0); } +#if defined (MODULE) || (LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)) static Scsi_Host_Template driver_template = IPS; #include "scsi_module.c" +#endif /* * Overrides for Emacs so that we almost follow Linus's tabbing style. diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c --- v2.4.14/linux/drivers/scsi/pci2000.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/scsi/pci2000.c Fri Nov 9 14:05:06 2001 @@ -858,7 +858,7 @@ } -MODULE_LICENSE("BSD without advertisement clause"); +MODULE_LICENSE("Dual BSD/GPL"); /* Eventually this will go into an include file, but this will be later */ static Scsi_Host_Template driver_template = PCI2000; diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.4.14/linux/drivers/scsi/pci2220i.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/scsi/pci2220i.c Fri Nov 9 14:05:06 2001 @@ -2924,7 +2924,7 @@ return 0; } -MODULE_LICENSE("BSD without advertising clause"); +MODULE_LICENSE("Dual BSD/GPL"); /* Eventually this will go into an include file, but this will be later */ static Scsi_Host_Template driver_template = PCI2220I; diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.4.14/linux/drivers/scsi/scsi.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/scsi/scsi.c Fri Nov 9 14:05:06 2001 @@ -96,17 +96,25 @@ /* Do not call reset on error if we just did a reset within 15 sec. */ #define MIN_RESET_PERIOD (15*HZ) +/* + * Macro to determine the size of SCSI command. This macro takes vendor + * unique commands into account. SCSI commands in groups 6 and 7 are + * vendor unique and we will depend upon the command length being + * supplied correctly in cmd_len. + */ +#define CDB_SIZE(SCpnt) ((((SCpnt->cmnd[0] >> 5) & 7) < 6) ? \ + COMMAND_SIZE(SCpnt->cmnd[0]) : SCpnt->cmd_len) /* * Data declarations. */ unsigned long scsi_pid; Scsi_Cmnd *last_cmnd; -/* Command groups 3 and 4 are reserved and should never be used. */ +/* Command group 3 is reserved and should never be used. */ const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, - 12, 12, 10, 10 + 16, 12, 10, 10 }; static unsigned long serial_number; static Scsi_Cmnd *scsi_bh_queue_head; @@ -679,18 +687,44 @@ * passes a meaningful return value. */ if (host->hostt->use_new_eh_code) { - spin_lock_irqsave(&io_request_lock, flags); - rtn = host->hostt->queuecommand(SCpnt, scsi_done); - spin_unlock_irqrestore(&io_request_lock, flags); - if (rtn != 0) { - scsi_delete_timer(SCpnt); - scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); - SCSI_LOG_MLQUEUE(3, printk("queuecommand : request rejected\n")); + /* + * Before we queue this command, check if the command + * length exceeds what the host adapter can handle. + */ + if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) { + spin_lock_irqsave(&io_request_lock, flags); + rtn = host->hostt->queuecommand(SCpnt, scsi_done); + spin_unlock_irqrestore(&io_request_lock, flags); + if (rtn != 0) { + scsi_delete_timer(SCpnt); + scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY); + SCSI_LOG_MLQUEUE(3, printk("queuecommand : request rejected\n")); + } + } else { + SCSI_LOG_MLQUEUE(3, printk("queuecommand : command too long.\n")); + SCpnt->result = (DID_ABORT << 16); + spin_lock_irqsave(&io_request_lock, flags); + scsi_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + rtn = 1; } } else { - spin_lock_irqsave(&io_request_lock, flags); - host->hostt->queuecommand(SCpnt, scsi_old_done); - spin_unlock_irqrestore(&io_request_lock, flags); + /* + * Before we queue this command, check if the command + * length exceeds what the host adapter can handle. + */ + if (CDB_SIZE(SCpnt) <= SCpnt->host->max_cmd_len) { + spin_lock_irqsave(&io_request_lock, flags); + host->hostt->queuecommand(SCpnt, scsi_old_done); + spin_unlock_irqrestore(&io_request_lock, flags); + } else { + SCSI_LOG_MLQUEUE(3, printk("queuecommand : command too long.\n")); + SCpnt->result = (DID_ABORT << 16); + spin_lock_irqsave(&io_request_lock, flags); + scsi_old_done(SCpnt); + spin_unlock_irqrestore(&io_request_lock, flags); + rtn = 1; + } } } else { int temp; @@ -702,8 +736,10 @@ #ifdef DEBUG_DELAY spin_unlock_irqrestore(&io_request_lock, flags); clock = jiffies + 4 * HZ; - while (time_before(jiffies, clock)) + while (time_before(jiffies, clock)) { barrier(); + cpu_relax(); + } printk("done(host = %d, result = %04x) : routine at %p\n", host->host_no, temp, host->hostt->command); spin_lock_irqsave(&io_request_lock, flags); @@ -787,14 +823,15 @@ { int i; int target = SDpnt->id; + int size = COMMAND_SIZE(((const unsigned char *)cmnd)[0]); printk("scsi_do_req (host = %d, channel = %d target = %d, " "buffer =%p, bufflen = %d, done = %p, timeout = %d, " "retries = %d)\n" "command : ", host->host_no, SDpnt->channel, target, buffer, bufflen, done, timeout, retries); - for (i = 0; i < 10; ++i) - printk("%02x ", ((unsigned char *) cmnd)[i]); - printk("\n"); + for (i = 0; i < size; ++i) + printk("%02x ", ((unsigned char *) cmnd)[i]); + printk("\n"); }); if (!host) { @@ -976,14 +1013,15 @@ { int i; int target = SCpnt->target; + int size = COMMAND_SIZE(((const unsigned char *)cmnd)[0]); printk("scsi_do_cmd (host = %d, channel = %d target = %d, " "buffer =%p, bufflen = %d, done = %p, timeout = %d, " "retries = %d)\n" "command : ", host->host_no, SCpnt->channel, target, buffer, bufflen, done, timeout, retries); - for (i = 0; i < 10; ++i) - printk("%02x ", ((unsigned char *) cmnd)[i]); - printk("\n"); + for (i = 0; i < size; ++i) + printk("%02x ", ((unsigned char *) cmnd)[i]); + printk("\n"); }); if (!host) { @@ -1476,9 +1514,6 @@ } spin_unlock_irqrestore(&device_request_lock, flags); } - -static int proc_scsi_gen_write(struct file * file, const char * buf, - unsigned long length, void *data); void __init scsi_host_no_insert(char *str, int n) { diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.4.14/linux/drivers/scsi/scsi.h Tue Oct 23 22:48:52 2001 +++ linux/drivers/scsi/scsi.h Fri Nov 9 15:02:23 2001 @@ -61,7 +61,7 @@ #endif #endif -#if defined(CONFIG_SBUS) && !defined(CONFIG_SUN3) +#if defined(CONFIG_SBUS) && !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) #include <asm/sbus.h> #if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE)) #define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir)) @@ -351,7 +351,7 @@ #define DRIVER_MASK 0x0f #define SUGGEST_MASK 0xf0 -#define MAX_COMMAND_SIZE 12 +#define MAX_COMMAND_SIZE 16 #define SCSI_SENSE_BUFFERSIZE 64 /* diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.4.14/linux/drivers/scsi/sd.c Mon Nov 5 15:55:32 2001 +++ linux/drivers/scsi/sd.c Fri Nov 9 14:05:06 2001 @@ -230,11 +230,8 @@ return -EFAULT; return 0; } - case BLKGETSIZE: /* Return device size */ - return put_user(sd[SD_PARTITION(inode->i_rdev)].nr_sects, (unsigned long *) arg); + case BLKGETSIZE: case BLKGETSIZE64: - return put_user((u64)sd[SD_PARTITION(inode->i_rdev)].nr_sects << 9, (u64 *)arg); - case BLKROSET: case BLKROGET: case BLKRASET: @@ -459,8 +456,10 @@ * is being re-read. */ - while (rscsi_disks[target].device->busy) + while (rscsi_disks[target].device->busy) { barrier(); + cpu_relax(); + } /* * The following code can sleep. * Module unloading must be prevented diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.4.14/linux/drivers/scsi/st.c Mon Nov 5 15:55:32 2001 +++ linux/drivers/scsi/st.c Fri Nov 9 13:52:21 2001 @@ -12,7 +12,7 @@ Copyright 1992 - 2001 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Wed Oct 3 22:17:59 2001 by makisara@kai.makisara.local + Last modified: Sat Nov 3 19:30:55 2001 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support @@ -21,7 +21,7 @@ error handling will be discarded. */ -static char *verstr = "20011003"; +static char *verstr = "20011103"; #include <linux/module.h> @@ -276,6 +276,17 @@ driver_byte(result) & DRIVER_MASK, host_byte(result)); } + if (STp->cln_mode >= EXTENDED_SENSE_START) { + if (STp->cln_sense_value) + STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] & + STp->cln_sense_mask) == STp->cln_sense_value); + else + STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] & + STp->cln_sense_mask) != 0); + } + if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */ + STp->cleaning_req = 1; + if ((sense[0] & 0x70) == 0x70 && scode == RECOVERED_ERROR #if ST_RECOVERED_WRITE_FATAL @@ -414,15 +425,6 @@ (STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt); scsi_release_request((STp->buffer)->last_SRpnt); - if (STbuffer->writing < STbuffer->buffer_bytes) -#if 0 - memcpy(STbuffer->b_data, - STbuffer->b_data + STbuffer->writing, - STbuffer->buffer_bytes - STbuffer->writing); -#else - printk(KERN_WARNING - "st: write_behind_check: something left in buffer!\n"); -#endif STbuffer->buffer_bytes -= STbuffer->writing; STps = &(STp->ps[STp->partition]); if (STps->drv_block >= 0) { @@ -636,47 +638,27 @@ return 0; } - -/* Open the device. Needs to be called with BKL only because of incrementing the SCSI host - module count. */ -static int st_open(struct inode *inode, struct file *filp) -{ - unsigned short st_flags; - int i, need_dma_buffer, new_session = FALSE; - int retval; - unsigned char cmd[MAX_COMMAND_SIZE]; +/* See if the drive is ready and gather information about the tape. Return values: + < 0 negative error code from errno.h + 0 drive ready + 1 drive not ready (possibly no tape) +*/ +#define CHKRES_READY 0 +#define CHKRES_NOT_READY 1 + +static int check_tape(Scsi_Tape *STp, struct file *filp) +{ + int i, retval, new_session = FALSE; + unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning; + unsigned short st_flags = filp->f_flags; Scsi_Request *SRpnt; - Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; - int dev = TAPE_NR(inode->i_rdev); + int dev = TAPE_NR(STp->devt); + struct inode *inode = filp->f_dentry->d_inode; int mode = TAPE_MODE(inode->i_rdev); - unsigned long flags; - - write_lock_irqsave(&st_dev_arr_lock, flags); - STp = scsi_tapes[dev]; - if (dev >= st_template.dev_max || STp == NULL) { - write_unlock_irqrestore(&st_dev_arr_lock, flags); - return (-ENXIO); - } - - if (STp->in_use) { - write_unlock_irqrestore(&st_dev_arr_lock, flags); - DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); ) - return (-EBUSY); - } - STp->in_use = 1; - write_unlock_irqrestore(&st_dev_arr_lock, flags); - STp->rew_at_close = STp->autorew_dev = (MINOR(inode->i_rdev) & 0x80) == 0; - - if (STp->device->host->hostt->module) - __MOD_INC_USE_COUNT(STp->device->host->hostt->module); - STp->device->access_count++; - if (!scsi_block_when_processing_errors(STp->device)) { - retval = (-ENXIO); - goto err_out; - } + STp->ready = ST_READY; if (mode != STp->current_mode) { DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", @@ -686,54 +668,11 @@ } STm = &(STp->modes[STp->current_mode]); - /* Allocate a buffer for this user */ - need_dma_buffer = STp->restr_dma; - write_lock_irqsave(&st_dev_arr_lock, flags); - for (i = 0; i < st_nbr_buffers; i++) - if (!st_buffers[i]->in_use && - (!need_dma_buffer || st_buffers[i]->dma)) { - STp->buffer = st_buffers[i]; - (STp->buffer)->in_use = 1; - break; - } - write_unlock_irqrestore(&st_dev_arr_lock, flags); - if (i >= st_nbr_buffers) { - STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE); - if (STp->buffer == NULL) { - printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev); - retval = (-EBUSY); - goto err_out; - } - } - - (STp->buffer)->writing = 0; - (STp->buffer)->syscall_result = 0; - (STp->buffer)->use_sg = STp->device->host->sg_tablesize; - - /* Compute the usable buffer size for this SCSI adapter */ - if (!(STp->buffer)->use_sg) - (STp->buffer)->buffer_size = (STp->buffer)->sg[0].length; - else { - for (i = 0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg && - i < (STp->buffer)->sg_segs; i++) - (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length; - } - - st_flags = filp->f_flags; - STp->write_prot = ((st_flags & O_ACCMODE) == O_RDONLY); - - STp->dirty = 0; - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - } - STp->ready = ST_READY; - STp->recover_count = 0; - DEB( STp->nbr_waits = STp->nbr_finished = 0; ) - memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = TEST_UNIT_READY; + saved_cleaning = STp->cleaning_req; + STp->cleaning_req = 0; SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout, MAX_READY_RETRIES, TRUE); if (!SRpnt) { @@ -742,7 +681,7 @@ } if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && - (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ + (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ /* Flush the queued UNIT ATTENTION sense data */ for (i=0; i < 10; i++) { @@ -771,6 +710,8 @@ } new_session = TRUE; } + else + STp->cleaning_req |= saved_cleaning; if ((STp->buffer)->syscall_result != 0) { if ((STp->device)->scsi_level >= SCSI_2 && @@ -788,7 +729,7 @@ STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); STp->partition = STp->new_partition = 0; STp->door_locked = ST_UNLOCKED; - return 0; + return CHKRES_NOT_READY; } if (STp->omit_blklims) @@ -869,7 +810,8 @@ DEBC(printk(ST_DEB_MSG "st%d: Write protected\n", dev)); - if ((st_flags & O_ACCMODE) == O_WRONLY || (st_flags & O_ACCMODE) == O_RDWR) { + if ((st_flags & O_ACCMODE) == O_WRONLY || + (st_flags & O_ACCMODE) == O_RDWR) { retval = (-EROFS); goto err_out; } @@ -904,6 +846,95 @@ } } + return CHKRES_READY; + + err_out: + return retval; +} + + + /* Open the device. Needs to be called with BKL only because of incrementing the SCSI host + module count. */ +static int st_open(struct inode *inode, struct file *filp) +{ + int i, need_dma_buffer; + int retval = (-EIO); + Scsi_Tape *STp; + ST_partstat *STps; + int dev = TAPE_NR(inode->i_rdev); + unsigned long flags; + + write_lock_irqsave(&st_dev_arr_lock, flags); + STp = scsi_tapes[dev]; + if (dev >= st_template.dev_max || STp == NULL) { + write_unlock_irqrestore(&st_dev_arr_lock, flags); + return (-ENXIO); + } + + if (STp->in_use) { + write_unlock_irqrestore(&st_dev_arr_lock, flags); + DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); ) + return (-EBUSY); + } + STp->in_use = 1; + write_unlock_irqrestore(&st_dev_arr_lock, flags); + STp->rew_at_close = STp->autorew_dev = (MINOR(inode->i_rdev) & 0x80) == 0; + + if (STp->device->host->hostt->module) + __MOD_INC_USE_COUNT(STp->device->host->hostt->module); + STp->device->access_count++; + + if (!scsi_block_when_processing_errors(STp->device)) { + retval = (-ENXIO); + goto err_out; + } + + /* Allocate a buffer for this user */ + need_dma_buffer = STp->restr_dma; + write_lock_irqsave(&st_dev_arr_lock, flags); + for (i = 0; i < st_nbr_buffers; i++) + if (!st_buffers[i]->in_use && + (!need_dma_buffer || st_buffers[i]->dma)) { + STp->buffer = st_buffers[i]; + (STp->buffer)->in_use = 1; + break; + } + write_unlock_irqrestore(&st_dev_arr_lock, flags); + if (i >= st_nbr_buffers) { + STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE); + if (STp->buffer == NULL) { + printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev); + retval = (-EBUSY); + goto err_out; + } + } + + (STp->buffer)->writing = 0; + (STp->buffer)->syscall_result = 0; + (STp->buffer)->use_sg = STp->device->host->sg_tablesize; + + /* Compute the usable buffer size for this SCSI adapter */ + if (!(STp->buffer)->use_sg) + (STp->buffer)->buffer_size = (STp->buffer)->sg[0].length; + else { + for (i = 0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg && + i < (STp->buffer)->sg_segs; i++) + (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length; + } + + STp->write_prot = ((filp->f_flags & O_ACCMODE) == O_RDONLY); + + STp->dirty = 0; + for (i = 0; i < ST_NBR_PARTITIONS; i++) { + STps = &(STp->ps[i]); + STps->rw = ST_IDLE; + } + STp->recover_count = 0; + DEB( STp->nbr_waits = STp->nbr_finished = 0; ) + + retval = check_tape(STp, filp); + if (retval < 0) + goto err_out; return 0; err_out: @@ -1819,7 +1850,7 @@ dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); printk(KERN_INFO - "st%d: sysv: %d\n", dev, STm->sysv); + "st%d: sysv: %d nowait: %d\n", dev, STm->sysv, STp->immediate); DEB(printk(KERN_INFO "st%d: debugging: %d\n", dev, debugging);) @@ -1856,6 +1887,7 @@ if ((STp->device)->scsi_level >= SCSI_2) STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; + STp->immediate = (options & MT_ST_NOWAIT) != 0; STm->sysv = (options & MT_ST_SYSV) != 0; DEB( debugging = (options & MT_ST_DEBUGGING) != 0; ) st_log_options(STp, STm, dev); @@ -1884,6 +1916,8 @@ STp->can_partitions = value; if ((options & MT_ST_SCSI2LOGICAL) != 0) STp->scsi2_logical = value; + if ((options & MT_ST_NOWAIT) != 0) + STp->immediate = value; if ((options & MT_ST_SYSV) != 0) STm->sysv = value; DEB( @@ -1922,6 +1956,17 @@ printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", dev, value); } + } else if (code == MT_ST_SET_CLN) { + value = (options & ~MT_ST_OPTIONS) & 0xff; + if (value != 0 && + value < EXTENDED_SENSE_START && value >= SCSI_SENSE_BUFFERSIZE) + return (-EINVAL); + STp->cln_mode = value; + STp->cln_sense_mask = (options >> 8) & 0xff; + STp->cln_sense_value = (options >> 16) & 0xff; + printk(KERN_INFO + "st%d: Cleaning request mode %d, mask %02x, value %02x\n", + dev, value, STp->cln_sense_mask, STp->cln_sense_value); } else if (code == MT_ST_DEF_OPTIONS) { code = (options & ~MT_ST_CLEAR_DEFAULT); value = (options & MT_ST_CLEAR_DEFAULT); @@ -2099,6 +2144,78 @@ STp->compression_changed = TRUE; return 0; } + + +/* Process the load and unload commands (does unload if the load code is zero) */ +static int do_load_unload(Scsi_Tape *STp, struct file *filp, int load_code) +{ + int retval = (-EIO), timeout; + DEB(int dev = TAPE_NR(STp->devt);) + unsigned char cmd[MAX_COMMAND_SIZE]; + ST_partstat *STps; + Scsi_Request *SRpnt; + + if (STp->ready != ST_READY && !load_code) { + if (STp->ready == ST_NO_TAPE) + return (-ENOMEDIUM); + else + return (-EIO); + } + + memset(cmd, 0, MAX_COMMAND_SIZE); + cmd[0] = START_STOP; + if (load_code) + cmd[4] |= 1; + /* + * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A + */ + if (load_code >= 1 + MT_ST_HPLOADER_OFFSET + && load_code <= 6 + MT_ST_HPLOADER_OFFSET) { + DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", + dev, (cmd[4]) ? "" : "un", + load_code - MT_ST_HPLOADER_OFFSET)); + cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ + } + if (STp->immediate) { + cmd[1] = 1; /* Don't wait for completion */ + timeout = STp->timeout; + } + else + timeout = STp->long_timeout; + + DEBC( + if (!load_code) + printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev); + else + printk(ST_DEB_MSG "st%d: Loading tape.\n", dev); + ); + + SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, + timeout, MAX_RETRIES, TRUE); + if (!SRpnt) + return (STp->buffer)->syscall_result; + + retval = (STp->buffer)->syscall_result; + scsi_release_request(SRpnt); + + if (!retval) { /* SCSI command successful */ + + if (!load_code) + STp->rew_at_close = 0; + else + STp->rew_at_close = STp->autorew_dev; + + retval = check_tape(STp, filp); + if (retval > 0) + retval = 0; + } + else { + STps = &(STp->ps[STp->partition]); + STps->drv_file = STps->drv_block = (-1); + } + + return retval; +} /* Internal ioctl function */ @@ -2106,7 +2223,7 @@ { int timeout; long ltmp; - int i, ioctl_result; + int ioctl_result; int chg_eof = TRUE; unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; @@ -2115,7 +2232,7 @@ int datalen = 0, direction = SCSI_DATA_NONE; int dev = TAPE_NR(STp->devt); - if (STp->ready != ST_READY && cmd_in != MTLOAD) { + if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) return (-ENOMEDIUM); else @@ -2254,42 +2371,11 @@ break; case MTREW: cmd[0] = REZERO_UNIT; -#if ST_NOWAIT - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->timeout; -#endif - DEBC(printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev)); - fileno = blkno = at_sm = 0; - break; - case MTOFFL: - case MTLOAD: - case MTUNLOAD: - cmd[0] = START_STOP; - if (cmd_in == MTLOAD) - cmd[4] |= 1; - /* - * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A - */ - if (cmd_in != MTOFFL && - arg >= 1 + MT_ST_HPLOADER_OFFSET - && arg <= 6 + MT_ST_HPLOADER_OFFSET) { - DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n", - dev, (cmd[4]) ? "" : "un", - arg - MT_ST_HPLOADER_OFFSET)); - cmd[3] = arg - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ + if (STp->immediate) { + cmd[1] = 1; /* Don't wait for completion */ + timeout = STp->timeout; } -#if ST_NOWAIT - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->timeout; -#else - timeout = STp->long_timeout; -#endif - DEBC( - if (cmd_in != MTLOAD) - printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev); - else - printk(ST_DEB_MSG "st%d: Loading tape.\n", dev); - ) + DEBC(printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev)); fileno = blkno = at_sm = 0; break; case MTNOP: @@ -2298,10 +2384,10 @@ break; case MTRETEN: cmd[0] = START_STOP; -#if ST_NOWAIT - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->timeout; -#endif + if (STp->immediate) { + cmd[1] = 1; /* Don't wait for completion */ + timeout = STp->timeout; + } cmd[4] = 3; DEBC(printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev)); fileno = blkno = at_sm = 0; @@ -2331,12 +2417,13 @@ return (-EACCES); cmd[0] = ERASE; cmd[1] = 1; /* To the end of tape */ -#if ST_NOWAIT - cmd[1] |= 2; /* Don't wait for completion */ - timeout = STp->timeout; -#else - timeout = STp->long_timeout * 8; -#endif + if (STp->immediate) { + cmd[1] |= 2; /* Don't wait for completion */ + timeout = STp->timeout; + } + else + timeout = STp->long_timeout * 8; + DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev)); fileno = blkno = at_sm = 0; break; @@ -2462,17 +2549,6 @@ else if (chg_eof) STps->eof = ST_NOEOF; - - if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) - STp->rew_at_close = 0; - else if (cmd_in == MTLOAD) { - STp->rew_at_close = STp->autorew_dev; - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].last_block_valid = FALSE; - } - STp->partition = 0; - } } else { /* SCSI command was not completely successful. Don't return from this block without releasing the SCSI command block! */ @@ -2692,10 +2768,10 @@ dev, STp->partition, partition)); } } -#if ST_NOWAIT - scmd[1] |= 1; /* Don't wait for completion */ - timeout = STp->timeout; -#endif + if (STp->immediate) { + scmd[1] |= 1; /* Don't wait for completion */ + timeout = STp->timeout; + } SRpnt = st_do_scsi(NULL, STp, scmd, 0, SCSI_DATA_NONE, timeout, MAX_READY_RETRIES, TRUE); @@ -3073,6 +3149,16 @@ goto out; } + if (mtc.mt_op == MTUNLOAD || mtc.mt_op == MTOFFL) { + retval = do_load_unload(STp, file, 0); + goto out; + } + + if (mtc.mt_op == MTLOAD) { + retval = do_load_unload(STp, file, max(1, mtc.mt_count)); + goto out; + } + if (STp->can_partitions && STp->ready == ST_READY && (i = update_partition(STp)) < 0) { retval = i; @@ -3155,6 +3241,8 @@ (STm->do_buffer_writes && STp->block_size != 0) || STp->drv_buffer != 0) mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff); + if (STp->cleaning_req) + mt_status.mt_gstat |= GMT_CLN(0xffffffff); i = copy_to_user((char *) arg, (char *) &(mt_status), sizeof(struct mtget)); @@ -3642,6 +3730,7 @@ tpnt->two_fm = ST_TWO_FM; tpnt->fast_mteom = ST_FAST_MTEOM; tpnt->scsi2_logical = ST_SCSI2LOGICAL; + tpnt->immediate = ST_NOWAIT; tpnt->write_threshold = st_write_threshold; tpnt->default_drvbuffer = 0xff; /* No forced buffering */ tpnt->partition = 0; diff -u --recursive --new-file v2.4.14/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v2.4.14/linux/drivers/scsi/st.h Mon Aug 27 12:41:44 2001 +++ linux/drivers/scsi/st.h Fri Nov 9 13:52:21 2001 @@ -1,9 +1,6 @@ #ifndef _ST_H #define _ST_H -/* - $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.h,v 1.1 1992/04/24 18:01:50 root Exp root $ - */ #ifndef _SCSI_H #include "scsi.h" @@ -78,9 +75,13 @@ unsigned char can_partitions; unsigned char two_fm; unsigned char fast_mteom; + unsigned char immediate; unsigned char restr_dma; unsigned char scsi2_logical; unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ + unsigned char cln_mode; /* 0 = none, otherwise sense byte nbr */ + unsigned char cln_sense_value; + unsigned char cln_sense_mask; unsigned char use_pf; /* Set Page Format bit in all mode selects? */ int tape_type; int write_threshold; @@ -112,6 +113,7 @@ unsigned char autorew_dev; /* auto-rewind device */ unsigned char rew_at_close; /* rewind necessary at close */ unsigned char inited; + unsigned char cleaning_req; /* cleaning requested? */ int block_size; int min_block; int max_block; @@ -167,5 +169,7 @@ #define ST_DONT_TOUCH 0 #define ST_NO 1 #define ST_YES 2 + +#define EXTENDED_SENSE_START 18 #endif diff -u --recursive --new-file v2.4.14/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c --- v2.4.14/linux/drivers/sound/ac97_codec.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/sound/ac97_codec.c Fri Nov 9 14:07:41 2001 @@ -130,7 +130,7 @@ {0x54524103, "TriTech TR28023", &null_ops}, {0x54524106, "TriTech TR28026", &null_ops}, {0x54524108, "TriTech TR28028", &tritech_ops}, - {0x54524123, "TriTech TR?????", &null_ops}, + {0x54524123, "TriTech TR A5", &null_ops}, {0x574D4C00, "Wolfson WM9704", &wolfson_ops}, {0x574D4C03, "Wolfson WM9703/9704", &wolfson_ops}, {0x574D4C04, "Wolfson WM9704 (quad)", &wolfson_ops}, @@ -143,7 +143,6 @@ {0x83847656, "SigmaTel STAC9756/57", &sigmatel_9744_ops}, {0x83847684, "SigmaTel STAC9783/84?", &null_ops}, {0x57454301, "Winbond 83971D", &null_ops}, - {0,} }; static const char *ac97_stereo_enhancements[] = diff -u --recursive --new-file v2.4.14/linux/drivers/sound/aci.c linux/drivers/sound/aci.c --- v2.4.14/linux/drivers/sound/aci.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/sound/aci.c Fri Nov 9 14:07:41 2001 @@ -47,6 +47,8 @@ * changed param aci_reset to reset, new params: ide, wss. * 2001-04-20 Robert Siemer * even more cleanups... + * 2001-10-08 Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * Get rid of check_region, .bss optimizations, use set_current_state */ #include <linux/kernel.h> @@ -70,9 +72,9 @@ #include "aci.h" -static int aci_solo=0; /* status bit of the card that can't be * +static int aci_solo; /* status bit of the card that can't be * * checked with ACI versions prior to 0xb0 */ -static int aci_amp=0; /* status bit for power-amp/line-out level +static int aci_amp; /* status bit for power-amp/line-out level but I have no docs about what is what... */ static int aci_micpreamp=3; /* microphone preamp-level that can't be * * checked with ACI versions prior to 0xb0 */ @@ -81,7 +83,7 @@ static struct semaphore aci_sem; #ifdef MODULE -static int reset = 0; +static int reset; MODULE_PARM(reset,"i"); MODULE_PARM_DESC(reset,"When set to 1, reset aci mixer."); #else @@ -146,7 +148,7 @@ case 20 ... 30: out /= 10; default: - current->state=TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(out); break; } @@ -209,28 +211,25 @@ int aci_rw_cmd(int write1, int write2, int write3) { int write[] = {write1, write2, write3}; - int read, i; + int read = -EINTR, i; if (down_interruptible(&aci_sem)) - return -EINTR; + goto out; for (i=0; i<3; i++) { if (write[i]< 0 || write[i] > 255) break; - else - if (aci_rawwrite(write[i])<0) { - up(&aci_sem); - return -EBUSY; - } + else { + read = aci_rawwrite(write[i]); + if (read < 0) + goto out_up; + } + } - if ((read=aci_rawread())<0) { - up(&aci_sem); - return -EBUSY; - } - - up(&aci_sem); - return read; + read = aci_rawread(); +out_up: up(&aci_sem); +out: return read; } EXPORT_SYMBOL(aci_rw_cmd); @@ -602,7 +601,7 @@ static int __init attach_aci(void) { char *boardname; - int i; + int i, rc = -EBUSY; init_MUTEX(&aci_sem); @@ -610,27 +609,32 @@ aci_port = (inb(0xf90) & 0x10) ? 0x344: 0x354; /* Get aci_port from MC4_PORT */ - if (check_region(aci_port, 3)) { - printk(KERN_NOTICE "aci: I/O area 0x%03x-0x%03x already used.\n", + if (!request_region(aci_port, 3, "sound mixer (ACI)")) { + printk(KERN_NOTICE + "aci: I/O area 0x%03x-0x%03x already used.\n", aci_port, aci_port+2); - return -EBUSY; + goto out; } /* force ACI into a known state */ + rc = -EFAULT; for (i=0; i<3; i++) if (aci_rw_cmd(ACI_ERROR_OP, -1, -1)<0) - return -EFAULT; + goto out_release_region; /* official this is one aci read call: */ + rc = -EFAULT; if ((aci_idcode[0]=aci_rw_cmd(ACI_READ_IDCODE, -1, -1))<0 || (aci_idcode[1]=aci_rw_cmd(ACI_READ_IDCODE, -1, -1))<0) { - printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n", aci_port); - return -EFAULT; + printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n", + aci_port); + goto out_release_region; } if ((aci_version=aci_rw_cmd(ACI_READ_VERSION, -1, -1))<0) { - printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n", aci_port); - return -EFAULT; + printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n", + aci_port); + goto out_release_region; } if (aci_idcode[0] == 'm') { @@ -660,42 +664,40 @@ aci_idcode[0], aci_idcode[1], boardname, aci_port); + rc = -EBUSY; if (reset) { /* first write()s after reset fail with my PCM20 */ if (aci_rw_cmd(ACI_INIT, -1, -1)<0 || aci_rw_cmd(ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP)<0 || aci_rw_cmd(ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP)<0) - return -EBUSY; + goto out_release_region; } /* the PCM20 is muted after reset (and reboot) */ if (aci_rw_cmd(ACI_SET_MUTE, 0x00, -1)<0) - return -EBUSY; + goto out_release_region; if (ide>=0) if (aci_rw_cmd(ACI_SET_IDE, !ide, -1)<0) - return -EBUSY; + goto out_release_region; if (wss>=0 && aci_idcode[1]=='A') if (aci_rw_cmd(ACI_SET_WSS, !!wss, -1)<0) - return -EBUSY; - - if (!request_region(aci_port, 3, "sound mixer (ACI)")) - return -ENOMEM; + goto out_release_region; - if ((mixer_device = sound_install_mixer(MIXER_DRIVER_VERSION, - boardname, - &aci_mixer_operations, - sizeof(aci_mixer_operations), - NULL)) >= 0) { - /* Maybe initialize the CS4231A mixer here... */ - } else { + mixer_device = sound_install_mixer(MIXER_DRIVER_VERSION, boardname, + &aci_mixer_operations, + sizeof(aci_mixer_operations), NULL); + rc = 0; + if (mixer_device < 0) { printk(KERN_ERR "aci: Failed to install mixer.\n"); - release_region(aci_port, 3); - return mixer_device; - } - - return 0; + rc = mixer_device; + goto out_release_region; + } /* else Maybe initialize the CS4231A mixer here... */ +out: return rc; +out_release_region: + release_region(aci_port, 3); + goto out; } static void __exit unload_aci(void) diff -u --recursive --new-file v2.4.14/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c --- v2.4.14/linux/drivers/sound/cmpci.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/sound/cmpci.c Fri Nov 9 14:07:41 2001 @@ -884,9 +884,9 @@ spin_unlock_irqrestore(&s->lock, flags); ret = prog_dmabuf(s, 1); + if (ret) return ret; spin_lock_irqsave(&s->lock, flags); - if (ret) return ret; // copy the hw state fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT); fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT); @@ -2846,6 +2846,17 @@ MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out"); MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center"); MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver"); + +static struct pci_device_id cmpci_pci_tbl[] = { + { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cmpci_pci_tbl); void initialize_chip(struct pci_dev *pcidev) { diff -u --recursive --new-file v2.4.14/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c --- v2.4.14/linux/drivers/sound/i810_audio.c Mon Nov 5 15:55:32 2001 +++ linux/drivers/sound/i810_audio.c Fri Nov 9 14:07:41 2001 @@ -2478,6 +2478,10 @@ for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { + /* Assume codec isn't available until we go through the + * gauntlet below */ + card->ac97_codec[num_ac97] = NULL; + /* The ICH programmer's reference says you should */ /* check the ready status before probing. So we chk */ /* What do we do if it's not ready? Wait and try */ @@ -2485,7 +2489,6 @@ if (!i810_ac97_exists(card,num_ac97)) { if(num_ac97 == 0) printk(KERN_ERR "i810_audio: Primary codec not ready.\n"); - card->ac97_codec[num_ac97] = 0; break; /* I think this works, if not ready stop */ } @@ -2503,6 +2506,7 @@ if(!i810_ac97_probe_and_powerup(card,codec)) { printk("i810_audio: timed out waiting for codec %d analog ready", num_ac97); + kfree(codec); break; /* it didn't work */ } /* Store state information about S/PDIF transmitter */ @@ -2750,7 +2754,7 @@ kfree(card); return -ENODEV; } - pci_dev->driver_data = card; + pci_set_drvdata(pci_dev, card); if(clocking == 48000) { i810_configure_clocking(); @@ -2778,7 +2782,7 @@ static void __exit i810_remove(struct pci_dev *pci_dev) { int i; - struct i810_card *card = pci_dev->driver_data; + struct i810_card *card = pci_get_drvdata(pci_dev); /* free hardware resources */ free_irq(card->irq, devs); release_region(card->iobase, 64); @@ -2797,7 +2801,7 @@ #ifdef CONFIG_PM static int i810_pm_suspend(struct pci_dev *dev, u32 pm_state) { - struct i810_card *card = dev->driver_data; + struct i810_card *card = pci_get_drvdata(dev); struct i810_state *state; unsigned long flags; struct dmabuf *dmabuf; @@ -2856,7 +2860,7 @@ static int i810_pm_resume(struct pci_dev *dev) { int num_ac97,i=0; - struct i810_card *card=(struct i810_card *)dev->driver_data; + struct i810_card *card=pci_get_drvdata(dev); pci_enable_device(dev); pci_restore_state (dev,card->pm_save_state); @@ -2870,7 +2874,7 @@ struct ac97_codec *codec = card->ac97_codec[num_ac97]; /* check they haven't stolen the hardware while we were away */ - if(!i810_ac97_exists(card,num_ac97)) { + if(!codec || !i810_ac97_exists(card,num_ac97)) { if(num_ac97) continue; else BUG(); } diff -u --recursive --new-file v2.4.14/linux/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c --- v2.4.14/linux/drivers/sound/maestro3.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/sound/maestro3.c Fri Nov 9 13:41:42 2001 @@ -2693,7 +2693,7 @@ goto out; } - pci_dev->driver_data = card; + pci_set_drvdata(pci_dev, card); m3_enable_ints(card); m3_assp_continue(card); @@ -2773,7 +2773,7 @@ { unsigned long flags; int i; - struct m3_card *card = pci_dev->driver_data; + struct m3_card *card = pci_get_drvdata(pci_dev); /* must be a better way.. */ save_flags(flags); @@ -2825,7 +2825,7 @@ unsigned long flags; int index; int i; - struct m3_card *card = pci_dev->driver_data; + struct m3_card *card = pci_get_drvdata(pci_dev); save_flags(flags); /* paranoia */ cli(); diff -u --recursive --new-file v2.4.14/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.4.14/linux/drivers/sound/trident.c Mon Nov 5 15:55:32 2001 +++ linux/drivers/sound/trident.c Fri Nov 9 14:07:41 2001 @@ -640,13 +640,21 @@ static void trident_free_pcm_channel(struct trident_card *card, unsigned int channel) { int bank; + unsigned char b; if (channel < 31 || channel > 63) return; + if (card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_DX || + card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_NX) { + b = inb (TRID_REG(card, T4D_REC_CH)); + if ((b & ~0x80) == channel) + outb(0x0, TRID_REG(card, T4D_REC_CH)); + } + bank = channel >> 5; channel = channel & 0x1f; - + card->banks[bank].bitmap &= ~(1 << (channel)); } diff -u --recursive --new-file v2.4.14/linux/drivers/sound/trident.h linux/drivers/sound/trident.h --- v2.4.14/linux/drivers/sound/trident.h Sun Sep 23 11:40:59 2001 +++ linux/drivers/sound/trident.h Fri Nov 9 14:07:41 2001 @@ -29,7 +29,7 @@ #endif #ifndef PCI_VENDOR_ID_SI -#define PCI_VENDOR_ID_SI 0x0139 +#define PCI_VENDOR_ID_SI 0x1039 #endif #ifndef PCI_VENDOR_ID_ALI diff -u --recursive --new-file v2.4.14/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c --- v2.4.14/linux/drivers/sound/via82cxxx_audio.c Tue Oct 9 17:06:52 2001 +++ linux/drivers/sound/via82cxxx_audio.c Fri Nov 9 13:45:35 2001 @@ -15,7 +15,7 @@ */ -#define VIA_VERSION "1.1.14b" +#define VIA_VERSION "1.9.1" #include <linux/config.h> @@ -88,9 +88,10 @@ #define VIA_MAX_FRAG_SIZE PAGE_SIZE #define VIA_MIN_FRAG_SIZE 64 -#define VIA_MIN_FRAG_NUMBER 2 +#define VIA_MIN_FRAG_NUMBER 2 /* 82C686 function 5 (audio codec) PCI configuration registers */ +#define VIA_ACLINK_STATUS 0x40 #define VIA_ACLINK_CTRL 0x41 #define VIA_FUNC_ENABLE 0x42 #define VIA_PNP_CONTROL 0x43 @@ -188,6 +189,7 @@ /* controller base 0 register bitmasks */ #define VIA_INT_DISABLE_MASK (~(0x01|0x02)) #define VIA_SGD_STOPPED (1 << 2) +#define VIA_SGD_PAUSED (1 << 6) #define VIA_SGD_ACTIVE (1 << 7) #define VIA_SGD_TERMINATE (1 << 6) #define VIA_SGD_FLAG (1 << 0) @@ -353,7 +355,10 @@ static struct pci_device_id via_pci_tbl[] __initdata = { - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5, + PCI_ANY_ID, PCI_ANY_ID, }, { 0, } }; MODULE_DEVICE_TABLE(pci,via_pci_tbl); @@ -387,7 +392,7 @@ * */ -static inline void via_chan_stop (int iobase) +static inline void via_chan_stop (long iobase) { if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE) outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL); @@ -408,7 +413,7 @@ * */ -static inline void via_chan_status_clear (int iobase) +static inline void via_chan_status_clear (long iobase) { u8 tmp = inb (iobase + VIA_PCM_STATUS); @@ -431,6 +436,19 @@ } +static int sg_active (long iobase) +{ + u8 tmp = inb (iobase + VIA_PCM_STATUS); + if ((tmp & VIA_SGD_STOPPED) || (tmp & VIA_SGD_PAUSED)) { + printk(KERN_WARNING "via82cxxx warning: SG stopped or paused\n"); + return 0; + } + if (tmp & VIA_SGD_ACTIVE) + return 1; + return 0; +} + + /**************************************************************** * * Miscellaneous debris @@ -451,6 +469,14 @@ static inline int via_syscall_down (struct via_info *card, int nonblock) { + /* Thomas Sailer: + * EAGAIN is supposed to be used if IO is pending, + * not if there is contention on some internal + * synchronization primitive which should be + * held only for a short time anyway + */ + nonblock = 0; + if (nonblock) { if (down_trylock (&card->syscall_sem)) return -EAGAIN; @@ -473,6 +499,8 @@ static void via_stop_everything (struct via_info *card) { + u8 tmp, new_tmp; + DPRINTK ("ENTER\n"); assert (card != NULL); @@ -492,11 +520,32 @@ via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN); /* - * clear any enabled interrupt bits, reset to 8-bit mono PCM mode + * clear any enabled interrupt bits */ - outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE); - outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE); - outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE); + tmp = inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE); + new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL); + if (tmp != new_tmp) + outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE); + + tmp = inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE); + new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL); + if (tmp != new_tmp) + outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE); + + tmp = inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE); + new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL); + if (tmp != new_tmp) + outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE); + + udelay(10); + + /* + * clear any existing flags + */ + via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN); + via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN); + via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN); + DPRINTK ("EXIT\n"); } @@ -521,6 +570,8 @@ DPRINTK ("ENTER, rate = %d\n", rate); + if (chan->rate == rate) + goto out; if (card->locked_rate) { chan->rate = 48000; goto out; @@ -614,7 +665,7 @@ * Performs some of the preparations necessary to begin * using a PCM channel. * - * Currently the preparations consist in + * Currently the preparations consist in * setting the * PCM channel to a known state. */ @@ -682,7 +733,7 @@ /* alloc DMA-able memory for scatter-gather buffers */ - chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE + + chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE + (((chan->frag_number * chan->frag_size) % PAGE_SIZE) ? 1 : 0); for (i = 0; i < chan->page_number; i++) { @@ -719,7 +770,7 @@ i, (long)chan->sgtable[i].addr); #endif - } + } /* overwrite the last buffer information */ chan->sgtable[chan->frag_number - 1].count = cpu_to_le32 (chan->frag_size | VIA_EOL); @@ -766,17 +817,17 @@ { DPRINTK ("ENTER\n"); - synchronize_irq(); - spin_lock_irq (&card->lock); /* stop any existing channel output */ + via_chan_status_clear (chan->iobase); via_chan_stop (chan->iobase); via_chan_status_clear (chan->iobase); - via_chan_pcm_fmt (chan, 1); spin_unlock_irq (&card->lock); + synchronize_irq(); + DPRINTK ("EXIT\n"); } @@ -844,7 +895,7 @@ /* if we are recording, enable recording fifo bit */ if (chan->is_record) chan->pcm_fmt |= VIA_PCM_REC_FIFO; - /* set interrupt select bits where applicable (PCM & FM out channels) */ + /* set interrupt select bits where applicable (PCM in & out channels) */ if (!chan->is_record) chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT; @@ -1017,7 +1068,7 @@ DPRINTK ("ENTER\n"); /* in both cases the buffer cannot be changed */ - if (chan->is_active || chan->is_mapped) { + if (chan->is_active || chan->is_mapped) { DPRINTK ("EXIT\n"); return -EINVAL; } @@ -1147,6 +1198,8 @@ static inline void via_chan_maybe_start (struct via_channel *chan) { + assert (chan->is_active == sg_active(chan->iobase)); + if (!chan->is_active && chan->is_enabled) { chan->is_active = 1; sg_begin (chan); @@ -1227,10 +1280,12 @@ data = (reg << 16) | VIA_CR80_READ | VIA_CR80_VALID; outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL); + udelay (20); + for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) { - udelay (1); - if ((((data = inl(card->baseaddr + 0x80)) & - (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID)) + udelay (1); + if ((((data = inl(card->baseaddr + VIA_BASE0_AC97_CTRL)) & + (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID)) goto out; } @@ -1240,9 +1295,11 @@ out: /* Once the valid bit has become set, we must wait a complete AC97 frame before the data has settled. */ - udelay(25); - data = (unsigned long) inl (card->baseaddr + 0x80); - + udelay(25); + data = (unsigned long) inl (card->baseaddr + VIA_BASE0_AC97_CTRL); + + outb (0x02, card->baseaddr + 0x83); + if (((data & 0x007F0000) >> 16) == reg) { DPRINTK ("EXIT, success, data=0x%lx, retval=0x%lx\n", data, data & 0x0000FFFF); @@ -1370,6 +1427,7 @@ static int __init via_ac97_reset (struct via_info *card) { struct pci_dev *pdev = card->pdev; + u8 tmp8; u16 tmp16; DPRINTK ("ENTER\n"); @@ -1403,20 +1461,43 @@ #endif /* - * reset AC97 controller: enable, disable, enable - * pause after each command for good luck + * Reset AC97 controller: enable, disable, enable, + * pausing after each command for good luck. Only + * do this if the codec is not ready, because it causes + * loud pops and such due to such a hard codec reset. */ - pci_write_config_byte (pdev, VIA_ACLINK_CTRL, VIA_CR41_AC97_ENABLE | - VIA_CR41_AC97_RESET | VIA_CR41_AC97_WAKEUP); - udelay (100); - - pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0); - udelay (100); - - pci_write_config_byte (pdev, VIA_ACLINK_CTRL, - VIA_CR41_AC97_ENABLE | VIA_CR41_PCM_ENABLE | - VIA_CR41_VRA | VIA_CR41_AC97_RESET); - udelay (100); + pci_read_config_byte (pdev, VIA_ACLINK_STATUS, &tmp8); + if ((tmp8 & VIA_CR40_AC97_READY) == 0) { + pci_write_config_byte (pdev, VIA_ACLINK_CTRL, + VIA_CR41_AC97_ENABLE | + VIA_CR41_AC97_RESET | + VIA_CR41_AC97_WAKEUP); + udelay (100); + + pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0); + udelay (100); + + pci_write_config_byte (pdev, VIA_ACLINK_CTRL, + VIA_CR41_AC97_ENABLE | + VIA_CR41_PCM_ENABLE | + VIA_CR41_VRA | VIA_CR41_AC97_RESET); + udelay (100); + } + + /* Make sure VRA is enabled, in case we didn't do a + * complete codec reset, above + */ + pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8); + if (((tmp8 & VIA_CR41_VRA) == 0) || + ((tmp8 & VIA_CR41_AC97_ENABLE) == 0) || + ((tmp8 & VIA_CR41_PCM_ENABLE) == 0) || + ((tmp8 & VIA_CR41_AC97_RESET) == 0)) { + pci_write_config_byte (pdev, VIA_ACLINK_CTRL, + VIA_CR41_AC97_ENABLE | + VIA_CR41_PCM_ENABLE | + VIA_CR41_VRA | VIA_CR41_AC97_RESET); + udelay (100); + } #if 0 /* this breaks on K7M */ /* disable legacy stuff */ @@ -1433,20 +1514,10 @@ /* WARNING: this line is magic. Remove this * and things break. */ - /* enable variable rate, variable rate MIC ADC */ - /* - * If we cannot enable VRA, we have a locked-rate codec. - * We try again to enable VRA before assuming so, however. - */ + /* enable variable rate */ tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); - if ((tmp16 & 1) == 0) { + if ((tmp16 & 1) == 0) via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); - tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); - if ((tmp16 & 1) == 0) { - card->locked_rate = 1; - printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n"); - } - } DPRINTK ("EXIT, returning 0\n"); return 0; @@ -1494,10 +1565,24 @@ goto err_out; } - /* enable variable rate, variable rate MIC ADC */ + /* enable variable rate */ tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); + /* + * If we cannot enable VRA, we have a locked-rate codec. + * We try again to enable VRA before assuming so, however. + */ + tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); + if ((tmp16 & 1) == 0) { + via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); + tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); + if ((tmp16 & 1) == 0) { + card->locked_rate = 1; + printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n"); + } + } + DPRINTK ("EXIT, returning 0\n"); return 0; @@ -1632,7 +1717,7 @@ uart401intr(irq, card->midi_devc, regs); #endif return; - } + } DPRINTK ("intr, status32 == 0x%08X\n", status32); /* synchronize interrupt handling under SMP. this spinlock @@ -1652,47 +1737,6 @@ /** - * via_interrupt_disable - Disable all interrupt-generating sources - * @card: Private info for specified board - * - * Disables all interrupt-generation flags in the Via - * audio hardware registers. - */ - -static void via_interrupt_disable (struct via_info *card) -{ - u8 tmp8; - unsigned long flags; - - DPRINTK ("ENTER\n"); - - assert (card != NULL); - - spin_lock_irqsave (&card->lock, flags); - - pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8); - if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) { - tmp8 |= VIA_CR48_FM_TRAP_TO_NMI; - pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8); - } - - outb (inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE) & - VIA_INT_DISABLE_MASK, - card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE); - outb (inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE) & - VIA_INT_DISABLE_MASK, - card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE); - outb (inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE) & - VIA_INT_DISABLE_MASK, - card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE); - - spin_unlock_irqrestore (&card->lock, flags); - - DPRINTK ("EXIT\n"); -} - - -/** * via_interrupt_init - Initialize interrupt handling * @card: Private info for specified board * @@ -1703,6 +1747,8 @@ static int via_interrupt_init (struct via_info *card) { + u8 tmp8; + DPRINTK ("ENTER\n"); assert (card != NULL); @@ -1716,6 +1762,13 @@ return -EIO; } + /* make sure FM irq is not routed to us */ + pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8); + if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) { + tmp8 |= VIA_CR48_FM_TRAP_TO_NMI; + pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8); + } + if (request_irq (card->pdev->irq, via_interrupt, SA_SHIRQ, VIA_MODULE_NAME, card)) { printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n", card->pdev->irq); @@ -1723,38 +1776,11 @@ return -EBUSY; } - /* we don't want interrupts until we're opened */ - via_interrupt_disable (card); - DPRINTK ("EXIT, returning 0\n"); return 0; } -/** - * via_interrupt_cleanup - Shutdown driver interrupt handling - * @card: Private info for specified board - * - * Disable any potential interrupt sources in the Via audio - * hardware, and then release (un-reserve) the IRQ line - * in the kernel core. - */ - -static void via_interrupt_cleanup (struct via_info *card) -{ - DPRINTK ("ENTER\n"); - - assert (card != NULL); - assert (card->pdev != NULL); - - via_interrupt_disable (card); - - free_irq (card->pdev->irq, card); - - DPRINTK ("EXIT\n"); -} - - /**************************************************************** * * OSS DSP device @@ -1958,18 +1984,27 @@ char *userbuf, size_t count, int nonblock) { + DECLARE_WAITQUEUE(wait, current); const char *orig_userbuf = userbuf; struct via_channel *chan = &card->ch_in; size_t size; int n, tmp; + ssize_t ret = 0; /* if SGD has not yet been started, start it */ via_chan_maybe_start (chan); handle_one_block: /* just to be a nice neighbor */ - if (current->need_resched) + /* Thomas Sailer: + * But also to ourselves, release semaphore if we do so */ + if (current->need_resched) { + up(&card->syscall_sem); schedule (); + ret = via_syscall_down (card, nonblock); + if (ret) + goto out; + } /* grab current channel software pointer. In the case of * recording, this is pointing to the next buffer that @@ -1981,33 +2016,53 @@ * to be copied to userland. sleep until at least * one buffer has been read from the audio hardware. */ - tmp = atomic_read (&chan->n_frags); - assert (tmp >= 0); - assert (tmp <= chan->frag_number); - while (tmp == 0) { - if (nonblock || !chan->is_active) - return -EAGAIN; + add_wait_queue(&chan->wait, &wait); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + tmp = atomic_read (&chan->n_frags); + assert (tmp >= 0); + assert (tmp <= chan->frag_number); + if (tmp) + break; + if (nonblock || !chan->is_active) { + ret = -EAGAIN; + break; + } + + up(&card->syscall_sem); DPRINTK ("Sleeping on block %d\n", n); - interruptible_sleep_on (&chan->wait); + schedule(); - if (signal_pending (current)) - return -ERESTARTSYS; + ret = via_syscall_down (card, nonblock); + if (ret) + break; - tmp = atomic_read (&chan->n_frags); + if (signal_pending (current)) { + ret = -ERESTARTSYS; + break; + } } + set_current_state(TASK_RUNNING); + remove_wait_queue(&chan->wait, &wait); + if (ret) + goto out; /* Now that we have a buffer we can read from, send * as much as sample data possible to userspace. */ while ((count > 0) && (chan->slop_len < chan->frag_size)) { size_t slop_left = chan->frag_size - chan->slop_len; + void *base = chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr; + unsigned ofs = n % (PAGE_SIZE / chan->frag_size); size = (count < slop_left) ? count : slop_left; if (copy_to_user (userbuf, - chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + n % (PAGE_SIZE / chan->frag_size) + chan->slop_len, - size)) - return -EFAULT; + base + ofs + chan->slop_len, + size)) { + ret = -EFAULT; + goto out; + } count -= size; chan->slop_len += size; @@ -2056,7 +2111,7 @@ goto handle_one_block; out: - return userbuf - orig_userbuf; + return (userbuf != orig_userbuf) ? (userbuf - orig_userbuf) : ret; } @@ -2107,16 +2162,25 @@ const char *userbuf, size_t count, int nonblock) { + DECLARE_WAITQUEUE(wait, current); const char *orig_userbuf = userbuf; struct via_channel *chan = &card->ch_out; volatile struct via_sgd_table *sgtable = chan->sgtable; size_t size; int n, tmp; + ssize_t ret = 0; handle_one_block: /* just to be a nice neighbor */ - if (current->need_resched) + /* Thomas Sailer: + * But also to ourselves, release semaphore if we do so */ + if (current->need_resched) { + up(&card->syscall_sem); schedule (); + ret = via_syscall_down (card, nonblock); + if (ret) + goto out; + } /* grab current channel fragment pointer. In the case of * playback, this is pointing to the next fragment that @@ -2128,21 +2192,37 @@ * to be filled by userspace. Sleep until * at least one fragment is available for our use. */ - tmp = atomic_read (&chan->n_frags); - assert (tmp >= 0); - assert (tmp <= chan->frag_number); - while (tmp == 0) { - if (nonblock || !chan->is_enabled) - return -EAGAIN; + add_wait_queue(&chan->wait, &wait); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + tmp = atomic_read (&chan->n_frags); + assert (tmp >= 0); + assert (tmp <= chan->frag_number); + if (tmp) + break; + if (nonblock || !chan->is_active) { + ret = -EAGAIN; + break; + } + + up(&card->syscall_sem); DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record); - interruptible_sleep_on (&chan->wait); + schedule(); - if (signal_pending (current)) - return -ERESTARTSYS; + ret = via_syscall_down (card, nonblock); + if (ret) + break; - tmp = atomic_read (&chan->n_frags); + if (signal_pending (current)) { + ret = -ERESTARTSYS; + break; + } } + set_current_state(TASK_RUNNING); + remove_wait_queue(&chan->wait, &wait); + if (ret) + goto out; /* Now that we have at least one fragment we can write to, fill the buffer * as much as possible with data from userspace. @@ -2152,8 +2232,10 @@ size = (count < slop_left) ? count : slop_left; if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len, - userbuf, size)) - return -EFAULT; + userbuf, size)) { + ret = -EFAULT; + goto out; + } count -= size; chan->slop_len += size; @@ -2264,7 +2346,8 @@ static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait) { struct via_info *card; - unsigned int mask = 0, rd, wr; + struct via_channel *chan; + unsigned int mask = 0; DPRINTK ("ENTER\n"); @@ -2272,28 +2355,21 @@ card = file->private_data; assert (card != NULL); - rd = (file->f_mode & FMODE_READ); - wr = (file->f_mode & FMODE_WRITE); - - if (wr && (atomic_read (&card->ch_out.n_frags) == 0)) { - assert (card->ch_out.is_active); - poll_wait(file, &card->ch_out.wait, wait); - } - if (rd) { - /* XXX is it ok, spec-wise, to start DMA here? */ - if (!card->ch_in.is_active) { - via_chan_set_buffering(card, &card->ch_in, -1); - via_chan_buffer_init(card, &card->ch_in); - } - via_chan_maybe_start (&card->ch_in); - if (atomic_read (&card->ch_in.n_frags) == 0) - poll_wait(file, &card->ch_in.wait, wait); + if (file->f_mode & FMODE_READ) { + chan = &card->ch_in; + if (sg_active (chan->iobase)) + poll_wait(file, &chan->wait, wait); + if (atomic_read (&chan->n_frags) > 0) + mask |= POLLIN | POLLRDNORM; } - if (wr && ((atomic_read (&card->ch_out.n_frags) > 0) || !card->ch_out.is_active)) - mask |= POLLOUT | POLLWRNORM; - if (rd && (atomic_read (&card->ch_in.n_frags) > 0)) - mask |= POLLIN | POLLRDNORM; + if (file->f_mode & FMODE_WRITE) { + chan = &card->ch_out; + if (sg_active (chan->iobase)) + poll_wait(file, &chan->wait, wait); + if (atomic_read (&chan->n_frags) > 0) + mask |= POLLOUT | POLLWRNORM; + } DPRINTK ("EXIT, returning %u\n", mask); return mask; @@ -2315,6 +2391,9 @@ static int via_dsp_drain_playback (struct via_info *card, struct via_channel *chan, int nonblock) { + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + DPRINTK ("ENTER, nonblock = %d\n", nonblock); if (chan->slop_len > 0) @@ -2325,10 +2404,16 @@ via_chan_maybe_start (chan); - while (atomic_read (&chan->n_frags) < chan->frag_number) { + add_wait_queue(&chan->wait, &wait); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + if (atomic_read (&chan->n_frags) >= chan->frag_number) + break; + if (nonblock) { DPRINTK ("EXIT, returning -EAGAIN\n"); - return -EAGAIN; + ret = -EAGAIN; + break; } #ifdef VIA_DEBUG @@ -2357,14 +2442,22 @@ printk (KERN_ERR "sleeping but not active\n"); #endif + up(&card->syscall_sem); + DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags)); - interruptible_sleep_on (&chan->wait); + schedule(); + + if ((ret = via_syscall_down (card, nonblock))) + break; if (signal_pending (current)) { DPRINTK ("EXIT, returning -ERESTARTSYS\n"); - return -ERESTARTSYS; + ret = -ERESTARTSYS; + break; } } + set_current_state(TASK_RUNNING); + remove_wait_queue(&chan->wait, &wait); #ifdef VIA_DEBUG { @@ -2392,8 +2485,8 @@ #endif out: - DPRINTK ("EXIT, returning 0\n"); - return 0; + DPRINTK ("EXIT, returning %d\n", ret); + return ret; } @@ -2695,7 +2788,6 @@ DPRINTK ("DSP_RESET\n"); if (rd) { via_chan_clear (card, &card->ch_in); - via_chan_pcm_fmt (&card->ch_in, 1); card->ch_in.frag_number = 0; card->ch_in.frag_size = 0; atomic_set(&card->ch_in.n_frags, 0); @@ -2703,7 +2795,6 @@ if (wr) { via_chan_clear (card, &card->ch_out); - via_chan_pcm_fmt (&card->ch_out, 1); card->ch_out.frag_number = 0; card->ch_out.frag_size = 0; atomic_set(&card->ch_out.n_frags, 0); @@ -2712,6 +2803,11 @@ rc = 0; break; + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + rc = 0; + break; + /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */ case SNDCTL_DSP_GETCAPS: DPRINTK ("DSP_GETCAPS\n"); @@ -2812,6 +2908,15 @@ break; + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if ((file->f_mode & FMODE_READ) && card->ch_in.is_enabled) + val |= PCM_ENABLE_INPUT; + if ((file->f_mode & FMODE_WRITE) && card->ch_out.is_enabled) + val |= PCM_ENABLE_OUTPUT; + rc = put_user(val, (int *)arg); + break; + /* Enable full duplex. Since we do this as soon as we are opened * with O_RDWR, this is mainly a no-op that always returns success. */ @@ -2834,7 +2939,7 @@ rc = via_chan_set_buffering(card, &card->ch_in, val); if (wr) - rc = via_chan_set_buffering(card, &card->ch_out, val); + rc = via_chan_set_buffering(card, &card->ch_out, val); DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n", val & 0xFFFF, @@ -2952,7 +3057,7 @@ via_chan_pcm_fmt (chan, 0); via_set_rate (&card->ac97, chan, 44100); } else { - via_chan_pcm_fmt (chan, 0); + via_chan_pcm_fmt (chan, 1); via_set_rate (&card->ac97, chan, 8000); } } @@ -3127,7 +3232,7 @@ pci_read_config_byte (pdev, 0x43, &r43); card->midi_info.io_base = 0x300 + ((r43 & 0x0c) << 2); } - + card->midi_info.irq = -pdev->irq; if (probe_uart401(& card->midi_info, THIS_MODULE)) { @@ -3181,10 +3286,10 @@ #ifdef CONFIG_MIDI_VIA82CXXX if (card->midi_info.io_base) - unload_uart401(&card->midi_info); + unload_uart401(&card->midi_info); #endif - via_interrupt_cleanup (card); + free_irq (card->pdev->irq, card); via_card_cleanup_proc (card); via_dsp_cleanup (card); via_ac97_cleanup (card); @@ -3197,8 +3302,8 @@ pci_set_drvdata (pdev, NULL); pci_release_regions (pdev); - pci_set_power_state (pdev, 3); /* ...zzzzzz */ pci_disable_device (pdev); + pci_set_power_state (pdev, 3); /* ...zzzzzz */ DPRINTK ("EXIT\n"); return; diff -u --recursive --new-file v2.4.14/linux/drivers/sound/vwsnd.c linux/drivers/sound/vwsnd.c --- v2.4.14/linux/drivers/sound/vwsnd.c Mon Aug 27 12:41:45 2001 +++ linux/drivers/sound/vwsnd.c Fri Nov 9 14:07:41 2001 @@ -3449,6 +3449,7 @@ MODULE_DESCRIPTION("SGI Visual Workstation sound module"); MODULE_AUTHOR("Bob Miller <kbob@sgi.com>"); +MODULE_LICENSE("GPL"); static int __init init_vwsnd(void) { diff -u --recursive --new-file v2.4.14/linux/drivers/usb/storage/freecom.c linux/drivers/usb/storage/freecom.c --- v2.4.14/linux/drivers/usb/storage/freecom.c Sun Aug 12 13:28:00 2001 +++ linux/drivers/usb/storage/freecom.c Fri Nov 9 14:37:14 2001 @@ -1,6 +1,6 @@ /* Driver for Freecom USB/IDE adaptor * - * $Id: freecom.c,v 1.15 2001/06/27 23:50:28 mdharm Exp $ + * $Id: freecom.c,v 1.18 2001/11/04 13:01:17 mdharm Exp $ * * Freecom v0.1: * @@ -132,6 +132,12 @@ sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) { + US_DEBUGP("transfer_amount: %d and total_transferred: %d\n", transfer_amount, total_transferred); + + /* End this if we're done */ + if (transfer_amount == total_transferred) + break; + /* transfer the lesser of the next buffer or the * remaining data */ if (transfer_amount - total_transferred >= @@ -139,10 +145,12 @@ result = usb_stor_transfer_partial(us, sg[i].address, sg[i].length); total_transferred += sg[i].length; - } else + } else { result = usb_stor_transfer_partial(us, sg[i].address, transfer_amount - total_transferred); + total_transferred += transfer_amount - total_transferred; + } /* if we get an error, end the loop here */ if (result) @@ -158,7 +166,7 @@ srb->result = result; } - +#if 0 /* Write a value to an ide register. */ static int freecom_ide_write (struct us_data *us, int reg, int value) @@ -255,6 +263,7 @@ return USB_STOR_TRANSPORT_GOOD; } +#endif static int freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, @@ -470,13 +479,15 @@ US_DEBUGP("Device indicates that it has %d bytes available\n", le16_to_cpu (fst->Count)); - /* Find the length we desire to read. It is the lesser of the SCSI - * layer's requested length, and the length the device claims to - * have available. */ + /* Find the length we desire to read. */ length = usb_stor_transfer_length (srb); US_DEBUGP("SCSI requested %d\n", length); - if (length > le16_to_cpu (fst->Count)) - length = le16_to_cpu (fst->Count); + + /* verify that this amount is legal */ + if (length > srb->request_bufflen) { + length = srb->request_bufflen; + US_DEBUGP("Truncating request to match buffer length: %d\n", length); + } /* What we do now depends on what direction the data is supposed to * move in. */ @@ -522,7 +533,6 @@ if (result != USB_STOR_TRANSPORT_GOOD) return result; -#if 1 US_DEBUGP("FCM: Waiting for status\n"); result = usb_stor_bulk_msg (us, fst, ipipe, FCM_PACKET_LENGTH, &partial); @@ -540,7 +550,7 @@ US_DEBUGP("Drive seems still hungry\n"); return USB_STOR_TRANSPORT_FAILED; } -#endif + US_DEBUGP("Transfer happy\n"); break; @@ -570,8 +580,7 @@ int freecom_init (struct us_data *us) { - int result, value; - int counter; + int result; char buffer[33]; /* Allocate a buffer for us. The upper usb transport code will @@ -591,42 +600,29 @@ buffer[32] = '\0'; US_DEBUGP("String returned from FC init is: %s\n", buffer); - result = freecom_ide_write (us, 0x06, 0xA0); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - result = freecom_ide_write (us, 0x01, 0x00); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - counter = 50; - do { - result = freecom_ide_read (us, 0x07, &value); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - if (counter-- < 0) { - US_DEBUGP("Timeout in freecom"); - return USB_STOR_TRANSPORT_ERROR; - } - } while ((value & 0x80) != 0); + /* Special thanks to the people at Freecom for providing me with + * this "magic sequence", which they use in their Windows and MacOS + * drivers to make sure that all the attached perhiperals are + * properly reset. + */ - result = freecom_ide_write (us, 0x07, 0x08); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - counter = 50; - do { - result = freecom_ide_read (us, 0x07, &value); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - if (counter-- < 0) { - US_DEBUGP("Timeout in freecom"); - return USB_STOR_TRANSPORT_ERROR; - } - } while ((value & 0x80) != 0); + /* send reset */ + result = usb_control_msg(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, 0), + 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); + US_DEBUGP("result from activate reset is %d\n", result); + + /* wait 250ms */ + mdelay(250); + + /* clear reset */ + result = usb_control_msg(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, 0), + 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); + US_DEBUGP("result from clear reset is %d\n", result); - result = freecom_ide_write (us, 0x08, 0x08); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + /* wait 3 seconds */ + mdelay(3 * 1000); return USB_STOR_TRANSPORT_GOOD; } diff -u --recursive --new-file v2.4.14/linux/drivers/usb/storage/scsiglue.c linux/drivers/usb/storage/scsiglue.c --- v2.4.14/linux/drivers/usb/storage/scsiglue.c Sun Sep 23 11:41:00 2001 +++ linux/drivers/usb/storage/scsiglue.c Fri Nov 9 14:37:14 2001 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * SCSI layer glue code * - * $Id: scsiglue.c,v 1.22 2001/09/02 04:29:27 mdharm Exp $ + * $Id: scsiglue.c,v 1.23 2001/10/15 07:02:32 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) diff -u --recursive --new-file v2.4.14/linux/drivers/usb/storage/sddr09.c linux/drivers/usb/storage/sddr09.c --- v2.4.14/linux/drivers/usb/storage/sddr09.c Mon Nov 5 15:55:32 2001 +++ linux/drivers/usb/storage/sddr09.c Fri Nov 9 14:37:14 2001 @@ -1,6 +1,6 @@ /* Driver for SanDisk SDDR-09 SmartMedia reader * - * $Id: sddr09.c,v 1.19 2001/09/02 06:07:20 mdharm Exp $ + * $Id: sddr09.c,v 1.21 2001/11/06 03:18:36 mdharm Exp $ * * SDDR09 driver v0.1: * diff -u --recursive --new-file v2.4.14/linux/drivers/usb/storage/transport.c linux/drivers/usb/storage/transport.c --- v2.4.14/linux/drivers/usb/storage/transport.c Sun Sep 23 11:41:00 2001 +++ linux/drivers/usb/storage/transport.c Fri Nov 9 14:37:14 2001 @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.40 2001/08/18 08:37:46 mdharm Exp $ + * $Id: transport.c,v 1.41 2001/10/15 07:02:32 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) diff -u --recursive --new-file v2.4.14/linux/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c --- v2.4.14/linux/drivers/usb/storage/usb.c Sun Sep 23 11:41:00 2001 +++ linux/drivers/usb/storage/usb.c Fri Nov 9 14:37:14 2001 @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.67 2001/07/29 23:41:52 mdharm Exp $ + * $Id: usb.c,v 1.68 2001/10/15 07:02:33 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) diff -u --recursive --new-file v2.4.14/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.4.14/linux/drivers/usb/uhci.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/usb/uhci.c Fri Nov 9 13:41:42 2001 @@ -2623,7 +2623,7 @@ uhci->dev = dev; uhci->io_addr = io_addr; uhci->io_size = io_size; - dev->driver_data = uhci; + pci_set_drvdata(dev, uhci); #ifdef CONFIG_PROC_FS uhci->num = uhci_num++; @@ -2931,7 +2931,7 @@ static void __devexit uhci_pci_remove(struct pci_dev *dev) { - struct uhci *uhci = dev->driver_data; + struct uhci *uhci = pci_get_drvdata(dev); if (uhci->bus->root_hub) usb_disconnect(&uhci->bus->root_hub); @@ -2956,14 +2956,14 @@ #ifdef CONFIG_PM static int uhci_pci_suspend(struct pci_dev *dev, u32 state) { - suspend_hc((struct uhci *) dev->driver_data); + suspend_hc((struct uhci *) pci_get_drvdata(dev)); return 0; } static int uhci_pci_resume(struct pci_dev *dev) { - reset_hc((struct uhci *) dev->driver_data); - start_hc((struct uhci *) dev->driver_data); + reset_hc((struct uhci *) pci_get_drvdata(dev)); + start_hc((struct uhci *) pci_get_drvdata(dev)); return 0; } #endif diff -u --recursive --new-file v2.4.14/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.4.14/linux/drivers/usb/usb-ohci.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/usb/usb-ohci.c Fri Nov 9 13:41:42 2001 @@ -2372,7 +2372,7 @@ ohci->regs = mem_base; ohci->ohci_dev = dev; - dev->driver_data = ohci; + pci_set_drvdata(dev, ohci); INIT_LIST_HEAD (&ohci->ohci_hcd_list); list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); @@ -2411,7 +2411,7 @@ free_irq (ohci->irq, ohci); ohci->irq = -1; } - ohci->ohci_dev->driver_data = 0; + pci_set_drvdata(ohci->ohci_dev, NULL); usb_deregister_bus (ohci->bus); usb_free_bus (ohci->bus); @@ -2600,7 +2600,7 @@ static void __devexit ohci_pci_remove (struct pci_dev *dev) { - ohci_t *ohci = (ohci_t *) dev->driver_data; + ohci_t *ohci = pci_get_drvdata(dev); dbg ("remove %s controller usb-%s%s%s", hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), @@ -2636,7 +2636,7 @@ static int ohci_pci_suspend (struct pci_dev *dev, u32 state) { - ohci_t *ohci = (ohci_t *) dev->driver_data; + ohci_t *ohci = pci_get_drvdata(dev); unsigned long flags; u16 cmd; @@ -2715,7 +2715,7 @@ static int ohci_pci_resume (struct pci_dev *dev) { - ohci_t *ohci = (ohci_t *) dev->driver_data; + ohci_t *ohci = pci_get_drvdata(dev); int temp; unsigned long flags; diff -u --recursive --new-file v2.4.14/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c --- v2.4.14/linux/drivers/usb/usb-uhci.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/usb/usb-uhci.c Fri Nov 9 13:41:42 2001 @@ -2848,7 +2848,7 @@ _static void __devexit uhci_pci_remove (struct pci_dev *dev) { - uhci_t *s = (uhci_t*) dev->driver_data; + uhci_t *s = pci_get_drvdata(dev); struct usb_device *root_hub = s->bus->root_hub; s->running = 0; // Don't allow submit_urb @@ -2895,14 +2895,14 @@ _static int uhci_pci_suspend (struct pci_dev *dev, u32 state) { - reset_hc((uhci_t *) dev->driver_data); + reset_hc((uhci_t *) pci_get_drvdata(dev)); return 0; } _static int uhci_pci_resume (struct pci_dev *dev) { - start_hc((uhci_t *) dev->driver_data); + start_hc((uhci_t *) pci_get_drvdata(dev)); return 0; } #endif @@ -3006,7 +3006,7 @@ } //chain new uhci device into global list - dev->driver_data = s; + pci_set_drvdata(dev, s); devs=s; return 0; diff -u --recursive --new-file v2.4.14/linux/drivers/video/hgafb.c linux/drivers/video/hgafb.c --- v2.4.14/linux/drivers/video/hgafb.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/video/hgafb.c Fri Nov 9 14:16:28 2001 @@ -312,10 +312,10 @@ static int __init hga_card_detect(void) { int count=0; - u16 *p, p_save; - u16 *q, q_save; + unsigned char p, p_save; + unsigned char q, q_save; - hga_vram_base = VGA_MAP_MEM(0xb0000); + hga_vram_base = 0xb0000; hga_vram_len = 0x08000; if (request_region(0x3b0, 12, "hgafb")) @@ -325,14 +325,14 @@ /* do a memory check */ - p = (u16 *) hga_vram_base; - q = (u16 *) (hga_vram_base + 0x01000); + p = hga_vram_base; + q = hga_vram_base + 0x01000; - p_save = scr_readw(p); q_save = scr_readw(q); + p_save = isa_readw(p); q_save = isa_readw(q); - scr_writew(0xaa55, p); if (scr_readw(p) == 0xaa55) count++; - scr_writew(0x55aa, p); if (scr_readw(p) == 0x55aa) count++; - scr_writew(p_save, p); + isa_writew(0xaa55, p); if (isa_readw(p) == 0xaa55) count++; + isa_writew(0x55aa, p); if (isa_readw(p) == 0x55aa) count++; + isa_writew(p_save, p); if (count != 2) { return 0; @@ -717,7 +717,7 @@ if (!nologo) hga_show_logo(); #endif /* MODULE */ - hga_fix.smem_start = hga_vram_base; + hga_fix.smem_start = VGA_MAP_MEM(hga_vram_base); hga_fix.smem_len = hga_vram_len; disp.var = hga_default_var; @@ -795,7 +795,7 @@ if (!options || !*options) return 0; - while (this_opt = strsep(&options, ",")) { + while ((this_opt = strsep(&options, ","))) { if (!strncmp(this_opt, "font:", 5)) strcpy(fb_info.fontname, this_opt+5); } diff -u --recursive --new-file v2.4.14/linux/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c --- v2.4.14/linux/drivers/video/imsttfb.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/video/imsttfb.c Fri Nov 9 13:41:42 2001 @@ -1950,7 +1950,7 @@ init_imstt(p); - pdev->driver_data = p; + pci_set_drvdata(pdev, p); return 0; } @@ -1958,7 +1958,7 @@ static void __devexit imsttfb_remove(struct pci_dev *pdev) { - struct fb_info_imstt *p = (struct fb_info_imstt *)pdev->driver_data; + struct fb_info_imstt *p = pci_get_drvdata(pdev); unregister_framebuffer(&p->info); iounmap(p->cmap_regs); diff -u --recursive --new-file v2.4.14/linux/drivers/video/matrox/i2c-matroxfb.c linux/drivers/video/matrox/i2c-matroxfb.c --- v2.4.14/linux/drivers/video/matrox/i2c-matroxfb.c Tue Oct 9 17:06:53 2001 +++ linux/drivers/video/matrox/i2c-matroxfb.c Fri Nov 9 14:07:41 2001 @@ -1,3 +1,15 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.51 2001/01/19 + * + * See matroxfb_base.c for contributors. + * + */ + #include "matroxfb_base.h" #include "matroxfb_maven.h" #include <linux/i2c.h> @@ -282,8 +294,8 @@ return NULL; matroxfb_DAC_lock_irqsave(flags); - matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0x00); - matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0xFF); + matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0xFF); + matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0x00); matroxfb_DAC_unlock_irqrestore(flags); memset(m2info, 0, sizeof(*m2info)); @@ -343,7 +355,7 @@ matroxfb_unregister_driver(&i2c_matroxfb); } -MODULE_AUTHOR("(c) 1999 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards"); module_init(i2c_matroxfb_init); diff -u --recursive --new-file v2.4.14/linux/drivers/video/matrox/matroxfb_DAC1064.c linux/drivers/video/matrox/matroxfb_DAC1064.c --- v2.4.14/linux/drivers/video/matrox/matroxfb_DAC1064.c Tue Oct 9 17:06:53 2001 +++ linux/drivers/video/matrox/matroxfb_DAC1064.c Fri Nov 9 14:07:41 2001 @@ -321,7 +321,8 @@ outDAC1064(PMINFO 0x20, 0x04); outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type)); if (ACCESS_FBINFO(devflags.g450dac)) { - outDAC1064(PMINFO M1064_X8B, 0xCC); /* only matrox know... */ + outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC); /* only matrox know... */ + outDAC1064(PMINFO M1064_XPWRCTRL, 0x1F); /* powerup everything */ outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]); } } diff -u --recursive --new-file v2.4.14/linux/drivers/video/matrox/matroxfb_DAC1064.h linux/drivers/video/matrox/matroxfb_DAC1064.h --- v2.4.14/linux/drivers/video/matrox/matroxfb_DAC1064.h Fri Dec 29 14:07:23 2000 +++ linux/drivers/video/matrox/matroxfb_DAC1064.h Fri Nov 9 14:07:41 2001 @@ -138,11 +138,13 @@ #define M1064_XTVO_DATA 0x88 #define M1064_XOUTPUTCONN 0x8A -#define M1064_X8B 0x8B +#define M1064_XSYNCCTRL 0x8B #define M1064_XPIXPLL2STAT 0x8C #define M1064_XPIXPLL2P 0x8D #define M1064_XPIXPLL2N 0x8E #define M1064_XPIXPLL2M 0x8F + +#define M1064_XPWRCTRL 0xA0 enum POS1064 { POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL, diff -u --recursive --new-file v2.4.14/linux/drivers/video/matrox/matroxfb_base.c linux/drivers/video/matrox/matroxfb_base.c --- v2.4.14/linux/drivers/video/matrox/matroxfb_base.c Tue Oct 23 22:48:52 2001 +++ linux/drivers/video/matrox/matroxfb_base.c Fri Nov 9 14:07:41 2001 @@ -988,8 +988,6 @@ #undef minfo } -static int matroxfb_switch(int con, struct fb_info *info); - static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank) { unsigned int sts1; @@ -1183,7 +1181,7 @@ fb_ioctl: matroxfb_ioctl, }; -static int matroxfb_switch(int con, struct fb_info *info) +int matroxfb_switch(int con, struct fb_info *info) { #define minfo ((struct matrox_fb_info*)info) struct fb_cmap* cmap; @@ -1414,11 +1412,11 @@ #define DEVF_VIDEO64BIT 0x0001 #define DEVF_SWAPS 0x0002 #define DEVF_SRCORG 0x0004 -/* #define DEVF_recycled 0x0008 */ +#define DEVF_BOTHDACS 0x0008 /* put CRTC1 on both outputs by default */ #define DEVF_CROSS4MB 0x0010 #define DEVF_TEXT4B 0x0020 #define DEVF_DDC_8_2 0x0040 -/* #define DEVF_recycled 0x0080 */ +#define DEVF_G550DAC 0x0080 #define DEVF_SUPPORT32MB 0x0100 #define DEVF_ANY_VXRES 0x0200 #define DEVF_TEXT16B 0x0400 @@ -1434,6 +1432,7 @@ #define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2) /* if you'll find how to drive DFP... */ #define DEVF_G450 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG) +#define DEVF_G550 (DEVF_G450 | DEVF_G550DAC | DEVF_BOTHDACS) static struct board { unsigned short vendor, device, rev, svid, sid; @@ -1477,13 +1476,13 @@ "Mystique 220 (PCI)"}, #endif #ifdef CONFIG_FB_MATROX_G100 - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 0xFF, PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_PCI, DEVF_G100, 230000, &vbG100, "MGA-G100 (PCI)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 0xFF, 0, 0, DEVF_G100, 230000, @@ -1561,24 +1560,30 @@ 230000, &vbG200, "G200 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0x80, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80, PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP, DEVF_G400, 360000, &vbG400, "Millennium G400 MAX (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0x80, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0x80, 0, 0, DEVF_G400, 300000, &vbG400, "G400 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, 0xFF, 0, 0, DEVF_G450, 500000, /* ??? vco goes up to 900MHz... */ &vbG400, - "G450 (AGP)"}, + "G450"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, 0xFF, + 0, 0, + DEVF_G550, + 500000, + &vbG400, + "G550"}, #endif {0, 0, 0xFF, 0, 0, @@ -1641,8 +1646,18 @@ if (dfp) ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_DFP; } + if (b->flags & DEVF_BOTHDACS) { +#ifdef CONFIG_FB_MATROX_G450 + ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY; + ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_SECONDARY; +#else + printk(KERN_INFO "Only digital output of G550 is now working (in analog mode). Enable G450 support in\n"); + printk(KERN_INFO "kernel configuration if you have analog monitor connected to G550 analog output.\n"); +#endif + } ACCESS_FBINFO(devflags.dfp_type) = dfp_type; ACCESS_FBINFO(devflags.g450dac) = b->flags & DEVF_G450DAC; + ACCESS_FBINFO(devflags.g550dac) = b->flags & DEVF_G550DAC; ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode); ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode); @@ -2060,7 +2075,7 @@ ACCESS_FBINFO(pcidev) = pdev; ACCESS_FBINFO(dead) = 0; ACCESS_FBINFO(usecount) = 0; - pdev->driver_data = MINFO; + pci_set_drvdata(pdev, MINFO); /* CMDLINE */ memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname))); /* DEVFLAGS */ @@ -2122,7 +2137,7 @@ static void pci_remove_matrox(struct pci_dev* pdev) { struct matrox_fb_info* minfo; - minfo = pdev->driver_data; + minfo = pci_get_drvdata(pdev); matroxfb_remove(PMINFO 1); } @@ -2140,7 +2155,7 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, #endif #ifdef CONFIG_FB_MATROX_G100 - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -2148,7 +2163,9 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, #endif {0, 0, @@ -2638,6 +2655,7 @@ module_exit(matrox_done); EXPORT_SYMBOL(matroxfb_register_driver); EXPORT_SYMBOL(matroxfb_unregister_driver); +EXPORT_SYMBOL(matroxfb_switch); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -u --recursive --new-file v2.4.14/linux/drivers/video/matrox/matroxfb_base.h linux/drivers/video/matrox/matroxfb_base.h --- v2.4.14/linux/drivers/video/matrox/matroxfb_base.h Tue Oct 9 17:06:53 2001 +++ linux/drivers/video/matrox/matroxfb_base.h Fri Nov 9 14:07:41 2001 @@ -146,21 +146,6 @@ #ifndef PCI_SS_VENDOR_ID_MATROX #define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX #endif -#ifndef PCI_DEVICE_ID_MATROX_G200_PCI -#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G200_AGP -#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G100 -#define PCI_DEVICE_ID_MATROX_G100 0x1000 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G100_AGP -#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001 -#endif -#ifndef PCI_DEVICE_ID_MATROX_G400_AGP -#define PCI_DEVICE_ID_MATROX_G400_AGP 0x0525 -#endif #ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP #define PCI_SS_ID_MATROX_GENERIC 0xFF00 @@ -533,6 +518,7 @@ /* 0 except for 6MB Millenium */ int memtype; int g450dac; + int g550dac; int dfp_type; } devflags; struct display_switch dispsw; diff -u --recursive --new-file v2.4.14/linux/drivers/video/matrox/matroxfb_crtc2.c linux/drivers/video/matrox/matroxfb_crtc2.c --- v2.4.14/linux/drivers/video/matrox/matroxfb_crtc2.c Fri May 25 09:54:50 2001 +++ linux/drivers/video/matrox/matroxfb_crtc2.c Fri Nov 9 14:07:41 2001 @@ -130,14 +130,31 @@ if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) tmp |= 0x00100000; /* connect CRTC2 to DAC */ } + if (mt->interlaced) { + tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */ + mt->VDisplay >>= 1; + mt->VSyncStart >>= 1; + mt->VSyncEnd >>= 1; + mt->VTotal >>= 1; + } mga_outl(0x3C10, tmp | 0x10000000); /* depth and so on... 0x10000000 is VIDRST polarity */ mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8)); mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8)); mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1)); mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1)); mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */ - mga_outl(0x3C28, pos); /* vmemory start */ - mga_outl(0x3C40, p->var.xres_virtual * (p->var.bits_per_pixel >> 3)); + { + u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3); + if (mt->interlaced) { + /* field #0 is smaller, so... */ + mga_outl(0x3C2C, pos); /* field #1 vmemory start */ + mga_outl(0x3C28, pos + linelen); /* field #0 vmemory start */ + linelen <<= 1; + } else { + mga_outl(0x3C28, pos); /* vmemory start */ + } + mga_outl(0x3C40, linelen); + } tmp = 0x0FFF0000; /* line compare */ if (mt->sync & FB_SYNC_HOR_HIGH_ACT) tmp |= 0x00000100; @@ -155,11 +172,20 @@ static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, struct fb_var_screeninfo* var) { unsigned int pos; + unsigned int linelen; + unsigned int pixelsize; #define minfo (m2info->primary_dev) - pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3; + pixelsize = var->bits_per_pixel >> 3; + linelen = var->xres_virtual * pixelsize; + pos = var->yoffset * linelen + var->xoffset * pixelsize; pos += m2info->video.offbase; - mga_outl(0x3C28, pos); + if (var->vmode & FB_VMODE_INTERLACED) { + mga_outl(0x3C2C, pos); + mga_outl(0x3C28, pos + linelen); + } else { + mga_outl(0x3C28, pos); + } #undef minfo } @@ -700,15 +726,13 @@ m2info->mmio.len = ACCESS_FBINFO(mmio.len); /* - * If we have two outputs, connect CRTC2 to it... + * If we have unused output, connect CRTC2 to it... */ - if (ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) { + if ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) && + !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) && + !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) { ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY; - ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_SECONDARY; - if (ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP) { - ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP; - ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_DFP; - } + ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP; } matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon); @@ -815,6 +839,7 @@ MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_DESCRIPTION("Matrox G400 CRTC2 driver"); +MODULE_LICENSE("GPL"); module_init(matroxfb_crtc2_init); module_exit(matroxfb_crtc2_exit); /* we do not have __setup() yet */ diff -u --recursive --new-file v2.4.14/linux/drivers/video/matrox/matroxfb_g450.c linux/drivers/video/matrox/matroxfb_g450.c --- v2.4.14/linux/drivers/video/matrox/matroxfb_g450.c Tue Jul 3 17:08:21 2001 +++ linux/drivers/video/matrox/matroxfb_g450.c Fri Nov 9 14:07:41 2001 @@ -1,3 +1,15 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.51 2001/01/19 + * + * See matroxfb_base.c for contributors. + * + */ + #include "matroxfb_g450.h" #include "matroxfb_misc.h" #include "matroxfb_DAC1064.h" @@ -31,36 +43,53 @@ 3 }; +static const struct matrox_pll_features g550_pll = { + 135000, + 27000, + 4, 127, + 0, 9, + 3 +}; + static void DAC1064_calcclock(unsigned int freq, unsigned int fmax, - unsigned int* in, unsigned int* feed, unsigned int* post) { + unsigned int* in, unsigned int* feed, unsigned int* post, + unsigned int timmings) { unsigned int fvco; unsigned int p; - fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); - /* 0 => 100 ... 275 MHz - 1 => 243 ... 367 MHz - 2 => 320 ... 475 MHz - 3 => 453 ... 556 MHz - 4 => 540 ... 594 MHz - 5 => 588 ... 621 MHz - 6 => 626 ... 637 MHz - 7 => 631 ... 642 MHz - - As you can see, never choose frequency > 621 MHz, there is unavailable gap... - Just to be sure, currently driver uses 110 ... 500 MHz range. - */ - if (fvco <= 260000) - ; - else if (fvco <= 350000) - p |= 0x08; - else if (fvco <= 460000) - p |= 0x10; - else if (fvco <= 550000) - p |= 0x18; - else if (fvco <= 590000) - p |= 0x20; - else - p |= 0x28; + switch (timmings) { + default: + fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); + /* 0 => 100 ... 275 MHz + 1 => 243 ... 367 MHz + 2 => 320 ... 475 MHz + 3 => 453 ... 556 MHz + 4 => 540 ... 594 MHz + 5 => 588 ... 621 MHz + 6 => 626 ... 637 MHz + 7 => 631 ... 642 MHz + + As you can see, never choose frequency > 621 MHz, there is unavailable gap... + Just to be sure, currently driver uses 110 ... 500 MHz range. + */ + if (fvco <= 260000) + ; + else if (fvco <= 350000) + p |= 0x08; + else if (fvco <= 460000) + p |= 0x10; + else if (fvco <= 550000) + p |= 0x18; + else if (fvco <= 590000) + p |= 0x20; + else + p |= 0x28; + break; + case 1: + fvco = matroxfb_PLL_calcclock(&g550_pll, freq, fmax, in, feed, &p); + /* p |= 0x00; */ + break; + } *post = p; return; } @@ -70,7 +99,7 @@ struct mavenregs* m) { unsigned int a, b, c; - DAC1064_calcclock(mt->pixclock, 500000, &a, &b, &c); + DAC1064_calcclock(mt->pixclock, 300000, &a, &b, &c, m2info->timmings); m->regs[0x80] = a; m->regs[0x81] = b; m->regs[0x82] = c; @@ -139,6 +168,7 @@ ACCESS_FBINFO(altout.output) = &matroxfb_g450_altout; up_write(&ACCESS_FBINFO(altout.lock)); ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY; + matroxfb_switch(ACCESS_FBINFO(currcon), (struct fb_info*)MINFO); return 0; } @@ -171,6 +201,11 @@ } memset(m2info, 0, sizeof(*m2info)); m2info->primary_dev = MINFO; + if (ACCESS_FBINFO(devflags.g550dac)) { + m2info->timmings = 1; + } else { + m2info->timmings = 0; + } if (matroxfb_g450_connect(m2info)) { kfree(m2info); printk(KERN_ERR "matroxfb_g450: G450 DAC failed to initialize\n"); @@ -198,7 +233,8 @@ matroxfb_unregister_driver(&g450); } -MODULE_AUTHOR("(c) 2000 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_AUTHOR("(c) 2000-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_DESCRIPTION("Matrox G450 secondary output driver"); +MODULE_LICENSE("GPL"); module_init(matroxfb_g450_init); module_exit(matroxfb_g450_exit); diff -u --recursive --new-file v2.4.14/linux/drivers/video/matrox/matroxfb_g450.h linux/drivers/video/matrox/matroxfb_g450.h --- v2.4.14/linux/drivers/video/matrox/matroxfb_g450.h Fri Dec 29 14:07:23 2000 +++ linux/drivers/video/matrox/matroxfb_g450.h Fri Nov 9 14:07:41 2001 @@ -6,6 +6,7 @@ struct matroxfb_g450_info { struct matrox_fb_info* primary_dev; + unsigned int timmings; }; #endif /* __MATROXFB_MAVEN_H__ */ diff -u --recursive --new-file v2.4.14/linux/drivers/video/matrox/matroxfb_maven.c linux/drivers/video/matrox/matroxfb_maven.c --- v2.4.14/linux/drivers/video/matrox/matroxfb_maven.c Sun Jul 9 22:16:28 2000 +++ linux/drivers/video/matrox/matroxfb_maven.c Fri Nov 9 14:07:41 2001 @@ -1,3 +1,15 @@ +/* + * + * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. + * + * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz> + * + * Version: 1.51 2001/01/19 + * + * See matroxfb_base.c for contributors. + * + */ + #include "matroxfb_maven.h" #include "matroxfb_misc.h" #include "matroxfb_DAC1064.h" @@ -1030,8 +1042,9 @@ i2c_del_driver(&maven_driver); } -MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver"); +MODULE_LICENSE("GPL"); module_init(matroxfb_maven_init); module_exit(matroxfb_maven_exit); /* we do not have __setup() yet */ diff -u --recursive --new-file v2.4.14/linux/drivers/video/matrox/matroxfb_misc.c linux/drivers/video/matrox/matroxfb_misc.c --- v2.4.14/linux/drivers/video/matrox/matroxfb_misc.c Tue Oct 9 17:06:53 2001 +++ linux/drivers/video/matrox/matroxfb_misc.c Fri Nov 9 14:07:41 2001 @@ -657,3 +657,7 @@ EXPORT_SYMBOL(matroxfb_fastfont_init); /* DAC1064, Ti3026 */ EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */ EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */ + +MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>"); +MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards"); +MODULE_LICENSE("GPL"); diff -u --recursive --new-file v2.4.14/linux/drivers/video/radeonfb.c linux/drivers/video/radeonfb.c --- v2.4.14/linux/drivers/video/radeonfb.c Mon Nov 5 15:55:33 2001 +++ linux/drivers/video/radeonfb.c Fri Nov 9 13:41:42 2001 @@ -889,7 +889,7 @@ rinfo->palette[i].blue = default_blu[j]; } - pdev->driver_data = rinfo; + pci_set_drvdata(pdev, rinfo); if (register_framebuffer ((struct fb_info *) rinfo) < 0) { printk ("radeonfb: could not register framebuffer\n"); @@ -930,7 +930,7 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev) { - struct radeonfb_info *rinfo = pdev->driver_data; + struct radeonfb_info *rinfo = pci_get_drvdata(pdev); if (!rinfo) return; diff -u --recursive --new-file v2.4.14/linux/drivers/video/sgivwfb.c linux/drivers/video/sgivwfb.c --- v2.4.14/linux/drivers/video/sgivwfb.c Tue Oct 23 22:48:53 2001 +++ linux/drivers/video/sgivwfb.c Fri Nov 9 14:07:41 2001 @@ -660,6 +660,7 @@ /* XXX FIXME - should try to pick best refresh rate */ /* for now, pick closest dot-clock within 3MHz*/ +#error "Floating point not allowed in kernel" req_dot = (int)((1.0e3/1.0e6) / (1.0e-12 * (float)var->pixclock)); printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n", var->pixclock, req_dot); @@ -954,6 +955,8 @@ } #ifdef MODULE +MODULE_LICENSE("GPL"); + int init_module(void) { return sgivwfb_init(); diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/300vtbl.h linux/drivers/video/sis/300vtbl.h --- v2.4.14/linux/drivers/video/sis/300vtbl.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/300vtbl.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,1522 @@ +typedef struct _SiS300_StStruct { + UCHAR St_ModeID; + USHORT St_ModeFlag; + UCHAR St_StTableIndex; + UCHAR St_CRT2CRTC; + UCHAR St_ResInfo; + UCHAR VB_StTVFlickerIndex; + UCHAR VB_StTVEdgeIndex; + UCHAR VB_StTVYFilterIndex; +} SiS300_StStruct; + +SiS300_StStruct SiS300_SModeIDTable[] = +{ + {0x01, 0x9208, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x1210, 0x14, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0x01, 0x1010, 0x17, 0x02, 0x02, 0x00, 0x00, 0x00}, + {0x03, 0x8208, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x03, 0x0210, 0x16, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x00, 0x00}, + {0x05, 0x9209, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x06, 0x8209, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x07, 0x0000, 0x07, 0x03, 0x03, 0x00, 0x00, 0x00}, + {0x07, 0x0000, 0x19, 0x02, 0x02, 0x00, 0x00, 0x00}, + {0x0d, 0x920a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x0e, 0x820a, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x0f, 0x0202, 0x11, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0x10, 0x0212, 0x12, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0x11, 0x0212, 0x1a, 0x04, 0x04, 0x00, 0x00, 0x00}, + {0x12, 0x0212, 0x1b, 0x04, 0x04, 0x00, 0x00, 0x00}, + {0x13, 0x021b, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x12, 0x0210, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x12, 0x0210, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00}, + {0xff, 0, 0, 0, 0, 0, 0, 0} +}; + +typedef struct _SiS300_StandTableStruct { + UCHAR CRT_COLS; + UCHAR ROWS; + UCHAR CHAR_HEIGHT; + USHORT CRT_LEN; + UCHAR SR[4]; + UCHAR MISC; + UCHAR CRTC[0x19]; + UCHAR ATTR[0x14]; + UCHAR GRC[9]; +} SiS300_StandTableStruct; + +SiS300_StandTableStruct SiS300_StandTable[] = { + {0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff}}, + {0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff}}, + {0x50, 0x18, 0x08, 0x4000, + {0x01, 0x01, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2, + 0xff}, + {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x01, 0x00, 0x01, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0xff}}, + {0x50, 0x18, 0x0e, 0x1000, + {0x00, 0x03, 0x00, 0x03}, + 0xa6, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff}}, +/* MDA_DAC*/ + {0x00, 0x00, 0x00, 0x0000, + {0x00, 0x00, 0x00, 0x15}, + 0x15, + {0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, + 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15}, + {0x15, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f}}, +/* CGA_DAC*/ + {0x00, 0x10, 0x04, 0x0114, + {0x11, 0x09, 0x15, 0x00}, + 0x10, + {0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, + 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x2a, 0x3a, + 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x10, + 0x04}, + {0x14, 0x01, 0x11, 0x09, 0x15, 0x00, 0x10, 0x04, + 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, 0x2e, + 0x3e, 0x2b, 0x3b, 0x2f}, + {0x3f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, + 0x3f}}, +/* EGA_DAC*/ + {0x00, 0x10, 0x04, 0x0114, + {0x11, 0x05, 0x15, 0x20}, + 0x30, + {0x24, 0x34, 0x21, 0x31, 0x25, 0x35, 0x08, 0x18, + 0x0c, 0x1c, 0x09, 0x19, 0x0d, 0x1d, 0x28, 0x38, + 0x2c, 0x3c, 0x29, 0x39, 0x2d, 0x3d, 0x02, 0x12, + 0x06}, + {0x16, 0x03, 0x13, 0x07, 0x17, 0x22, 0x32, 0x26, + 0x36, 0x23, 0x33, 0x27, 0x37, 0x0a, 0x1a, 0x0e, + 0x1e, 0x0b, 0x1b, 0x0f}, + {0x1f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, + 0x3f}}, +/* VGA_DAC*/ + {0x00, 0x10, 0x04, 0x0114, + {0x11, 0x09, 0x15, 0x2a}, + 0x3a, + {0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x05, + 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x18, 0x1c, 0x20, + 0x24, 0x28, 0x2d, 0x32, 0x38, 0x3f, 0x00, 0x10, + 0x1f}, + {0x2f, 0x3f, 0x1f, 0x27, 0x2f, 0x37, 0x3f, 0x2d, + 0x31, 0x36, 0x3a, 0x3f, 0x00, 0x07, 0x0e, 0x15, + 0x1c, 0x0e, 0x11, 0x15}, + {0x18, 0x1c, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x00, + 0x04}}, + {0x08, 0x0c, 0x10, 0x0a08, + {0x0c, 0x0e, 0x10, 0x0b}, + 0x0c, + {0x0d, 0x0f, 0x10, 0x10, 0x01, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, + 0x04, 0x04, 0x01, 0x00, 0x05, 0x02, 0x05, 0x00, + 0x06}, + {0x01, 0x06, 0x05, 0x06, 0x00, 0x08, 0x01, 0x08, + 0x00, 0x07, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00}}, + {0x28, 0x18, 0x08, 0x2000, + {0x09, 0x0f, 0x00, 0x06}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff}}, + {0x50, 0x18, 0x08, 0x4000, + {0x01, 0x0f, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff}}, + {0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff}}, + {0x4a, 0x36, 0x00, 0x00c0, + {0x00, 0x00, 0x00, 0x00}, + 0x00, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3a, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1a, 0x00, 0x57, 0x39, 0x00, 0xc0, + 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00}}, + {0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa2, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x0b, 0x00, 0x05, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, + 0xff}}, + {0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff}}, + {0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x28, 0x18, 0x10, 0x0800, + {0x08, 0x03, 0x00, 0x02}, + 0x67, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff}}, + {0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x66, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff}}, + {0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3, + 0xff}, + {0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, + 0xff}}, + {0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff}}, + {0x28, 0x18, 0x08, 0x2000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x41, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff}} +}; + +typedef struct _SiS300_ExtStruct { + UCHAR Ext_ModeID; + USHORT Ext_ModeFlag; + USHORT Ext_ModeInfo; + USHORT Ext_Point; + USHORT Ext_VESAID; + UCHAR Ext_VESAMEMSize; + UCHAR Ext_RESINFO; + UCHAR VB_ExtTVFlickerIndex; + UCHAR VB_ExtTVEdgeIndex; + UCHAR VB_ExtTVYFilterIndex; + UCHAR REFindex; +} SiS300_ExtStruct; +SiS300_ExtStruct SiS300_EModeIDTable[] = { + {0x6a, 0x2212, 0x47, 0x3563, 0x0102, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x2e, 0x0a1b, 0x36, 0x3539, 0x0101, 0x08, 0x06, 0x00, 0x00, 0x00, 0x08}, + {0x2f, 0x021b, 0x35, 0x3532, 0x0100, 0x08, 0x05, 0x00, 0x00, 0x00, 0x10}, + {0x30, 0x2a1b, 0x47, 0x3563, 0x0103, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x31, 0x0a1b, 0xad, 0x3630, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x11}, + {0x32, 0x2a1b, 0xae, 0x3637, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x00, 0x12}, + {0x33, 0x0a1d, 0xad, 0x3630, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x11}, + {0x34, 0x2a1d, 0xae, 0x3637, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x00, 0x12}, + {0x35, 0x0a1f, 0xad, 0x3630, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x11}, + {0x36, 0x2a1f, 0xae, 0x3637, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x00, 0x12}, + {0x37, 0x0212, 0x58, 0x358d, 0x0104, 0x08, 0x08, 0x00, 0x00, 0x00, 0x13}, + {0x38, 0x0a1b, 0x58, 0x358d, 0x0105, 0x08, 0x08, 0x00, 0x00, 0x00, 0x13}, + {0x3a, 0x0e3b, 0x69, 0x35be, 0x0107, 0x08, 0x09, 0x00, 0x00, 0x00, 0x1a}, + {0x3c, 0x063b, 0x7a, 0x35d4, 0x0130, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x1e}, + {0x3d, 0x067d, 0x7a, 0x35d4, 0x0131, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x1e}, + {0x40, 0x921c, 0x00, 0x3516, 0x010d, 0x08, 0x00, 0x00, 0x00, 0x00, 0x23}, + {0x41, 0x921d, 0x00, 0x3516, 0x010e, 0x08, 0x00, 0x00, 0x00, 0x00, 0x23}, + {0x43, 0x0a1c, 0x36, 0x3539, 0x0110, 0x08, 0x06, 0x00, 0x00, 0x00, 0x08}, + {0x44, 0x0a1d, 0x36, 0x3539, 0x0111, 0x08, 0x06, 0x00, 0x00, 0x00, 0x08}, + {0x46, 0x2a1c, 0x47, 0x3563, 0x0113, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x47, 0x2a1d, 0x47, 0x3563, 0x0114, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x49, 0x0a3c, 0x58, 0x358d, 0x0116, 0x08, 0x08, 0x00, 0x00, 0x00, 0x13}, + {0x4a, 0x0a3d, 0x58, 0x358d, 0x0117, 0x08, 0x08, 0x00, 0x00, 0x00, 0x13}, + {0x4c, 0x0e7c, 0x69, 0x35be, 0x0119, 0x08, 0x09, 0x00, 0x00, 0x00, 0x1a}, + {0x4d, 0x0e7d, 0x69, 0x35be, 0x011a, 0x08, 0x09, 0x00, 0x00, 0x00, 0x1a}, + {0x50, 0x921b, 0x01, 0x351d, 0x0132, 0x08, 0x01, 0x00, 0x00, 0x00, 0x24}, + {0x51, 0x921b, 0x13, 0x3524, 0x0133, 0x08, 0x03, 0x00, 0x00, 0x00, 0x25}, + {0x52, 0x921b, 0x24, 0x352b, 0x0134, 0x08, 0x04, 0x00, 0x00, 0x00, 0x26}, + {0x56, 0x921d, 0x01, 0x351d, 0x0135, 0x08, 0x01, 0x00, 0x00, 0x00, 0x24}, + {0x57, 0x921d, 0x13, 0x3524, 0x0136, 0x08, 0x03, 0x00, 0x00, 0x00, 0x25}, + {0x58, 0x921d, 0x24, 0x352b, 0x0137, 0x08, 0x04, 0x00, 0x00, 0x00, 0x26}, + {0x59, 0x921b, 0x00, 0x3516, 0x0138, 0x08, 0x00, 0x00, 0x00, 0x00, 0x23}, + {0x5d, 0x021d, 0x35, 0x3532, 0x0139, 0x08, 0x05, 0x00, 0x00, 0x00, 0x10}, + {0x62, 0x0a3f, 0x36, 0x3539, 0x013a, 0x08, 0x06, 0x00, 0x00, 0x00, 0x08}, + {0x63, 0x2a3f, 0x47, 0x3563, 0x013b, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00}, + {0x64, 0x0a7f, 0x58, 0x358d, 0x013c, 0x08, 0x08, 0x00, 0x00, 0x00, 0x13}, + {0x65, 0x0eff, 0x69, 0x35be, 0x013d, 0x08, 0x09, 0x00, 0x00, 0x00, 0x1a}, + {0x66, 0x06ff, 0x7a, 0x35d4, 0x013e, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x1e}, + {0x68, 0x067b, 0x8b, 0x35ef, 0x013f, 0x08, 0x0b, 0x00, 0x00, 0x00, 0x27}, + {0x69, 0x06fd, 0x8b, 0x35ef, 0x0140, 0x08, 0x0b, 0x00, 0x00, 0x00, 0x27}, + {0x6b, 0x07ff, 0x8b, 0x35ef, 0x0000, 0x10, 0x0b, 0x00, 0x00, 0x00, 0x27}, + {0x6c, 0x067b, 0x9c, 0x35f6, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x28}, + {0x6d, 0x06fd, 0x9c, 0x35f6, 0x0000, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x28}, + {0x6e, 0x0e3b, 0x6f, 0x35b2, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x00, 0x29}, + {0x6f, 0x0e7d, 0x6f, 0x35b2, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x00, 0x29}, + {0x7b, 0x0eff, 0x6f, 0x35b2, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x00, 0x29}, + {0x7c, 0x221b, 0xb3, 0x363e, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x2b}, + {0x7d, 0x221d, 0xb3, 0x363e, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x2b}, + {0x7e, 0x223f, 0xb3, 0x363e, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x2b}, + {0xff, 0x0000, 0x00, 0x0000, 0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +typedef struct _SiS300_Ext2Struct { + USHORT Ext_InfoFlag; + UCHAR Ext_CRT1CRTC; + UCHAR Ext_CRTVCLK; + UCHAR Ext_CRT2CRTC; + UCHAR ModeID; + USHORT XRes; + USHORT YRes; + USHORT ROM_OFFSET; +} SiS300_Ext2Struct; +SiS300_Ext2Struct SiS300_RefIndex[] = { + {0x085f, 0x0d, 0x03, 0x05, 0x6a, 800, 600, 0x3563}, + {0x0467, 0x0e, 0x44, 0x05, 0x6a, 800, 600, 0x3568}, + {0x0067, 0x4f, 0x07, 0x48, 0x6a, 800, 600, 0x356d}, + {0x0067, 0x10, 0x06, 0x8b, 0x6a, 800, 600, 0x3572}, + {0x0147, 0x11, 0x08, 0x00, 0x6a, 800, 600, 0x3577}, + {0x0147, 0x12, 0x0c, 0x00, 0x6a, 800, 600, 0x357c}, + {0x0047, 0x51, 0x4e, 0x00, 0x6a, 800, 600, 0x3581}, + {0x0047, 0x11, 0x13, 0x00, 0x6a, 800, 600, 0x3586}, + {0xc85f, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x3539}, + {0xc067, 0x06, 0x02, 0x04, 0x2e, 640, 480, 0x353e}, + {0xc067, 0x07, 0x02, 0x47, 0x2e, 640, 480, 0x3543}, + {0xc067, 0x08, 0x03, 0x8a, 0x2e, 640, 480, 0x3548}, + {0xc047, 0x09, 0x05, 0x00, 0x2e, 640, 480, 0x354d}, + {0xc047, 0x0a, 0x08, 0x00, 0x2e, 640, 480, 0x3552}, + {0xc047, 0x0b, 0x0a, 0x00, 0x2e, 640, 480, 0x3557}, + {0xc047, 0x0c, 0x10, 0x00, 0x2e, 640, 480, 0x355c}, + {0x487f, 0x04, 0x00, 0x00, 0x2f, 640, 400, 0x3532}, + {0xc00f, 0x31, 0x01, 0x06, 0x31, 2048, 1536, 0x3630}, + {0x000f, 0x32, 0x03, 0x06, 0x32, 720, 480, 0x3637}, + {0x0187, 0x15, 0x05, 0x00, 0x37, 1024, 768, 0x358d}, + {0xc877, 0x16, 0x09, 0x06, 0x37, 1024, 768, 0x3592}, + {0xc067, 0x97, 0x0b, 0x49, 0x37, 1024, 768, 0x3597}, + {0x0267, 0x18, 0x0d, 0x00, 0x37, 1024, 768, 0x359c}, + {0x0047, 0x59, 0x11, 0x8c, 0x37, 1024, 768, 0x35a1}, + {0x0047, 0x1a, 0x52, 0x00, 0x37, 1024, 768, 0x35a6}, + {0x0047, 0x5b, 0x16, 0x00, 0x37, 1024, 768, 0x35ab}, + {0x0387, 0x5c, 0x4d, 0x00, 0x3a, 1280, 1024, 0x35be}, + {0x0077, 0x1d, 0x14, 0x07, 0x3a, 1280, 1024, 0x35c3}, + {0x0047, 0x1e, 0x17, 0x00, 0x3a, 1280, 1024, 0x35c8}, + {0x0007, 0x1f, 0x98, 0x00, 0x3a, 1280, 1024, 0x35cd}, + {0x0007, 0x60, 0x59, 0x00, 0x3c, 1600, 1200, 0x35d4}, + {0x0007, 0x21, 0x5a, 0x00, 0x3c, 1600, 1200, 0x35d9}, + {0x0007, 0x22, 0x1b, 0x00, 0x3c, 1600, 1200, 0x35de}, + {0x0007, 0x63, 0x1d, 0x00, 0x3c, 1600, 1200, 0x35e3}, + {0x0007, 0x24, 0x1e, 0x00, 0x3c, 1600, 1200, 0x35e8}, + {0x407f, 0x00, 0x00, 0x00, 0x40, 320, 200, 0x3516}, + {0xc07f, 0x01, 0x00, 0x04, 0x50, 320, 240, 0x351d}, + {0x0077, 0x02, 0x04, 0x05, 0x51, 400, 300, 0x3524}, + {0xc077, 0x03, 0x09, 0x06, 0x52, 512, 384, 0x352b}, + {0x8207, 0x25, 0x1f, 0x00, 0x68, 1920, 1440, 0x35ef}, + {0x0007, 0x26, 0x20, 0x00, 0x6c, 2048, 1536, 0x35f6}, + {0x0027, 0x27, 0x14, 0x08, 0x6e, 720, 576, 0x35b2}, + {0x0027, 0x27, 0x14, 0x08, 0x6e, 720, 576, 0x35b7}, + {0x00df, 0x33, 0x28, 0x00, 0x7c, 1280, 960, 0x363e}, + {0xc05f, 0x34, 0x28, 0x00, 0x7c, 1280, 960, 0x3643}, + {0xffff, 0, 0, 0, 0, 0, 0, 0} +}; + +/*add for 300 oem util*/ +typedef struct _SiS_VBModeIDTableStruct { + UCHAR ModeID; + UCHAR VB_TVDelayIndex; + UCHAR VB_TVFlickerIndex; + UCHAR VB_TVPhaseIndex; + UCHAR VB_TVYFilterIndex; + UCHAR VB_LCDDelayIndex; + UCHAR _VB_LCDHIndex; + UCHAR _VB_LCDVIndex; +} SiS_VBModeIDTableStruct; +SiS_VBModeIDTableStruct SiS300_VBModeIDTable[] = { + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02}, + {0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00}, + {0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x01}, + {0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x02}, + {0x05, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00}, + {0x06, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x00}, + {0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x01}, + {0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x02}, + {0x0d, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00}, + {0x0e, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x00}, + {0x0f, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x01}, + {0x10, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x01}, + {0x11, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x03}, + {0x12, 0x00, 0x00, 0x01, 0x05, 0x00, 0x02, 0x03}, + {0x13, 0x00, 0x00, 0x01, 0x04, 0x00, 0x04, 0x00}, + {0x6a, 0x00, 0x00, 0x01, 0x07, 0x00, 0x08, 0x0a}, + {0x2e, 0x00, 0x00, 0x01, 0x05, 0x00, 0x06, 0x08}, + {0x2f, 0x00, 0x00, 0x01, 0x05, 0x00, 0x06, 0x06}, + {0x30, 0x00, 0x00, 0x01, 0x07, 0x00, 0x08, 0x0a}, + {0x31, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00}, + {0x32, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00}, + {0x37, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0c}, + {0x38, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0c}, + {0x3a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x40, 0x00, 0x00, 0x01, 0x04, 0x00, 0x05, 0x05}, + {0x41, 0x00, 0x00, 0x01, 0x04, 0x00, 0x05, 0x05}, + {0x43, 0x00, 0x00, 0x01, 0x05, 0x00, 0x06, 0x08}, + {0x44, 0x00, 0x00, 0x01, 0x05, 0x00, 0x06, 0x08}, + {0x46, 0x00, 0x00, 0x01, 0x07, 0x00, 0x08, 0x0a}, + {0x47, 0x00, 0x00, 0x01, 0x07, 0x00, 0x08, 0x0a}, + {0x49, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0c}, + {0x4a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0c}, + {0x4c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x4d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x50, 0x00, 0x00, 0x01, 0x04, 0x00, 0x05, 0x07}, + {0x51, 0x00, 0x00, 0x01, 0x07, 0x00, 0x07, 0x09}, + {0x52, 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0x0b}, + {0x56, 0x00, 0x00, 0x01, 0x04, 0x00, 0x05, 0x07}, + {0x57, 0x00, 0x00, 0x01, 0x07, 0x00, 0x07, 0x09}, + {0x58, 0x00, 0x00, 0x01, 0x00, 0x00, 0x09, 0x0b}, + {0x59, 0x00, 0x00, 0x01, 0x04, 0x00, 0x05, 0x05}, + {0x5d, 0x00, 0x00, 0x01, 0x07, 0x00, 0x06, 0x06}, + {0x62, 0x00, 0x00, 0x01, 0x05, 0x00, 0x06, 0x08}, + {0x63, 0x00, 0x00, 0x01, 0x07, 0x00, 0x08, 0x0a}, + {0x64, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x0c}, + {0x65, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x6e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x6f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d}, + {0x7b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0d} +}; +/*end*/ + +typedef struct _SiS300_CRT1TableStruct { + UCHAR CR[17]; +} SiS300_CRT1TableStruct; +SiS300_CRT1TableStruct SiS300_CRT1Table[] = { + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x04, + 0x00}}, + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x04, + 0x00}}, + {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}}, + {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}}, + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}}, + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, + {{0x63, 0x4f, 0x50, 0x86, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8b, 0xdf, 0xe7, 0xff, 0x10, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}}, + {{0x66, 0x4f, 0x4f, 0x86, 0x56, 0x9e, 0x03, 0x3e, + 0xe4, 0x87, 0xdf, 0xdf, 0x04, 0x00, 0x00, 0x01, + 0x00}}, + {{0x6c, 0x4f, 0x4f, 0x83, 0x59, 0x9e, 0x00, 0x3e, + 0xe5, 0x8d, 0xdf, 0xdf, 0x01, 0x00, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9d, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01, + 0x00}}, + {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xe5, 0xe5, 0xfc, 0x00, 0x00, 0x01, + 0x00}}, + {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}}, + {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}}, + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}}, + {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, + {{0x8c, 0x63, 0x63, 0x87, 0x72, 0x16, 0x7e, 0xf0, + 0x59, 0x8d, 0x57, 0x57, 0x7f, 0x00, 0x00, 0x06, + 0x01}}, + {{0x7e, 0x63, 0x63, 0x82, 0x6c, 0x14, 0x75, 0xe0, + 0x58, 0x0b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, + {{0x7e, 0x63, 0x63, 0x82, 0x6c, 0x14, 0x75, 0xe0, + 0x58, 0x0b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, + {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}}, + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, + {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, + {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}}, + {{0x9f, 0x7f, 0x7f, 0x83, 0x83, 0x93, 0x1e, 0xf5, + 0x00, 0x84, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, + {{0xa2, 0x7f, 0x7f, 0x86, 0x84, 0x94, 0x37, 0xf5, + 0x0b, 0x82, 0xff, 0xff, 0x38, 0x10, 0x00, 0x02, + 0x01}}, + {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}}, + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}}, + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, + {{0x3f, 0xef, 0xef, 0x83, 0xfd, 0x1a, 0xda, 0x1f, + 0xa0, 0x84, 0x9f, 0x9f, 0xdb, 0x1f, 0x01, 0x01, + 0x00}}, + {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}}, + {{0xdc, 0x9f, 0x9f, 0x00, 0xab, 0x19, 0xe6, 0xef, + 0xc0, 0xc3, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}}, + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}}, + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}}, + {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}}, + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}}, + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, + {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x15, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}}, + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}}, + {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, + {{0x7b, 0x59, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x3f, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, + {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15, + 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02, + 0x00}}, + {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e, + 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02, + 0x00}} +}; + +typedef struct _SiS300_MCLKDataStruct { + UCHAR SR28, SR29, SR2A; + USHORT CLOCK; +} SiS300_MCLKDataStruct; +SiS300_MCLKDataStruct SiS300_MCLKData[] = { + {0x5a, 0x64, 0x80, 66}, + {0xb3, 0x45, 0x80, 83}, + {0x37, 0x61, 0x80, 100}, + {0x37, 0x22, 0x80, 133}, + {0x37, 0x61, 0x80, 100}, + {0x37, 0x61, 0x80, 100}, + {0x37, 0x61, 0x80, 100}, + {0x37, 0x61, 0x80, 100} +}; + +typedef struct _SiS300_ECLKDataStruct { + UCHAR SR2E, SR2F, SR30; + USHORT CLOCK; +} SiS300_ECLKDataStruct; +SiS300_ECLKDataStruct SiS300_ECLKData[] = { + {0x54, 0x43, 0x80, 100}, + {0x53, 0x43, 0x80, 100}, + {0x55, 0x43, 0x80, 100}, + {0x52, 0x43, 0x80, 100}, + {0x3f, 0x42, 0x80, 100}, + {0x54, 0x43, 0x80, 100}, + {0x54, 0x43, 0x80, 100}, + {0x54, 0x43, 0x80, 100} +}; + +typedef struct _SiS300_VCLKDataStruct { + UCHAR SR2B, SR2C; + USHORT CLOCK; +} SiS300_VCLKDataStruct; +SiS300_VCLKDataStruct SiS300_VCLKData[] = { + {0x1b, 0xe1, 25}, + {0x4e, 0xe4, 28}, + {0x57, 0xe4, 32}, + {0xc3, 0xc8, 36}, + {0x42, 0xc3, 40}, + {0x5d, 0xc4, 45}, + {0x52, 0x65, 50}, + {0x53, 0x65, 50}, + {0x6d, 0x66, 56}, + {0x5a, 0x64, 65}, + {0x46, 0x44, 68}, + {0x3e, 0x43, 75}, + {0x6d, 0x46, 76}, + {0x41, 0x43, 79}, + {0x31, 0x42, 79}, + {0x46, 0x25, 85}, + {0x78, 0x29, 87}, + {0x62, 0x44, 95}, + {0x2b, 0x22, 105}, + {0x49, 0x24, 106}, + {0xc3, 0x28, 108}, + {0x3c, 0x23, 109}, + {0xf7, 0x2c, 132}, + {0xd4, 0x28, 136}, + {0x41, 0x05, 158}, + {0x43, 0x05, 162}, + {0xe1, 0x0f, 175}, + {0xfc, 0x12, 189}, + {0xde, 0x26, 194}, + {0x54, 0x05, 203}, + {0x3f, 0x03, 230}, + {0x30, 0x02, 234}, + {0x24, 0x01, 266}, + {0x52, 0x2a, 54}, + {0x52, 0x6a, 27}, + {0x62, 0x24, 70}, + {0x62, 0x64, 70}, + {0xa8, 0x4c, 30}, + {0x20, 0x26, 33}, + {0x31, 0xc2, 39}, + {0xbf, 0xc8, 35}, + {0x60, 0x36, 30}, + {0x40, 0x4a, 28}, + {0x9f, 0x46, 44}, + {0x97, 0x2c, 26}, + {0x44, 0xe4, 25}, + {0x7e, 0x32, 47}, + {0x8a, 0x24, 31}, + {0x97, 0x2c, 26}, + {0xce, 0x3c, 39}, + {0x52, 0x4a, 36}, + {0x34, 0x61, 95}, + {0x78, 0x27, 108}, + {0xff, 0x1b, 6625} +}; + +UCHAR SiS300_ScreenOffset[] = + { 0x14, 0x19, 0x20, 0x28, 0x32, 0x40, 0x50, 0x64, 0x78, 0x80, 0x2d, 0x35, + 0xff }; + +typedef struct _SiS300_StResInfoStruct { + USHORT HTotal; + USHORT VTotal; +} SiS300_StResInfoStruct; +SiS300_StResInfoStruct SiS300_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} +}; + +typedef struct _SiS300_ModeResInfoStruct { + USHORT HTotal; + USHORT VTotal; + UCHAR XChar; + UCHAR YChar; +} SiS300_ModeResInfoStruct; +SiS300_ModeResInfoStruct SiS300_ModeResInfo[] = { + {320, 200, 8, 8}, + {320, 240, 8, 8}, + {320, 400, 8, 8}, + {400, 300, 8, 8}, + {512, 384, 8, 8}, + {640, 400, 8, 16}, + {640, 480, 8, 16}, + {800, 600, 8, 16}, + {1024, 768, 8, 16}, + {1280, 1024, 8, 16}, + {1600, 1200, 8, 16}, + {1920, 1440, 8, 16}, + {720, 480, 8, 16}, + {720, 576, 8, 16}, + {1280, 960, 8, 16} +}; + +UCHAR SiS300_OutputSelect = 0x40; +UCHAR SiS300_SoftSetting = 30; +UCHAR SiS300_SR07 = 0x10; +UCHAR SiS300_SR15[8][4] = { + {0x1, 0x9, 0xa3, 0x0}, + {0x43, 0x43, 0x43, 0x0}, + {0x1e, 0x1e, 0x1e, 0x0}, + {0x2a, 0x2a, 0x2a, 0x0}, + {0x6, 0x6, 0x6, 0x0}, + {0x0, 0x0, 0x0, 0x0}, + {0x0, 0x0, 0x0, 0x0}, + {0x0, 0x0, 0x0, 0x0} +}; +UCHAR SiS300_SR1F = 0x0; +UCHAR SiS300_SR21 = 0x16; +UCHAR SiS300_SR22 = 0xb2; +UCHAR SiS300_SR23 = 0xf6; +UCHAR SiS300_SR24 = 0xd; +UCHAR SiS300_SR25[] = { 0x0, 0x0 }; +UCHAR SiS300_SR31 = 0x0; +UCHAR SiS300_SR32 = 0x11; +UCHAR SiS300_SR33 = 0x0; +UCHAR SiS300_CRT2Data_1_2 = 0x40; +UCHAR SiS300_CRT2Data_4_D = 0x0; +UCHAR SiS300_CRT2Data_4_E = 0x0; +UCHAR SiS300_CRT2Data_4_10 = 0x80; +USHORT SiS300_RGBSenseData = 0xd1; +USHORT SiS300_VideoSenseData = 0xb3; +USHORT SiS300_YCSenseData = 0xb9; +USHORT SiS300_RGBSenseData2 = 0x0190; /*301b */ +USHORT SiS300_VideoSenseData2 = 0x0174; +USHORT SiS300_YCSenseData2 = 0x016b; + +UCHAR SiS300_CR40[5][4]; +UCHAR SiS300_CR49[2]; +UCHAR SiS300_NTSCPhase[] = { 0x21, 0xed, 0x8a, 0x8 }; +UCHAR SiS300_PALPhase[] = { 0x2a, 0x5, 0xd3, 0x0 }; +UCHAR SiS300_NTSCPhase2[] = { 0x21, 0xF0, 0x7B, 0xD6 }; /*301b */ +UCHAR SiS300_PALPhase2[] = { 0x2a, 0x09, 0x86, 0xe9 }; +UCHAR SiS300_PALMPhase[] = { 0x21, 0xE4, 0x2E, 0x9B }; /*palmn */ +UCHAR SiS300_PALNPhase[] = { 0x21, 0xF4, 0x3E, 0xBA }; + +typedef struct _SiS300_PanelDelayTblStruct { + UCHAR timer[2]; +} SiS300_PanelDelayTblStruct; +SiS300_PanelDelayTblStruct SiS300_PanelDelayTbl[] = { + {{0x05, 0xaa}}, + {{0x05, 0x14}}, + {{0x05, 0x36}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x90}}, + {{0x05, 0x90}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x64}}, + {{0x05, 0x14}}, + {{0x05, 0x14}}, + {{0x05, 0x14}} +}; + +typedef struct _SiS300_LCDDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS300_LCDDataStruct; +SiS300_LCDDataStruct SiS300_StLCD1024x768Data[] = { + {66, 31, 992, 510, 1320, 816}, + {66, 31, 992, 510, 1320, 816}, + {176, 75, 900, 510, 1320, 816}, + {176, 75, 900, 510, 1320, 816}, + {66, 31, 992, 510, 1320, 816}, + {27, 16, 1024, 650, 1350, 832}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS300_LCDDataStruct SiS300_ExtLCD1024x768Data[] = { + {12, 5, 896, 512, 1344, 806}, + {12, 5, 896, 510, 1344, 806}, + {32, 15, 1008, 505, 1344, 806}, + {32, 15, 1008, 514, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS300_LCDDataStruct SiS300_St2LCD1024x768Data[] = { + {62, 25, 800, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {104, 45, 945, 496, 1344, 806}, + {62, 25, 800, 546, 1344, 806}, + {31, 18, 1008, 624, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS300_LCDDataStruct SiS300_StLCD1280x1024Data[] = { + {4, 1, 880, 510, 1650, 1088}, + {4, 1, 880, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {4, 1, 880, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS300_LCDDataStruct SiS300_ExtLCD1280x1024Data[] = { + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 500, 1688, 1066}, + {211, 75, 1024, 625, 1688, 1066}, + {211, 120, 1280, 798, 1688, 1066}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS300_LCDDataStruct SiS300_St2LCD1280x1024Data[] = { + {22, 5, 800, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS300_LCDDataStruct SiS300_NoScaleData[] = { + {1, 1, 800, 449, 800, 449}, + {1, 1, 800, 449, 800, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 800, 525, 800, 525}, + {1, 1, 1056, 628, 1056, 628}, + {1, 1, 1344, 806, 1344, 806}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS300_LCDDataStruct SiS300_LCD1280x960Data[] = { + {9, 2, 800, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {30, 11, 1056, 625, 1800, 1000}, + {5, 3, 1350, 800, 1800, 1000}, + {1, 1, 1576, 1050, 1576, 1050}, + {1, 1, 1800, 1000, 1800, 1000} +}; + +typedef struct _SiS300_TVDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT TVHDE; + USHORT TVVDE; + USHORT RVBHRS; + UCHAR FlickerMode; + USHORT HALFRVBHRS; + UCHAR RY1COE; + UCHAR RY2COE; + UCHAR RY3COE; + UCHAR RY4COE; +} SiS300_TVDataStruct; +SiS300_TVDataStruct SiS300_StPALData[] = { + {1, 1, 864, 525, 1270, 400, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 350, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 864, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 864, 525, 1270, 480, 50, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 600, 50, 0, 0, 0xf4, 0xff, 0x1c, 0x22} +}; + +SiS300_TVDataStruct SiS300_ExtPALData[] = { + {27, 10, 848, 448, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {108, 35, 848, 398, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {12, 5, 954, 448, 1270, 530, 50, 0, 50, 0xf1, 0x04, 0x1f, 0x18}, + {9, 4, 960, 463, 1644, 438, 50, 0, 50, 0xf4, 0x0b, 0x1c, 0x0a}, + {9, 4, 848, 528, 1270, 530, 0, 0, 50, 0xf5, 0xfb, 0x1b, 0x2a}, + {36, 25, 1060, 648, 1316, 530, 438, 0, 438, 0xeb, 0x05, 0x25, 0x16}, + {3, 2, 1080, 619, 1270, 540, 438, 0, 438, 0xf3, 0x00, 0x1d, 0x20}, + {1, 1, 1170, 821, 1270, 520, 686, 0, 686, 0xF3, 0x00, 0x1D, 0x20} /*301b */ + +}; + +SiS300_TVDataStruct SiS300_StNTSCData[] = { + {1, 1, 858, 525, 1270, 400, 50, 0, 760, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 50, 0, 640, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 858, 525, 1270, 480, 0, 0, 760, 0xf1, 0x04, 0x1f, 0x18} +}; + +SiS300_TVDataStruct SiS300_ExtNTSCData[] = { + {143, 65, 858, 443, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {88, 35, 858, 393, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 443, 1270, 440, 92, 0, 92, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 393, 1270, 440, 92, 0, 92, 0xf4, 0x0b, 0x1c, 0x0a}, + {143, 76, 836, 523, 1270, 440, 224, 0, 0, 0xf1, 0x05, 0x1f, 0x16}, + {143, 120, 1056, 643, 1270, 440, 0, 128, 0, 0xf4, 0x10, 0x1c, 0x00}, + {143, 76, 836, 523, 1270, 440, 0, 128, 0, 0xee, 0x0c, 0x22, 0x08}, + {65, 64, 1056, 791, 1270, 480, 638, 0, 0, 0xf1, 0x04, 0x1f, 0x18} /*301b */ +}; + +SiS_TVDataStruct SiS300_St1HiTVData[] = { + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00} +}; + +SiS_TVDataStruct SiS300_St2HiTVData[] = { + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00} +}; + +SiS_TVDataStruct SiS300_ExtHiTVData[] = { + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00} +}; + +UCHAR SiS300_NTSCTiming[] = { + 0x17, 0x1d, 0x03, 0x09, 0x05, 0x06, 0x0c, 0x0c, + 0x94, 0x49, 0x01, 0x0a, 0x06, 0x0d, 0x04, 0x0a, + 0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x1b, + 0x0c, 0x50, 0x00, 0x97, 0x00, 0xda, 0x4a, 0x17, + 0x7d, 0x05, 0x4b, 0x00, 0x00, 0xe2, 0x00, 0x02, + 0x03, 0x0a, 0x65, 0x9d, 0x08, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x50, + 0x00, 0x40, 0x44, 0x00, 0xdb, 0x02, 0x3b, 0x00 +}; + +UCHAR SiS300_PALTiming[] = { + 0x19, 0x52, 0x35, 0x6e, 0x04, 0x38, 0x3d, 0x70, + 0x94, 0x49, 0x01, 0x12, 0x06, 0x3e, 0x35, 0x6d, + 0x06, 0x14, 0x3e, 0x35, 0x6d, 0x00, 0x45, 0x2b, + 0x70, 0x50, 0x00, 0x9b, 0x00, 0xd9, 0x5d, 0x17, + 0x7d, 0x05, 0x45, 0x00, 0x00, 0xe8, 0x00, 0x02, + 0x0d, 0x00, 0x68, 0xb0, 0x0b, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x63, + 0x00, 0x40, 0x3e, 0x00, 0xe1, 0x02, 0x28, 0x00 +}; + +UCHAR SiS300_HiTVExtTiming[] = { 0x00 }; + +UCHAR SiS300_HiTVSt1Timing[] = { 0x00 }; + +UCHAR SiS300_HiTVSt2Timing[] = { 0x00 }; + +UCHAR SiS300_HiTVTextTiming[] = { 0x00 }; + +UCHAR SiS300_HiTVGroup3Data[] = { 0x00 }; + +UCHAR SiS300_HiTVGroup3Simu[] = { 0x00 }; + +UCHAR SiS300_HiTVGroup3Text[] = { 0x00 }; + +typedef struct _SiS300_LVDSDataStruct { + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS300_LVDSDataStruct; +SiS300_LVDSDataStruct SiS300_LVDS800x600Data_1[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS800x600Data_2[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS1024x768Data_1[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS1024x768Data_2[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS1280x1024Data_1[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS1280x1024Data_2[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_LVDS640x480Data_1[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_CHTVUNTSCData[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_CHTVONTSCData[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_CHTVUPALData[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +SiS300_LVDSDataStruct SiS300_CHTVOPALData[] = { + {0x00, 0x00, 0x00, 0x00} +}; + +typedef struct _SiS300_LVDSDesStruct { + USHORT LCDHDES; + USHORT LCDVDES; +} SiS300_LVDSDesStruct; +SiS300_LVDSDesStruct SiS300_PanelType00_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType01_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType02_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType03_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType04_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType05_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType06_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType07_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType08_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType09_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0a_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0b_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0c_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0d_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0e_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0f_1[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType00_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType01_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType02_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType03_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType04_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType05_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType06_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType07_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType08_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType09_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0a_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0b_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0c_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0d_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0e_2[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_PanelType0f_2[] = { + {0x00, 0x00} +}; + +/*301b*/ +SiS300_LVDSDesStruct SiS300_PanelType1076_1[] = { + {0x00, 0x00} +}; +SiS300_LVDSDesStruct SiS300_PanelType1210_1[] = { + {0x00, 0x00} +}; +SiS300_LVDSDesStruct SiS300_PanelType1296_1[] = { + {0x00, 0x00} +}; +SiS300_LVDSDesStruct SiS300_PanelType1076_2[] = { + {0x00, 0x00} +}; +SiS300_LVDSDesStruct SiS300_PanelType1210_2[] = { + {0x00, 0x00} +}; +SiS300_LVDSDesStruct SiS300_PanelType1296_2[] = { + {0x00, 0x00} +}; +/*end 301b*/ + +SiS300_LVDSDesStruct SiS300_CHTVUNTSCDesData[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_CHTVONTSCDesData[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_CHTVUPALDesData[] = { + {0x00, 0x00} +}; + +SiS300_LVDSDesStruct SiS300_CHTVOPALDesData[] = { + {0x00, 0x00} +}; + +typedef struct _SiS300_LVDSCRT1DataStruct { + UCHAR CR[15]; +} SiS300_LVDSCRT1DataStruct; +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2_H[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1UNTSC[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1ONTSC[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1UPAL[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1OPAL[] = { + + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}} +}; + +typedef struct _SiS300_CHTVRegDataStruct { + UCHAR Reg[5]; +} SiS300_CHTVRegDataStruct; +SiS300_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00}} +}; + +SiS300_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = { + {{0x00, 0x00, 0x00, 0x00, 0x00}} +}; + +UCHAR SiS300_CHTVVCLKUNTSC[] = { 0x00 }; + +UCHAR SiS300_CHTVVCLKONTSC[] = { 0x00 }; + +UCHAR SiS300_CHTVVCLKUPAL[] = { 0x00 }; + +UCHAR SiS300_CHTVVCLKOPAL[] = { 0x00 }; diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/310vtbl.h linux/drivers/video/sis/310vtbl.h --- v2.4.14/linux/drivers/video/sis/310vtbl.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/310vtbl.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,2604 @@ +typedef struct _SiS310_StStruct { + UCHAR St_ModeID; + USHORT St_ModeFlag; + UCHAR St_StTableIndex; + UCHAR St_CRT2CRTC; + UCHAR St_ResInfo; + UCHAR VB_StTVFlickerIndex; + UCHAR VB_StTVEdgeIndex; + UCHAR VB_StTVYFilterIndex; +} SiS310_StStruct; + +SiS310_StStruct SiS310_SModeIDTable[] = +{ + {0x01, 0x9208, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, + {0x01, 0x1210, 0x14, 0x01, 0x01, 0x00, 0x01, 0x00}, + {0x01, 0x1010, 0x17, 0x02, 0x02, 0x00, 0x01, 0x01}, + {0x03, 0x8208, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02}, + {0x03, 0x0210, 0x16, 0x01, 0x01, 0x00, 0x01, 0x02}, + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03}, + {0x05, 0x9209, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x06, 0x8209, 0x06, 0x00, 0x00, 0x00, 0x00, 0x05}, + {0x07, 0x0000, 0x07, 0x03, 0x03, 0x00, 0x01, 0x03}, + {0x07, 0x0000, 0x19, 0x02, 0x02, 0x00, 0x01, 0x03}, + {0x0d, 0x920a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x0e, 0x820a, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x05}, + {0x0f, 0x0202, 0x11, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0x10, 0x0212, 0x12, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0x11, 0x0212, 0x1a, 0x04, 0x04, 0x00, 0x00, 0x05}, + {0x12, 0x0212, 0x1b, 0x04, 0x04, 0x00, 0x00, 0x05}, + {0x13, 0x021b, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x12, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x00, 0x05}, + {0x12, 0x0210, 0x18, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +typedef struct _SiS310_StandTableStruct { + UCHAR CRT_COLS; + UCHAR ROWS; + UCHAR CHAR_HEIGHT; + USHORT CRT_LEN; + UCHAR SR[4]; + UCHAR MISC; + UCHAR CRTC[0x19]; + UCHAR ATTR[0x14]; + UCHAR GRC[9]; +} SiS310_StandTableStruct; + +SiS310_StandTableStruct SiS310_StandTable[] = { +/* MD_0_200 */ + { + 0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_1_200 */ + { + 0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_200 */ + { + 0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_3_200 */ + { + 0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_4 */ + { + 0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff} + }, +/* MD_5 */ + { + 0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff} + }, +/* MD_6 */ + { + 0x50, 0x18, 0x08, 0x4000, + {0x01, 0x01, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2, + 0xff}, + {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x01, 0x00, 0x01, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0xff} + }, +/* MD_7 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x00, 0x03, 0x00, 0x03}, + 0xa6, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff} + }, +/* MDA_DAC */ + { + 0x00, 0x00, 0x00, 0x0000, + {0x00, 0x00, 0x00, 0x15}, + 0x15, + {0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, + 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15}, + {0x15, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f} + }, +/* CGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {0x11, 0x09, 0x15, 0x00}, + 0x10, + {0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, + 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x2a, 0x3a, + 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x10, + 0x04}, + {0x14, 0x01, 0x11, 0x09, 0x15, 0x00, 0x10, 0x04, + 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, 0x2e, + 0x3e, 0x2b, 0x3b, 0x2f}, + {0x3f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, + 0x3f} + }, +/* EGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {0x11, 0x05, 0x15, 0x20}, + 0x30, + {0x24, 0x34, 0x21, 0x31, 0x25, 0x35, 0x08, 0x18, + 0x0c, 0x1c, 0x09, 0x19, 0x0d, 0x1d, 0x28, 0x38, + 0x2c, 0x3c, 0x29, 0x39, 0x2d, 0x3d, 0x02, 0x12, + 0x06}, + {0x16, 0x03, 0x13, 0x07, 0x17, 0x22, 0x32, 0x26, + 0x36, 0x23, 0x33, 0x27, 0x37, 0x0a, 0x1a, 0x0e, + 0x1e, 0x0b, 0x1b, 0x0f}, + {0x1f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, + 0x3f} + }, +/* VGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {0x11, 0x09, 0x15, 0x2a}, + 0x3a, + {0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x05, + 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x18, 0x1c, 0x20, + 0x24, 0x28, 0x2d, 0x32, 0x38, 0x3f, 0x00, 0x10, + 0x1f}, + {0x2f, 0x3f, 0x1f, 0x27, 0x2f, 0x37, 0x3f, 0x2d, + 0x31, 0x36, 0x3a, 0x3f, 0x00, 0x07, 0x0e, 0x15, + 0x1c, 0x0e, 0x11, 0x15}, + {0x18, 0x1c, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x00, + 0x04} + }, + { + 0x08, 0x0c, 0x10, 0x0a08, + {0x0c, 0x0e, 0x10, 0x0b}, + 0x0c, + {0x0d, 0x0f, 0x10, 0x10, 0x01, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, + 0x04, 0x04, 0x01, 0x00, 0x05, 0x02, 0x05, 0x00, + 0x06}, + {0x01, 0x06, 0x05, 0x06, 0x00, 0x08, 0x01, 0x08, + 0x00, 0x07, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} + }, +/* MD_D */ + { + 0x28, 0x18, 0x08, 0x2000, + {0x09, 0x0f, 0x00, 0x06}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_E */ + { + 0x50, 0x18, 0x08, 0x4000, + {0x01, 0x0f, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* ExtVGATable */ + { + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff} + }, +/* ROM_SAVEPTR */ + { + 0x9f, 0x3b, 0x00, 0x00c0, + {0x00, 0x00, 0x00, 0x00}, + 0x00, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x3f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1a, 0x00, 0xac, 0x3e, 0x00, 0xc0, + 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} + }, +/* MD_F */ + { + 0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa2, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x0b, 0x00, 0x05, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, + 0xff} + }, +/* MD_10 */ + { + 0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_0_350 */ + { + 0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_1_350 */ + { + 0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_350 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_3_350 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_0_1_400 */ + { + 0x28, 0x18, 0x10, 0x0800, + {0x08, 0x03, 0x00, 0x02}, + 0x67, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_3_400 */ + { + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_7_400 */ + { + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x66, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff} + }, +/* MD_11 */ + { + 0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3, + 0xff}, + {0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, + 0xff} + }, +/* ExtEGATable */ + { + 0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_13 */ + { + 0x28, 0x18, 0x08, 0x2000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x41, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff} + } +}; + +typedef struct _SiS310_ExtStruct { + UCHAR Ext_ModeID; + USHORT Ext_ModeFlag; + USHORT Ext_ModeInfo; + USHORT Ext_Point; + USHORT Ext_VESAID; + UCHAR Ext_VESAMEMSize; + UCHAR Ext_RESINFO; + UCHAR VB_ExtTVFlickerIndex; + UCHAR VB_ExtTVEdgeIndex; + UCHAR VB_ExtTVYFilterIndex; + UCHAR REFindex; +} SiS310_ExtStruct; +SiS310_ExtStruct SiS310_EModeIDTable[] = { + + {0x6a, 0x2212, 0x0407, 0x3a81, 0x0102, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x2e, 0x0a1b, 0x0306, 0x3a57, 0x0101, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x2f, 0x0a1b, 0x0305, 0x3a50, 0x0100, 0x08, 0x05, 0x00, 0x00, 0x05, + 0x10}, + {0x30, 0x2a1b, 0x0407, 0x3a81, 0x0103, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x31, 0x0a1b, 0x030d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x32, 0x0a1b, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x33, 0x0a1d, 0x0a0d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x34, 0x2a1d, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x35, 0x0a1f, 0x0a0d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x36, 0x2a1f, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x37, 0x0212, 0x0508, 0x3aab, 0x0104, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x38, 0x0a1b, 0x0508, 0x3aab, 0x0105, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x3a, 0x0e3b, 0x0609, 0x3adc, 0x0107, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x3c, 0x063b, 0x070a, 0x3af2, 0x0130, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x3d, 0x067d, 0x070a, 0x3af2, 0x0131, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x40, 0x9a1c, 0x0000, 0x3a34, 0x010d, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x41, 0x9a1d, 0x0000, 0x3a34, 0x010e, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x43, 0x0a1c, 0x0306, 0x3a57, 0x0110, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x44, 0x0a1d, 0x0306, 0x3a57, 0x0111, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x46, 0x2a1c, 0x0407, 0x3a81, 0x0113, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x47, 0x2a1d, 0x0407, 0x3a81, 0x0114, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x49, 0x0a3c, 0x0508, 0x3aab, 0x0116, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x4a, 0x0a3d, 0x0508, 0x3aab, 0x0117, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x4c, 0x0e7c, 0x0609, 0x3adc, 0x0119, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x4d, 0x0e7d, 0x0609, 0x3adc, 0x011a, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x50, 0x9a1b, 0x0001, 0x3a3b, 0x0132, 0x08, 0x01, 0x00, 0x00, 0x04, + 0x26}, + {0x51, 0xba1b, 0x0103, 0x3a42, 0x0133, 0x08, 0x03, 0x00, 0x00, 0x07, + 0x27}, + {0x52, 0x9a1b, 0x0204, 0x3a49, 0x0134, 0x08, 0x04, 0x00, 0x00, 0x00, + 0x28}, + {0x56, 0x9a1d, 0x0001, 0x3a3b, 0x0135, 0x08, 0x01, 0x00, 0x00, 0x04, + 0x26}, + {0x57, 0xba1d, 0x0103, 0x3a42, 0x0136, 0x08, 0x03, 0x00, 0x00, 0x07, + 0x27}, + {0x58, 0x9a1d, 0x0204, 0x3a49, 0x0137, 0x08, 0x04, 0x00, 0x00, 0x00, + 0x28}, + {0x59, 0x9a1b, 0x0000, 0x3a34, 0x0138, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x5d, 0x0a1d, 0x0305, 0x3a50, 0x0139, 0x08, 0x05, 0x00, 0x00, 0x07, + 0x10}, + {0x62, 0x0a3f, 0x0306, 0x3a57, 0x013a, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x63, 0x2a3f, 0x0407, 0x3a81, 0x013b, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x64, 0x0a7f, 0x0508, 0x3aab, 0x013c, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x65, 0x0eff, 0x0609, 0x3adc, 0x013d, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x66, 0x06ff, 0x070a, 0x3af2, 0x013e, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x68, 0x067b, 0x080b, 0x3b17, 0x013f, 0x08, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x69, 0x06fd, 0x080b, 0x3b17, 0x0140, 0x08, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x6b, 0x07ff, 0x080b, 0x3b17, 0x0141, 0x10, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x6c, 0x067b, 0x090c, 0x3b37, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x6d, 0x06fd, 0x090c, 0x3b37, 0x0000, 0x10, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x6e, 0x07ff, 0x090c, 0x3b37, 0x0000, 0x10, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x70, 0x2a1b, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x71, 0x0a1b, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x74, 0x0a1d, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x75, 0x0a3d, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x76, 0x2a1f, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x77, 0x0a1f, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x78, 0x0a3f, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x79, 0x0a3b, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x7a, 0x2a1d, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x7b, 0x0e3b, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0x7c, 0x0e7d, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0x7d, 0x0eff, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0xff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} +}; + +typedef struct _SiS310_Ext2Struct { + USHORT Ext_InfoFlag; + UCHAR Ext_CRT1CRTC; + UCHAR Ext_CRTVCLK; + UCHAR Ext_CRT2CRTC; + UCHAR ModeID; + USHORT XRes; + USHORT YRes; + USHORT ROM_OFFSET; +} SiS310_Ext2Struct; +SiS310_Ext2Struct SiS310_RefIndex[] = { + {0x005f, 0x0d, 0x03, 0x05, 0x6a, 800, 600, 0x3a81}, /* 0x0 */ + {0x0467, 0x0e, 0x04, 0x05, 0x6a, 800, 600, 0x3a86}, /* 0x1 */ + {0x0067, 0x0f, 0x08, 0x48, 0x6a, 800, 600, 0x3a8b}, /* 0x2 */ + {0x0067, 0x10, 0x07, 0x8b, 0x6a, 800, 600, 0x3a90}, /* 0x3 */ + {0x0147, 0x11, 0x0a, 0x00, 0x6a, 800, 600, 0x3a95}, /* 0x4 */ + {0x4147, 0x12, 0x0d, 0x00, 0x6a, 800, 600, 0x3a9a}, /* 0x5 */ + {0x4047, 0x13, 0x13, 0x00, 0x6a, 800, 600, 0x3a9f}, /* 0x6 */ + {0x4047, 0x14, 0x1c, 0x00, 0x6a, 800, 600, 0x3aa4}, /* 0x7 */ + {0xc05f, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x3a57}, /* 0x8 */ + {0xc067, 0x06, 0x02, 0x04, 0x2e, 640, 480, 0x3a5c}, /* 0x9 */ + {0xc067, 0x07, 0x02, 0x47, 0x2e, 640, 480, 0x3a61}, /* 0xa */ + {0xc067, 0x08, 0x03, 0x8a, 0x2e, 640, 480, 0x3a66}, /* 0xb */ + {0x4047, 0x09, 0x05, 0x00, 0x2e, 640, 480, 0x3a6b}, /* 0xc */ + {0x4047, 0x0a, 0x09, 0x00, 0x2e, 640, 480, 0x3a70}, /* 0xd */ + {0x4047, 0x0b, 0x0e, 0x00, 0x2e, 640, 480, 0x3a75}, /* 0xe */ + {0xc047, 0x0c, 0x15, 0x00, 0x2e, 640, 480, 0x3a7a}, /* 0xf */ + {0x407f, 0x04, 0x00, 0x00, 0x2f, 640, 400, 0x3a50}, /* 0x10 */ + {0xc00f, 0x3c, 0x01, 0x06, 0x31, 720, 480, 0x3b85}, /* 0x11 */ + {0x000f, 0x3d, 0x03, 0x06, 0x32, 720, 576, 0x3b8c}, /* 0x12 */ + {0x0187, 0x15, 0x06, 0x00, 0x37, 1024, 768, 0x3aab}, /* 0x13 */ + {0xc877, 0x16, 0x0b, 0x06, 0x37, 1024, 768, 0x3ab0}, /* 0x14 301b TV1024x768 */ + {0xc067, 0x17, 0x0f, 0x49, 0x37, 1024, 768, 0x3ab5}, /* 0x15 */ + {0x0267, 0x18, 0x11, 0x00, 0x37, 1024, 768, 0x3aba}, /* 0x16 */ + {0x0047, 0x19, 0x16, 0x8c, 0x37, 1024, 768, 0x3abf}, /* 0x17 */ + {0x4047, 0x1a, 0x1b, 0x00, 0x37, 1024, 768, 0x3ac4}, /* 0x18 */ + {0x4047, 0x1b, 0x1f, 0x00, 0x37, 1024, 768, 0x3ac9}, /* 0x19 */ + {0x0387, 0x1c, 0x11, 0x00, 0x3a, 1280, 1024, 0x3adc}, /* 0x1a */ + {0x0077, 0x1d, 0x19, 0x07, 0x3a, 1280, 1024, 0x3ae1}, /* 0x1b */ + {0x0047, 0x1e, 0x1e, 0x00, 0x3a, 1280, 1024, 0x3ae6}, /* 0x1c */ + {0x0007, 0x1f, 0x20, 0x00, 0x3a, 1280, 1024, 0x3aeb}, /* 0x1d */ + {0x0007, 0x20, 0x21, 0x00, 0x3c, 1600, 1200, 0x3af2}, /* 0x1e */ + {0x0007, 0x21, 0x22, 0x00, 0x3c, 1600, 1200, 0x3af7}, /* 0x1f */ + {0x0007, 0x22, 0x23, 0x00, 0x3c, 1600, 1200, 0x3afc}, /* 0x20 */ + {0x0007, 0x23, 0x25, 0x00, 0x3c, 1600, 1200, 0x3b01}, /* 0x21 */ + {0x0007, 0x24, 0x26, 0x00, 0x3c, 1600, 1200, 0x3b06}, /* 0x22 */ + {0x0007, 0x25, 0x2c, 0x00, 0x3c, 1600, 1200, 0x3b0b}, /* 0x23 */ + {0x0007, 0x26, 0x34, 0x00, 0x3c, 1600, 1200, 0x3b10}, /* 0x24 */ + {0x407f, 0x00, 0x00, 0x00, 0x40, 320, 200, 0x3a34}, /* 0x25 */ + {0xc07f, 0x01, 0x00, 0x04, 0x50, 320, 240, 0x3a3b}, /* 0x26 */ + {0x007f, 0x02, 0x04, 0x05, 0x51, 400, 300, 0x3a42}, /* 0x27 */ + {0xc077, 0x03, 0x0b, 0x06, 0x52, 512, 384, 0x3a49}, /* 0x28 */ + {0x8007, 0x27, 0x27, 0x00, 0x68, 1920, 1440, 0x3b17}, /* 0x29 */ + {0x4007, 0x28, 0x29, 0x00, 0x68, 1920, 1440, 0x3b1c}, /* 0x2a */ + {0x4007, 0x29, 0x2e, 0x00, 0x68, 1920, 1440, 0x3b21}, /* 0x2b */ + {0x4007, 0x2a, 0x30, 0x00, 0x68, 1920, 1440, 0x3b26}, /* 0x2c */ + {0x4007, 0x2b, 0x35, 0x00, 0x68, 1920, 1440, 0x3b2b}, /* 0x2d */ + {0x4005, 0x2c, 0x39, 0x00, 0x68, 1920, 1440, 0x3b30}, /* 0x2e */ + {0x4007, 0x2d, 0x2b, 0x00, 0x6c, 2048, 1536, 0x3b37}, /* 0x2f */ + {0x4007, 0x2e, 0x31, 0x00, 0x6c, 2048, 1536, 0x3b3c}, /* 0x30 */ + {0x4007, 0x2f, 0x33, 0x00, 0x6c, 2048, 1536, 0x3b41}, /* 0x31 */ + {0x4007, 0x30, 0x37, 0x00, 0x6c, 2048, 1536, 0x3b46}, /* 0x32 */ + {0x4005, 0x31, 0x38, 0x00, 0x6c, 2048, 1536, 0x3b4b}, /* 0x33 */ + {0x0057, 0x32, 0x40, 0x08, 0x70, 800, 480, 0x3b52}, /* 0x34 */ + {0x0047, 0x33, 0x07, 0x08, 0x70, 800, 480, 0x3b57}, /* 0x35 */ + {0x0047, 0x34, 0x0a, 0x08, 0x70, 800, 480, 0x3b5c}, /* 0x36 */ + {0x0057, 0x35, 0x0b, 0x09, 0x71, 1024, 576, 0x3b63}, /* 0x37 */ + {0x0047, 0x36, 0x11, 0x09, 0x71, 1024, 576, 0x3b68}, /* 0x38 */ + {0x0047, 0x37, 0x16, 0x09, 0x71, 1024, 576, 0x3b6d}, /* 0x39 */ + {0x0057, 0x38, 0x19, 0x0a, 0x75, 1280, 720, 0x3b74}, /* 0x3a */ + {0x0047, 0x39, 0x1e, 0x0a, 0x75, 1280, 720, 0x3b79}, /* 0x3b */ + {0x0047, 0x3a, 0x20, 0x0a, 0x75, 1280, 720, 0x3b7e}, /* 0x3c */ + {0x0027, 0x3b, 0x19, 0x08, 0x7b, 1280, 960, 0x3ad0}, /* 0x3d */ + {0x0027, 0x3b, 0x19, 0x08, 0x7b, 1280, 960, 0x3ad5}, /* 0x3e */ + {0xffff, 0x00, 0x00, 0x00, 0x00, 0000, 0000, 0x0000} +}; + +typedef struct _SiS310_CRT1TableStruct { + UCHAR CR[17]; +} SiS310_CRT1TableStruct; + +SiS310_CRT1TableStruct SiS310_CRT1Table[] = { + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, + 0x00}}, /* 0x0 */ + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x1 */ + {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}}, /* 0x2 */ + {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}}, /* 0x3 */ + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}}, /* 0x4 */ + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, /* 0x5 */ + {{0x63, 0x4f, 0x50, 0x86, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8b, 0xdf, 0xe7, 0xff, 0x10, 0x00, 0x01, + 0x00}}, /* 0x6 */ + {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}}, /* 0x7 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}}, /* 0x8 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x00, 0x00, 0x05, + 0x61}}, /* 0x9 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, + 0x61}}, /* 0xa */ + {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x10, 0x00, 0x05, + 0x61}}, /* 0xb */ + {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xe5, 0xe5, 0xfc, 0x00, 0x00, 0x01, + 0x00}}, /* 0xc */ + {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, /* 0xd */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}}, /* 0xe */ + {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}}, /* 0xf */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}}, /* 0x10 */ + {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, /* 0x11 */ + {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, + 0x61}}, /* 0x12 */ + {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, + 0x61}}, /* 0x13 */ + {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, + 0x61}}, /* 0x14 */ + {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}}, /* 0x15 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x16 */ + {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x17 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, /* 0x18 */ + {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}}, /* 0x19 */ + {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1a */ + {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1b */ + {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}}, /* 0x1c */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1d */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1e */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1f */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x20 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x21 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x22 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x23 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x24 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x25 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x26 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x27 */ + {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x28 */ + {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x29 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2a */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2b */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2c */ + {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2d */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2e */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2f */ + {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x30 */ + {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}}, /* 0x31 */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}}, /* 0x32 */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}}, /* 0x33 */ + {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}}, /* 0x34 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}}, /* 0x35 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x36 */ + {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x15, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}}, /* 0x37 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x38 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x39 */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}}, /* 0x3a */ + {{0xdc, 0x9f, 0x9f, 0x00, 0xab, 0x19, 0xe6, 0xef, + 0xc0, 0xc3, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}}, /* 0x3b */ + {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, /* 0x3c */ + {{0x7b, 0x59, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x3f, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}} /* 0x3d */ +}; + +typedef struct _SiS310_MCLKDataStruct { + UCHAR SR28, SR29, SR2A; + USHORT CLOCK; +} SiS310_MCLKDataStruct; +SiS310_MCLKDataStruct SiS310_MCLKData[] = { + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166} +}; + +typedef struct _SiS310_ECLKDataStruct { + UCHAR SR2E, SR2F, SR30; + USHORT CLOCK; +} SiS310_ECLKDataStruct; +SiS310_ECLKDataStruct SiS310_ECLKData[] = { + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166} +}; + +typedef struct _SiS310_VCLKDataStruct { + UCHAR SR2B, SR2C; + USHORT CLOCK; +} SiS310_VCLKDataStruct; +SiS310_VCLKDataStruct SiS310_VCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x0 */ + {0x4e, 0xe4, 28}, /* 0x1 */ + {0x57, 0xe4, 31}, /* 0x2 */ + {0xc3, 0xc8, 36}, /* 0x3 */ + {0x42, 0xe2, 40}, /* 0x4 */ + {0xfe, 0xcd, 43}, /* 0x5 */ + {0x5d, 0xc4, 44}, /* 0x6 */ + {0x52, 0xe2, 49}, /* 0x7 */ + {0x53, 0xe2, 50}, /* 0x8 */ + {0x74, 0x67, 52}, /* 0x9 */ + {0x6d, 0x66, 56}, /* 0xa */ + {0x6c, 0xc3, 65}, /* 0xb */ + {0x46, 0x44, 67}, /* 0xc */ + {0xb1, 0x46, 68}, /* 0xd */ + {0xd3, 0x4a, 72}, /* 0xe */ + {0x29, 0x61, 75}, /* 0xf */ + {0x6e, 0x46, 76}, /* 0x10 */ + {0x2b, 0x61, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x41, 104}, /* 0x17 */ + {0x3a, 0x23, 105}, /* 0x18 */ + {0x70, 0x44, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0x54, 0x42, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x62, 0x06, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a */ + {0x52, 0x6a, 27}, /* 0x3b */ + {0x62, 0x24, 70}, /* 0x3c */ + {0x62, 0x64, 70}, /* 0x3d */ + {0xa8, 0x4c, 30}, /* 0x3e */ + {0x20, 0x26, 33}, /* 0x3f */ + {0x31, 0xc2, 39} /* 0x40 */ +}; + +typedef struct _SiS310_VBVCLKDataStruct { + UCHAR Part4_A, Part4_B; + USHORT CLOCK; +} SiS310_VBVCLKDataStruct; +SiS310_VBVCLKDataStruct SiS310_VBVCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x0 */ + {0x4e, 0xe4, 28}, /* 0x1 */ + {0x57, 0xe4, 31}, /* 0x2 */ + {0xc3, 0xc8, 36}, /* 0x3 */ + {0x42, 0x47, 40}, /* 0x4 */ + {0xfe, 0xcd, 43}, /* 0x5 */ + {0x5d, 0xc4, 44}, /* 0x6 */ + {0x52, 0x47, 49}, /* 0x7 */ + {0x53, 0x47, 50}, /* 0x8 */ + {0x74, 0x67, 52}, /* 0x9 */ + {0x6d, 0x66, 56}, /* 0xa */ + {0x5a, 0x64, 65}, /* 0xb */ + {0x46, 0x44, 67}, /* 0xc */ + {0xb1, 0x46, 68}, /* 0xd */ + {0xd3, 0x4a, 72}, /* 0xe */ + {0x29, 0x61, 75}, /* 0xf */ + {0x6d, 0x46, 75}, /* 0x10 */ + {0x41, 0x43, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x22, 104}, /* 0x17 */ + {0x49, 0x24, 105}, /* 0x18 */ + {0xf8, 0x2f, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0xd4, 0x28, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x70, 0x07, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a */ + {0x52, 0x6a, 27}, /* 0x3b */ + {0x62, 0x24, 70}, /* 0x3c */ + {0x62, 0x64, 70}, /* 0x3d */ + {0xa8, 0x4c, 30}, /* 0x3e */ + {0x20, 0x26, 33}, /* 0x3f */ + {0x31, 0xc2, 39} /* 0x40 */ +}; + +UCHAR SiS310_ScreenOffset[] = + { 0x14, 0x19, 0x20, 0x28, 0x32, 0x40, 0x50, 0x64, 0x78, 0x80, 0x2d, 0x35 }; + +typedef struct _SiS310_StResInfoStruct { + USHORT HTotal; + USHORT VTotal; +} SiS310_StResInfoStruct; +SiS310_StResInfoStruct SiS310_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} +}; + +typedef struct _SiS310_ModeResInfoStruct { + USHORT HTotal; + USHORT VTotal; + UCHAR XChar; + UCHAR YChar; +} SiS310_ModeResInfoStruct; +SiS310_ModeResInfoStruct SiS310_ModeResInfo[] = { + {320, 200, 8, 8}, + {320, 240, 8, 8}, + {320, 400, 8, 8}, + {400, 300, 8, 8}, + {512, 384, 8, 8}, + {640, 400, 8, 16}, + {640, 480, 8, 16}, + {800, 600, 8, 16}, + {1024, 768, 8, 16}, + {1280, 1024, 8, 16}, + {1600, 1200, 8, 16}, + {1920, 1440, 8, 16}, + {2048, 1536, 8, 16}, + {720, 480, 8, 16}, + {720, 576, 8, 16}, + {1280, 960, 8, 16}, + {800, 480, 8, 16}, + {1024, 576, 8, 16}, + {1280, 720, 8, 16} +}; + +UCHAR SiS310_OutputSelect = 0x40; +UCHAR SiS310_SoftSetting = 30; +UCHAR SiS310_SR07 = 0x18; +UCHAR SiS310_SR15[8][4] = { + {0x0, 0x4, 0x60, 0x60}, + {0xf, 0xf, 0xf, 0xf}, + {0xba, 0xba, 0xba, 0xba}, + {0xa9, 0xa9, 0xac, 0xac}, + {0xa0, 0xa0, 0xa0, 0xa8}, + {0x0, 0x0, 0x2, 0x2}, + {0x30, 0x30, 0x40, 0x40}, + {0x0, 0xa5, 0xfb, 0xf6} +}; +UCHAR SiS310_CR40[5][4] = { + {0x77, 0x77, 0x33, 0x33}, + {0x77, 0x77, 0x33, 0x33}, + {0x0, 0x0, 0x0, 0x0}, + {0x5b, 0x5b, 0x3, 0x3}, + {0x0, 0x0, 0xf0, 0xf8} +}; +UCHAR SiS310_CR49[] = { 0xaa, 0x88 }; +UCHAR SiS310_SR1F = 0x0; +UCHAR SiS310_SR21 = 0xa5; +UCHAR SiS310_SR22 = 0xfb; +UCHAR SiS310_SR23 = 0xf6; +UCHAR SiS310_SR24 = 0xd; +UCHAR SiS310_SR25[] = { 0x33, 0x3 }; +UCHAR SiS310_SR31 = 0x0; +UCHAR SiS310_SR32 = 0x11; +UCHAR SiS310_SR33 = 0x0; +UCHAR SiS310_CRT2Data_1_2 = 0x0; +UCHAR SiS310_CRT2Data_4_D = 0x0; +UCHAR SiS310_CRT2Data_4_E = 0x0; +UCHAR SiS310_CRT2Data_4_10 = 0x80; +USHORT SiS310_RGBSenseData = 0xd1; +USHORT SiS310_VideoSenseData = 0xb9; +USHORT SiS310_YCSenseData = 0xb3; +USHORT SiS310_RGBSenseData2 = 0x0190; /*301b */ +USHORT SiS310_VideoSenseData2 = 0x0174; +USHORT SiS310_YCSenseData2 = 0x016b; +UCHAR SiS310_NTSCPhase[] = { 0x21, 0xed, 0x8a, 0x8 }; +UCHAR SiS310_PALPhase[] = { 0x2a, 0x5, 0xd3, 0x0 }; +UCHAR SiS310_NTSCPhase2[] = { 0x21, 0xF0, 0x7B, 0xD6 }; /*301b */ +UCHAR SiS310_PALPhase2[] = { 0x2a, 0x09, 0x86, 0xe9 }; +UCHAR SiS310_PALMPhase[] = { 0x21, 0xE4, 0x2E, 0x9B }; /*palmn */ +UCHAR SiS310_PALNPhase[] = { 0x21, 0xF4, 0x3E, 0xBA }; + +typedef struct _SiS310_LCDDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS310_LCDDataStruct; +SiS310_LCDDataStruct SiS310_StLCD1024x768Data[] = { + {62, 25, 800, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {104, 45, 945, 496, 1344, 806}, + {62, 25, 800, 546, 1344, 806}, + {31, 18, 1008, 624, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_ExtLCD1024x768Data[] = { + {12, 5, 896, 512, 1344, 806}, + {12, 5, 896, 510, 1344, 806}, + {32, 15, 1008, 505, 1344, 806}, + {32, 15, 1008, 514, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_St2LCD1024x768Data[] = { + {62, 25, 800, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {104, 45, 945, 496, 1344, 806}, + {62, 25, 800, 546, 1344, 806}, + {31, 18, 1008, 624, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_StLCD1280x1024Data[] = { + {22, 5, 800, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_ExtLCD1280x1024Data[] = { + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 500, 1688, 1066}, + {211, 75, 1024, 625, 1688, 1066}, + {211, 120, 1280, 798, 1688, 1066}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_St2LCD1280x1024Data[] = { + {22, 5, 800, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_NoScaleData[] = { + {1, 1, 800, 449, 800, 449}, + {1, 1, 800, 449, 800, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 800, 525, 800, 525}, + {1, 1, 1056, 628, 1056, 628}, + {1, 1, 1344, 806, 1344, 806}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_LCD1280x960Data[] = { + {9, 2, 800, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {30, 11, 1056, 625, 1800, 1000}, + {5, 3, 1350, 800, 1800, 1000}, + {1, 1, 1576, 1050, 1576, 1050}, + {1, 1, 1800, 1000, 1800, 1000} +}; + +typedef struct _SiS310_TVDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT TVHDE; + USHORT TVVDE; + USHORT RVBHRS; + UCHAR FlickerMode; + USHORT HALFRVBHRS; + UCHAR RY1COE; + UCHAR RY2COE; + UCHAR RY3COE; + UCHAR RY4COE; +} SiS310_TVDataStruct; +SiS310_TVDataStruct SiS310_StPALData[] = { + {1, 1, 864, 525, 1270, 400, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 350, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 864, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 864, 525, 1270, 480, 50, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 600, 50, 0, 0, 0xf4, 0xff, 0x1c, 0x22} +}; + +SiS310_TVDataStruct SiS310_ExtPALData[] = { + {27, 10, 848, 448, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {108, 35, 848, 398, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {12, 5, 954, 448, 1270, 530, 50, 0, 50, 0xf1, 0x04, 0x1f, 0x18}, + {9, 4, 960, 463, 1644, 438, 50, 0, 50, 0xf4, 0x0b, 0x1c, 0x0a}, + {9, 4, 848, 528, 1270, 530, 0, 0, 50, 0xf5, 0xfb, 0x1b, 0x2a}, + {36, 25, 1060, 648, 1316, 530, 438, 0, 438, 0xeb, 0x05, 0x25, 0x16}, + {3, 2, 1080, 619, 1270, 540, 438, 0, 438, 0xf3, 0x00, 0x1d, 0x20}, + {1, 1, 1170, 821, 1270, 520, 686, 0, 686, 0xF3, 0x00, 0x1D, 0x20} /*301b */ +}; + +SiS310_TVDataStruct SiS310_StNTSCData[] = { + {1, 1, 858, 525, 1270, 400, 50, 0, 760, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 50, 0, 640, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 858, 525, 1270, 480, 0, 0, 760, 0xf1, 0x04, 0x1f, 0x18} +}; + +SiS310_TVDataStruct SiS310_ExtNTSCData[] = { + {143, 65, 858, 443, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {88, 35, 858, 393, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 443, 1270, 440, 92, 0, 92, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 393, 1270, 440, 92, 0, 92, 0xf4, 0x0b, 0x1c, 0x0a}, + {143, 76, 836, 523, 1270, 440, 224, 0, 0, 0xf1, 0x05, 0x1f, 0x16}, + {143, 120, 1056, 643, 1270, 440, 0, 128, 0, 0xf4, 0x10, 0x1c, 0x00}, + {2, 1, 858, 503, 1270, 480, 0, 128, 0, 0xee, 0x0c, 0x22, 0x08}, + {65, 64, 1056, 791, 1270, 480, 638, 0, 0, 0xEE, 0x0C, 0x22, 0x08} /*301b */ +}; + +SiS310_TVDataStruct SiS310_St1HiTVData[] = { + {0x00} +}; + +SiS310_TVDataStruct SiS310_St2HiTVData[] = { + {0x00} +}; + +SiS310_TVDataStruct SiS310_ExtHiTVData[] = { + {0x00} +}; + +UCHAR SiS310_NTSCTiming[] = { + 0x17, 0x1d, 0x03, 0x09, 0x05, 0x06, 0x0c, 0x0c, + 0x94, 0x49, 0x01, 0x0a, 0x06, 0x0d, 0x04, 0x0a, + 0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x1b, + 0x0c, 0x50, 0x00, 0x97, 0x00, 0xda, 0x4a, 0x17, + 0x7d, 0x05, 0x4b, 0x00, 0x00, 0xe2, 0x00, 0x02, + 0x03, 0x0a, 0x65, 0x9d, 0x08, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x50, + 0x00, 0x40, 0x44, 0x00, 0xdb, 0x02, 0x3b, 0x00 +}; + +UCHAR SiS310_PALTiming[] = { + 0x19, 0x52, 0x35, 0x6e, 0x04, 0x38, 0x3d, 0x70, + 0x94, 0x49, 0x01, 0x12, 0x06, 0x3e, 0x35, 0x6d, + 0x06, 0x14, 0x3e, 0x35, 0x6d, 0x00, 0x45, 0x2b, + 0x70, 0x50, 0x00, 0x9b, 0x00, 0xd9, 0x5d, 0x17, + 0x7d, 0x05, 0x45, 0x00, 0x00, 0xe8, 0x00, 0x02, + 0x0d, 0x00, 0x68, 0xb0, 0x0b, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x63, + 0x00, 0x40, 0x3e, 0x00, 0xe1, 0x02, 0x28, 0x00 +}; + +UCHAR SiS310_HiTVExtTiming[] = { 0x00 }; + +UCHAR SiS310_HiTVSt1Timing[] = { 0x00 }; + +UCHAR SiS310_HiTVSt2Timing[] = { 0x00 }; + +UCHAR SiS310_HiTVTextTiming[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Data[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Simu[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Text[] = { 0x00 }; + +typedef struct _SiS310_PanelDelayTblStruct { + UCHAR timer[2]; +} SiS310_PanelDelayTblStruct; +SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[] = { + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}}, + {{0x00, 0x00}} +}; + +typedef struct _SiS310_LVDSDataStruct { + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS310_LVDSDataStruct; +SiS310_LVDSDataStruct SiS310_LVDS800x600Data_1[] = { + {848, 433, 1060, 629}, + {848, 389, 1060, 629}, + {848, 433, 1060, 629}, + {848, 389, 1060, 629}, + {848, 518, 1060, 629}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {800, 449, 1000, 644}, + {800, 525, 1000, 635} +}; + +SiS310_LVDSDataStruct SiS310_LVDS800x600Data_2[] = { + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {800, 449, 1000, 644}, + {800, 525, 1000, 635} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1024x768Data_1[] = { + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 518, 1344, 806}, + {1050, 638, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1024x768Data_2[] = { + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1280x1024Data_1[] = { + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 518, 1344, 806}, + {1050, 638, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1280x1024Data_2[] = { + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS640x480Data_1[] = { + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 525, 800, 525}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628} +}; + +SiS310_LVDSDataStruct SiS310_CHTVUNTSCData[] = { + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {784, 600, 784, 600}, + {1064, 750, 1064, 750} +}; + +SiS310_LVDSDataStruct SiS310_CHTVONTSCData[] = { + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {784, 525, 784, 525}, + {1040, 700, 1040, 700} +}; + +SiS310_LVDSDataStruct SiS310_CHTVUPALData[] = { + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {840, 750, 840, 750}, + {936, 836, 936, 836} +}; + +SiS310_LVDSDataStruct SiS310_CHTVOPALData[] = { + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {840, 625, 840, 625}, + {960, 750, 960, 750} +}; + +typedef struct _SiS310_LVDSDesStruct { + USHORT LCDHDES; + USHORT LCDVDES; +} SiS310_LVDSDesStruct; +SiS310_LVDSDesStruct SiS310_PanelType00_1[] = { + {0, 626}, + {0, 624}, + {0, 626}, + {0, 624}, + {0, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType01_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType02_1[] = { + {0, 626}, + {0, 624}, + {0, 626}, + {0, 624}, + {0, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType03_1[] = { + {8, 436}, + {8, 440}, + {8, 436}, + {8, 440}, + {8, 512}, + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794} +}; + +SiS310_LVDSDesStruct SiS310_PanelType04_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType05_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType06_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType07_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType08_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType09_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0a_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0b_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0c_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0d_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0e_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0f_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType00_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType01_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType02_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType03_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {1152, 622}, + {1152, 597} +}; + +SiS310_LVDSDesStruct SiS310_PanelType04_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType05_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType06_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType07_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType08_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType09_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0a_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0b_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0c_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0d_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0e_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0f_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; +/*301b*/ +SiS310_LVDSDesStruct SiS310_PanelType1076_1[] = { + {0x00, 0x00} +}; +SiS310_LVDSDesStruct SiS310_PanelType1210_1[] = { + {0x00, 0x00} +}; +SiS310_LVDSDesStruct SiS310_PanelType1296_1[] = { + {0x00, 0x00} +}; +SiS310_LVDSDesStruct SiS310_PanelType1076_2[] = { + {0x00, 0x00} +}; +SiS310_LVDSDesStruct SiS310_PanelType1210_2[] = { + {0x00, 0x00} +}; +SiS310_LVDSDesStruct SiS310_PanelType1296_2[] = { + {0x00, 0x00} +}; +/*end 301b*/ + +SiS310_LVDSDesStruct SiS310_CHTVUNTSCDesData[] = { + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVONTSCDesData[] = { + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVUPALDesData[] = { + {256, 0}, + {256, 0}, + {256, 0}, + {256, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVOPALDesData[] = { + {256, 0}, + {256, 0}, + {256, 0}, + {256, 0}, + {0, 0}, + {0, 0} +}; + +/*add for LCDA*/ +typedef struct _SiS310_LCDACRT1DataStruct { + UCHAR CR[17]; +} SiS310_LCDACRT1DataStruct; +SiS310_LCDACRT1DataStruct SiS310_LCDACRT1800x600_1[] = { + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x05, + 0x00}}, + {{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_1[] = { + {{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0xDf, 0x05, 0x00, 0x00, 0x05, + 0x00}}, + {{0x87, 0x63, 0x63, 0x8B, 0x69, 0x1A, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x57, 0x7D, 0x20, 0x00, 0x26, + 0x01}}, + {{0xA3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0xFf, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_1[] = { + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x01, + 0x00}}, + {{0x7e, 0x63, 0x82, 0x68, 0x15, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x26, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT1800x600_1_H[] = { + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x04, + 0x00}}, + {{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_1_H[] = { + {{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0xDf, 0x05, 0x00, 0x00, 0x44, + 0x00}}, + {{0x41, 0x31, 0x31, 0x85, 0x35, 0x1d, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x57, 0x7D, 0x20, 0x00, 0x55, + 0x01}}, + {{0x4f, 0x3F, 0x3F, 0x93, 0x45, 0x0D, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0xFf, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_1_H[] = { + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x04, + 0x00}}, + {{0x3c, 0x31, 0x80, 0x35, 0x1c, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x55, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT1800x600_2[] = { + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_2[] = { + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_2[] = { + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT1800x600_2_H[] = { + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x3a, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_2_H[] = { + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x31, 0x93, 0x3e, 0x06, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_2_H[] = { + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x31, 0x93, 0x3e, 0x86, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +typedef struct _SiS310_LVDSCRT1DataStruct { + UCHAR CR[15]; +} SiS310_LVDSCRT1DataStruct; +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1[] = { + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}}, + {{0x65, 0x4f, 0x89, 0x56, 0x83, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x05, + 0x00}}, + {{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1[] = { + {{0x73, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}}, + {{0x73, 0x4f, 0x97, 0x55, 0x86, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0x05, 0x00, 0x00, 0x05, + 0x00}}, + {{0x87, 0x63, 0x8B, 0x69, 0x1A, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x7D, 0x20, 0x00, 0x26, + 0x01}}, + {{0xA3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1[] = { + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}}, + {{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x01, + 0x00}}, + {{0x7e, 0x63, 0x82, 0x68, 0x15, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x26, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1_H[] = { + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}}, + {{0x30, 0x27, 0x94, 0x2c, 0x92, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x04, + 0x00}}, + {{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1_H[] = { + {{0x37, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}}, + {{0x37, 0x27, 0x9B, 0x2b, 0x94, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0x05, 0x00, 0x00, 0x44, + 0x00}}, + {{0x41, 0x31, 0x85, 0x35, 0x1d, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x7D, 0x20, 0x00, 0x55, + 0x01}}, + {{0x4f, 0x3F, 0x93, 0x45, 0x0D, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1_H[] = { + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}}, + {{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x04, + 0x00}}, + {{0x3c, 0x31, 0x80, 0x35, 0x1c, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x55, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2[] = { + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x00}}, + {{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2[] = { + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2[] = { + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}}, + {{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}}, + {{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2_H[] = { + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x3a, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x05, + 0x00}}, + {{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2_H[] = { + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x31, 0x93, 0x3e, 0x06, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2_H[] = { + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}}, + {{0x4f, 0x31, 0x93, 0x3e, 0x86, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}}, + {{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1UNTSC[] = { + {{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xe8, 0x84, 0x8f, 0x57, 0x20, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xd0, 0x82, 0x5d, 0x57, 0x00, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xe8, 0x84, 0x8f, 0x57, 0x20, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xd0, 0x82, 0x5d, 0x57, 0x00, 0x00, 0x01, + 0x00}}, + {{0x5d, 0x4f, 0x81, 0x53, 0x9c, 0x56, 0xba, + 0x18, 0x84, 0xdf, 0x57, 0x00, 0x00, 0x01, + 0x00}}, + {{0x80, 0x63, 0x84, 0x6c, 0x17, 0xec, 0xf0, + 0x90, 0x8c, 0x57, 0xed, 0x20, 0x00, 0x06, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1ONTSC[] = { + {{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xc0, 0x84, 0x8f, 0x0c, 0x20, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xb0, 0x8d, 0x5d, 0x0c, 0x00, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xc0, 0x84, 0x8f, 0x0c, 0x20, 0x00, 0x01, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xb0, 0x8d, 0x5d, 0x0c, 0x00, 0x00, 0x01, + 0x00}}, + {{0x5d, 0x4f, 0x81, 0x56, 0x9c, 0x0b, 0x3e, + 0xe8, 0x84, 0xdf, 0x0c, 0x00, 0x00, 0x01, + 0x00}}, + {{0x7d, 0x63, 0x81, 0x6a, 0x16, 0xba, 0xf0, + 0x7f, 0x86, 0x57, 0xbb, 0x00, 0x00, 0x06, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1UPAL[] = { + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf8, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf8, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x55, 0x80, 0xec, 0xba, + 0x50, 0x84, 0xdf, 0xed, 0x00, 0x00, 0x05, + 0x00}}, + {{0x70, 0x63, 0x94, 0x68, 0x8d, 0x42, 0xf1, + 0xc8, 0x8c, 0x57, 0xe9, 0x20, 0x00, 0x05, + 0x01}} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1OPAL[] = { + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf0, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf0, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}}, + {{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}}, + {{0x64, 0x4f, 0x88, 0x55, 0x80, 0x6f, 0xba, + 0x20, 0x83, 0xdf, 0x70, 0x00, 0x00, 0x05, + 0x00}}, + {{0x73, 0x63, 0x97, 0x69, 0x8e, 0xec, 0xf0, + 0x90, 0x8c, 0x57, 0xed, 0x20, 0x00, 0x05, + 0x01}} +}; + +typedef struct _SiS310_CHTVRegDataStruct { + UCHAR Reg[5]; +} SiS310_CHTVRegDataStruct; +SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = { + {{0x00}} +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = { + {{0x00}} +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = { + {{0x00}} +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = { + {{0x00}} +}; + +UCHAR SiS310_CHTVVCLKUNTSC[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKONTSC[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKUPAL[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKOPAL[] = { 0x00 }; diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/325vtbl.h linux/drivers/video/sis/325vtbl.h --- v2.4.14/linux/drivers/video/sis/325vtbl.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/325vtbl.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,2318 @@ +typedef struct _SiS310_StStruct { + UCHAR St_ModeID; + USHORT St_ModeFlag; + UCHAR St_StTableIndex; + UCHAR St_CRT2CRTC; + UCHAR St_ResInfo; + UCHAR VB_StTVFlickerIndex; + UCHAR VB_StTVEdgeIndex; + UCHAR VB_StTVYFilterIndex; +} SiS310_StStruct; +SiS310_StStruct SiS310_SModeIDTable[] = +{ + {0x01, 0x9208, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, + {0x01, 0x1210, 0x14, 0x01, 0x01, 0x00, 0x01, 0x00}, + {0x01, 0x1010, 0x17, 0x02, 0x02, 0x00, 0x01, 0x01}, + {0x03, 0x8208, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02}, + {0x03, 0x0210, 0x16, 0x01, 0x01, 0x00, 0x01, 0x02}, + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03}, + {0x05, 0x9209, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x06, 0x8209, 0x06, 0x00, 0x00, 0x00, 0x00, 0x05}, + {0x07, 0x0000, 0x07, 0x03, 0x03, 0x00, 0x01, 0x03}, + {0x07, 0x0000, 0x19, 0x02, 0x02, 0x00, 0x01, 0x03}, + {0x0d, 0x920a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x0e, 0x820a, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x05}, + {0x0f, 0x0202, 0x11, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0x10, 0x0212, 0x12, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0x11, 0x0212, 0x1a, 0x04, 0x04, 0x00, 0x00, 0x05}, + {0x12, 0x0212, 0x1b, 0x04, 0x04, 0x00, 0x00, 0x05}, + {0x13, 0x021b, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x04}, + {0x12, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x00, 0x05}, + {0x12, 0x0210, 0x18, 0x01, 0x01, 0x00, 0x00, 0x05}, + {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +typedef struct _SiS310_StandTableStruct { + UCHAR CRT_COLS; + UCHAR ROWS; + UCHAR CHAR_HEIGHT; + USHORT CRT_LEN; + UCHAR SR[4]; + UCHAR MISC; + UCHAR CRTC[0x19]; + UCHAR ATTR[0x14]; + UCHAR GRC[9]; +} SiS310_StandTableStruct; + +SiS310_StandTableStruct SiS310_StandTable[] = { +/* MD_0_200 */ + { + 0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_1_200 */ + { + 0x28, 0x18, 0x08, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_200 */ + { + 0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_3_200 */ + { + 0x50, 0x18, 0x08, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_4 */ + { + 0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff} + }, +/* MD_5 */ + { + 0x28, 0x18, 0x08, 0x4000, + {0x09, 0x03, 0x00, 0x02}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2, + 0xff}, + {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x03, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, + 0xff} + }, +/* MD_6 */ + { + 0x50, 0x18, 0x08, 0x4000, + {0x01, 0x01, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2, + 0xff}, + {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x01, 0x00, 0x01, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0xff} + }, +/* MD_7 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x00, 0x03, 0x00, 0x03}, + 0xa6, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff} + }, +/* MDA_DAC */ + { + 0x00, 0x00, 0x00, 0x0000, + {0x00, 0x00, 0x00, 0x15}, + 0x15, + {0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00, + 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15}, + {0x15, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f} + }, +/* CGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {0x11, 0x09, 0x15, 0x00}, + 0x10, + {0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, + 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x2a, 0x3a, + 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x10, + 0x04}, + {0x14, 0x01, 0x11, 0x09, 0x15, 0x00, 0x10, 0x04, + 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, 0x2e, + 0x3e, 0x2b, 0x3b, 0x2f}, + {0x3f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, + 0x3f} + }, +/* EGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {0x11, 0x05, 0x15, 0x20}, + 0x30, + {0x24, 0x34, 0x21, 0x31, 0x25, 0x35, 0x08, 0x18, + 0x0c, 0x1c, 0x09, 0x19, 0x0d, 0x1d, 0x28, 0x38, + 0x2c, 0x3c, 0x29, 0x39, 0x2d, 0x3d, 0x02, 0x12, + 0x06}, + {0x16, 0x03, 0x13, 0x07, 0x17, 0x22, 0x32, 0x26, + 0x36, 0x23, 0x33, 0x27, 0x37, 0x0a, 0x1a, 0x0e, + 0x1e, 0x0b, 0x1b, 0x0f}, + {0x1f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, + 0x3f} + }, +/* VGA_DAC */ + { + 0x00, 0x10, 0x04, 0x0114, + {0x11, 0x09, 0x15, 0x2a}, + 0x3a, + {0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x05, + 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x18, 0x1c, 0x20, + 0x24, 0x28, 0x2d, 0x32, 0x38, 0x3f, 0x00, 0x10, + 0x1f}, + {0x2f, 0x3f, 0x1f, 0x27, 0x2f, 0x37, 0x3f, 0x2d, + 0x31, 0x36, 0x3a, 0x3f, 0x00, 0x07, 0x0e, 0x15, + 0x1c, 0x0e, 0x11, 0x15}, + {0x18, 0x1c, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x00, + 0x04} + }, + { + 0x08, 0x0c, 0x10, 0x0a08, + {0x0c, 0x0e, 0x10, 0x0b}, + 0x0c, + {0x0d, 0x0f, 0x10, 0x10, 0x01, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x00, + 0x04, 0x04, 0x01, 0x00, 0x05, 0x02, 0x05, 0x00, + 0x06}, + {0x01, 0x06, 0x05, 0x06, 0x00, 0x08, 0x01, 0x08, + 0x00, 0x07, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} + }, +/* MD_D */ + { + 0x28, 0x18, 0x08, 0x2000, + {0x09, 0x0f, 0x00, 0x06}, + 0x63, + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_E */ + { + 0x50, 0x18, 0x08, 0x4000, + {0x01, 0x0f, 0x00, 0x06}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* ExtVGATable */ + { + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff} + }, +/* ROM_SAVEPTR */ + { + 0x9f, 0x3b, 0x00, 0x00c0, + {0x00, 0x00, 0x00, 0x00}, + 0x00, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x3f, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1a, 0x00, 0xac, 0x3e, 0x00, 0xc0, + 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} + }, +/* MD_F */ + { + 0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa2, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x0b, 0x00, 0x05, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, + 0xff} + }, +/* MD_10 */ + { + 0x50, 0x18, 0x0e, 0x8000, + {0x01, 0x0f, 0x00, 0x06}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_0_350 */ + { + 0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_1_350 */ + { + 0x28, 0x18, 0x0e, 0x0800, + {0x09, 0x03, 0x00, 0x02}, + 0xa3, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_350 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_3_350 */ + { + 0x50, 0x18, 0x0e, 0x1000, + {0x01, 0x03, 0x00, 0x02}, + 0xa3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x08, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_0_1_400 */ + { + 0x28, 0x18, 0x10, 0x0800, + {0x08, 0x03, 0x00, 0x02}, + 0x67, + {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_2_3_400 */ + { + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, + 0xff} + }, +/* MD_7_400 */ + { + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x66, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, + 0xff} + }, +/* MD_11 */ + { + 0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3, + 0xff}, + {0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, + 0xff} + }, +/* ExtEGATable */ + { + 0x50, 0x1d, 0x10, 0xa000, + {0x01, 0x0f, 0x00, 0x06}, + 0xe3, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x01, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0xff} + }, +/* MD_13 */ + { + 0x28, 0x18, 0x08, 0x2000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x63, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x41, 0x00, 0x0f, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, + 0xff} + } +}; + +typedef struct _SiS310_ExtStruct { + UCHAR Ext_ModeID; + USHORT Ext_ModeFlag; + USHORT Ext_ModeInfo; + USHORT Ext_Point; + USHORT Ext_VESAID; + UCHAR Ext_VESAMEMSize; + UCHAR Ext_RESINFO; + UCHAR VB_ExtTVFlickerIndex; + UCHAR VB_ExtTVEdgeIndex; + UCHAR VB_ExtTVYFilterIndex; + UCHAR REFindex; +} SiS310_ExtStruct; +SiS310_ExtStruct SiS310_EModeIDTable[] = { + + {0x6a, 0x2212, 0x0407, 0x3a81, 0x0102, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x2e, 0x0a1b, 0x0306, 0x3a57, 0x0101, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x2f, 0x0a1b, 0x0305, 0x3a50, 0x0100, 0x08, 0x05, 0x00, 0x00, 0x05, + 0x10}, + {0x30, 0x2a1b, 0x0407, 0x3a81, 0x0103, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x31, 0x0a1b, 0x030d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x32, 0x0a1b, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x33, 0x0a1d, 0x0a0d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x34, 0x2a1d, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x35, 0x0a1f, 0x0a0d, 0x3b85, 0x0000, 0x08, 0x0d, 0x00, 0x00, 0x06, + 0x11}, + {0x36, 0x2a1f, 0x0a0e, 0x3b8c, 0x0000, 0x08, 0x0e, 0x00, 0x00, 0x06, + 0x12}, + {0x37, 0x0212, 0x0508, 0x3aab, 0x0104, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x38, 0x0a1b, 0x0508, 0x3aab, 0x0105, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x3a, 0x0e3b, 0x0609, 0x3adc, 0x0107, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x3c, 0x063b, 0x070a, 0x3af2, 0x0130, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x3d, 0x067d, 0x070a, 0x3af2, 0x0131, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x40, 0x9a1c, 0x0000, 0x3a34, 0x010d, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x41, 0x9a1d, 0x0000, 0x3a34, 0x010e, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x43, 0x0a1c, 0x0306, 0x3a57, 0x0110, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x44, 0x0a1d, 0x0306, 0x3a57, 0x0111, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x46, 0x2a1c, 0x0407, 0x3a81, 0x0113, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x47, 0x2a1d, 0x0407, 0x3a81, 0x0114, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x49, 0x0a3c, 0x0508, 0x3aab, 0x0116, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x4a, 0x0a3d, 0x0508, 0x3aab, 0x0117, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x4c, 0x0e7c, 0x0609, 0x3adc, 0x0119, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x4d, 0x0e7d, 0x0609, 0x3adc, 0x011a, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x50, 0x9a1b, 0x0001, 0x3a3b, 0x0132, 0x08, 0x01, 0x00, 0x00, 0x04, + 0x26}, + {0x51, 0xba1b, 0x0103, 0x3a42, 0x0133, 0x08, 0x03, 0x00, 0x00, 0x07, + 0x27}, + {0x52, 0x9a1b, 0x0204, 0x3a49, 0x0134, 0x08, 0x04, 0x00, 0x00, 0x00, + 0x28}, + {0x56, 0x9a1d, 0x0001, 0x3a3b, 0x0135, 0x08, 0x01, 0x00, 0x00, 0x04, + 0x26}, + {0x57, 0xba1d, 0x0103, 0x3a42, 0x0136, 0x08, 0x03, 0x00, 0x00, 0x07, + 0x27}, + {0x58, 0x9a1d, 0x0204, 0x3a49, 0x0137, 0x08, 0x04, 0x00, 0x00, 0x00, + 0x28}, + {0x59, 0x9a1b, 0x0000, 0x3a34, 0x0138, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x25}, + {0x5d, 0x0a1d, 0x0305, 0x3a50, 0x0139, 0x08, 0x05, 0x00, 0x00, 0x07, + 0x10}, + {0x62, 0x0a3f, 0x0306, 0x3a57, 0x013a, 0x08, 0x06, 0x00, 0x00, 0x05, + 0x08}, + {0x63, 0x2a3f, 0x0407, 0x3a81, 0x013b, 0x08, 0x07, 0x00, 0x00, 0x07, + 0x00}, + {0x64, 0x0a7f, 0x0508, 0x3aab, 0x013c, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x13}, + {0x65, 0x0eff, 0x0609, 0x3adc, 0x013d, 0x08, 0x09, 0x00, 0x00, 0x00, + 0x1a}, + {0x66, 0x06ff, 0x070a, 0x3af2, 0x013e, 0x08, 0x0a, 0x00, 0x00, 0x00, + 0x1e}, + {0x68, 0x067b, 0x080b, 0x3b17, 0x013f, 0x08, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x69, 0x06fd, 0x080b, 0x3b17, 0x0140, 0x08, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x6b, 0x07ff, 0x080b, 0x3b17, 0x0141, 0x10, 0x0b, 0x00, 0x00, 0x00, + 0x29}, + {0x6c, 0x067b, 0x090c, 0x3b37, 0x0000, 0x08, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x6d, 0x06fd, 0x090c, 0x3b37, 0x0000, 0x10, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x6e, 0x07ff, 0x090c, 0x3b37, 0x0000, 0x10, 0x0c, 0x00, 0x00, 0x00, + 0x2f}, + {0x70, 0x2a1b, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x71, 0x0a1b, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x74, 0x0a1d, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x75, 0x0a3d, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x76, 0x2a1f, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x77, 0x0a1f, 0x0511, 0x3b63, 0x0000, 0x08, 0x11, 0x00, 0x00, 0x00, + 0x37}, + {0x78, 0x0a3f, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x79, 0x0a3b, 0x0612, 0x3b74, 0x0000, 0x08, 0x12, 0x00, 0x00, 0x00, + 0x3a}, + {0x7a, 0x2a1d, 0x0410, 0x3b52, 0x0000, 0x08, 0x10, 0x00, 0x00, 0x07, + 0x34}, + {0x7b, 0x0e3b, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0x7c, 0x0e7d, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0x7d, 0x0eff, 0x060f, 0x3ad0, 0x0000, 0x08, 0x0f, 0x00, 0x00, 0x00, + 0x3d}, + {0xff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00} +}; + +typedef struct _SiS310_Ext2Struct { + USHORT Ext_InfoFlag; + UCHAR Ext_CRT1CRTC; + UCHAR Ext_CRTVCLK; + UCHAR Ext_CRT2CRTC; + UCHAR ModeID; + USHORT XRes; + USHORT YRes; + USHORT ROM_OFFSET; +} SiS310_Ext2Struct; +SiS310_Ext2Struct SiS310_RefIndex[] = { + {0x005f, 0x0d, 0x03, 0x05, 0x6a, 800, 600, 0x3a81}, /* 0x0 */ + {0x0467, 0x0e, 0x04, 0x05, 0x6a, 800, 600, 0x3a86}, /* 0x1 */ + {0x0067, 0x0f, 0x08, 0x48, 0x6a, 800, 600, 0x3a8b}, /* 0x2 */ + {0x0067, 0x10, 0x07, 0x8b, 0x6a, 800, 600, 0x3a90}, /* 0x3 */ + {0x0147, 0x11, 0x0a, 0x00, 0x6a, 800, 600, 0x3a95}, /* 0x4 */ + {0x4147, 0x12, 0x0d, 0x00, 0x6a, 800, 600, 0x3a9a}, /* 0x5 */ + {0x4047, 0x13, 0x13, 0x00, 0x6a, 800, 600, 0x3a9f}, /* 0x6 */ + {0x4047, 0x14, 0x1c, 0x00, 0x6a, 800, 600, 0x3aa4}, /* 0x7 */ + {0xc05f, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x3a57}, /* 0x8 */ + {0xc067, 0x06, 0x02, 0x04, 0x2e, 640, 480, 0x3a5c}, /* 0x9 */ + {0xc067, 0x07, 0x02, 0x47, 0x2e, 640, 480, 0x3a61}, /* 0xa */ + {0xc067, 0x08, 0x03, 0x8a, 0x2e, 640, 480, 0x3a66}, /* 0xb */ + {0x4047, 0x09, 0x05, 0x00, 0x2e, 640, 480, 0x3a6b}, /* 0xc */ + {0x4047, 0x0a, 0x09, 0x00, 0x2e, 640, 480, 0x3a70}, /* 0xd */ + {0x4047, 0x0b, 0x0e, 0x00, 0x2e, 640, 480, 0x3a75}, /* 0xe */ + {0xc047, 0x0c, 0x15, 0x00, 0x2e, 640, 480, 0x3a7a}, /* 0xf */ + {0x407f, 0x04, 0x00, 0x00, 0x2f, 640, 400, 0x3a50}, /* 0x10 */ + {0xc00f, 0x3c, 0x01, 0x06, 0x31, 720, 480, 0x3b85}, /* 0x11 */ + {0x000f, 0x3d, 0x03, 0x06, 0x32, 720, 576, 0x3b8c}, /* 0x12 */ + {0x0187, 0x15, 0x06, 0x00, 0x37, 1024, 768, 0x3aab}, /* 0x13 */ + {0xc877, 0x16, 0x0b, 0x06, 0x37, 1024, 768, 0x3ab0}, /* 0x14 301b TV1024x768 */ + {0xc067, 0x17, 0x0f, 0x49, 0x37, 1024, 768, 0x3ab5}, /* 0x15 */ + {0x0267, 0x18, 0x11, 0x00, 0x37, 1024, 768, 0x3aba}, /* 0x16 */ + {0x0047, 0x19, 0x16, 0x8c, 0x37, 1024, 768, 0x3abf}, /* 0x17 */ + {0x4047, 0x1a, 0x1b, 0x00, 0x37, 1024, 768, 0x3ac4}, /* 0x18 */ + {0x4047, 0x1b, 0x1f, 0x00, 0x37, 1024, 768, 0x3ac9}, /* 0x19 */ + {0x0387, 0x1c, 0x11, 0x00, 0x3a, 1280, 1024, 0x3adc}, /* 0x1a */ + {0x0077, 0x1d, 0x19, 0x07, 0x3a, 1280, 1024, 0x3ae1}, /* 0x1b */ + {0x0047, 0x1e, 0x1e, 0x00, 0x3a, 1280, 1024, 0x3ae6}, /* 0x1c */ + {0x0007, 0x1f, 0x20, 0x00, 0x3a, 1280, 1024, 0x3aeb}, /* 0x1d */ + {0x0007, 0x20, 0x21, 0x00, 0x3c, 1600, 1200, 0x3af2}, /* 0x1e */ + {0x0007, 0x21, 0x22, 0x00, 0x3c, 1600, 1200, 0x3af7}, /* 0x1f */ + {0x0007, 0x22, 0x23, 0x00, 0x3c, 1600, 1200, 0x3afc}, /* 0x20 */ + {0x0007, 0x23, 0x25, 0x00, 0x3c, 1600, 1200, 0x3b01}, /* 0x21 */ + {0x0007, 0x24, 0x26, 0x00, 0x3c, 1600, 1200, 0x3b06}, /* 0x22 */ + {0x0007, 0x25, 0x2c, 0x00, 0x3c, 1600, 1200, 0x3b0b}, /* 0x23 */ + {0x0007, 0x26, 0x34, 0x00, 0x3c, 1600, 1200, 0x3b10}, /* 0x24 */ + {0x407f, 0x00, 0x00, 0x00, 0x40, 320, 200, 0x3a34}, /* 0x25 */ + {0xc07f, 0x01, 0x00, 0x04, 0x50, 320, 240, 0x3a3b}, /* 0x26 */ + {0x007f, 0x02, 0x04, 0x05, 0x51, 400, 300, 0x3a42}, /* 0x27 */ + {0xc077, 0x03, 0x0b, 0x06, 0x52, 512, 384, 0x3a49}, /* 0x28 */ + {0x8007, 0x27, 0x27, 0x00, 0x68, 1920, 1440, 0x3b17}, /* 0x29 */ + {0x4007, 0x28, 0x29, 0x00, 0x68, 1920, 1440, 0x3b1c}, /* 0x2a */ + {0x4007, 0x29, 0x2e, 0x00, 0x68, 1920, 1440, 0x3b21}, /* 0x2b */ + {0x4007, 0x2a, 0x30, 0x00, 0x68, 1920, 1440, 0x3b26}, /* 0x2c */ + {0x4007, 0x2b, 0x35, 0x00, 0x68, 1920, 1440, 0x3b2b}, /* 0x2d */ + {0x4005, 0x2c, 0x39, 0x00, 0x68, 1920, 1440, 0x3b30}, /* 0x2e */ + {0x4007, 0x2d, 0x2b, 0x00, 0x6c, 2048, 1536, 0x3b37}, /* 0x2f */ + {0x4007, 0x2e, 0x31, 0x00, 0x6c, 2048, 1536, 0x3b3c}, /* 0x30 */ + {0x4007, 0x2f, 0x33, 0x00, 0x6c, 2048, 1536, 0x3b41}, /* 0x31 */ + {0x4007, 0x30, 0x37, 0x00, 0x6c, 2048, 1536, 0x3b46}, /* 0x32 */ + {0x4005, 0x31, 0x38, 0x00, 0x6c, 2048, 1536, 0x3b4b}, /* 0x33 */ + {0x0057, 0x32, 0x40, 0x08, 0x70, 800, 480, 0x3b52}, /* 0x34 */ + {0x0047, 0x33, 0x07, 0x08, 0x70, 800, 480, 0x3b57}, /* 0x35 */ + {0x0047, 0x34, 0x0a, 0x08, 0x70, 800, 480, 0x3b5c}, /* 0x36 */ + {0x0057, 0x35, 0x0b, 0x09, 0x71, 1024, 576, 0x3b63}, /* 0x37 */ + {0x0047, 0x36, 0x11, 0x09, 0x71, 1024, 576, 0x3b68}, /* 0x38 */ + {0x0047, 0x37, 0x16, 0x09, 0x71, 1024, 576, 0x3b6d}, /* 0x39 */ + {0x0057, 0x38, 0x19, 0x0a, 0x75, 1280, 720, 0x3b74}, /* 0x3a */ + {0x0047, 0x39, 0x1e, 0x0a, 0x75, 1280, 720, 0x3b79}, /* 0x3b */ + {0x0047, 0x3a, 0x20, 0x0a, 0x75, 1280, 720, 0x3b7e}, /* 0x3c */ + {0x0027, 0x3b, 0x19, 0x08, 0x7b, 1280, 960, 0x3ad0}, /* 0x3d */ + {0x0027, 0x3b, 0x19, 0x08, 0x7b, 1280, 960, 0x3ad5}, /* 0x3e */ + {0xffff, 0x00, 0x00, 0x00, 0x00, 0000, 0000, 0x0000} +}; + +typedef struct _SiS310_CRT1TableStruct { + UCHAR CR[17]; +} SiS310_CRT1TableStruct; +SiS310_CRT1TableStruct SiS310_CRT1Table[] = { + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, + 0x00}, /* 0x0 */ + {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}, /* 0x1 */ + {0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}, /* 0x2 */ + {0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}, /* 0x3 */ + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}, /* 0x4 */ + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}, /* 0x5 */ + {0x63, 0x4f, 0x50, 0x86, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8b, 0xdf, 0xe7, 0xff, 0x10, 0x00, 0x01, + 0x00}, /* 0x6 */ + {0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}, /* 0x7 */ + {0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}, /* 0x8 */ + {0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x00, 0x00, 0x05, + 0x61}, /* 0x9 */ + {0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, + 0x61}, /* 0xa */ + {0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x10, 0x00, 0x05, + 0x61}, /* 0xb */ + {0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xe5, 0xe5, 0xfc, 0x00, 0x00, 0x01, + 0x00}, /* 0xc */ + {0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}, /* 0xd */ + {0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}, /* 0xe */ + {0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}, /* 0xf */ + {0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}, /* 0x10 */ + {0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}, /* 0x11 */ + {0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, + 0x61}, /* 0x12 */ + {0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, + 0x61}, /* 0x13 */ + {0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, + 0x61}, /* 0x14 */ + {0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}, /* 0x15 */ + {0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}, /* 0x16 */ + {0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}, /* 0x17 */ + {0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}, /* 0x18 */ + {0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}, /* 0x19 */ + {0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, + 0x62}, /* 0x1a */ + {0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, + 0x62}, /* 0x1b */ + {0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}, /* 0x1c */ + {0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}, /* 0x1d */ + {0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}, /* 0x1e */ + {0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}, /* 0x1f */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x20 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x21 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x22 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x23 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x24 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x25 */ + {0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}, /* 0x26 */ + {0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}, /* 0x27 */ + {0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, + 0x63}, /* 0x28 */ + {0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, + 0x63}, /* 0x29 */ + {0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}, /* 0x2a */ + {0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}, /* 0x2b */ + {0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}, /* 0x2c */ + {0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, + 0x44}, /* 0x2d */ + {0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, + 0x44}, /* 0x2e */ + {0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, + 0x44}, /* 0x2f */ + {0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, + 0x44}, /* 0x30 */ + {0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}, /* 0x31 */ + {0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}, /* 0x32 */ + {0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}, /* 0x33 */ + {0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}, /* 0x34 */ + {0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}, /* 0x35 */ + {0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}, /* 0x36 */ + {0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x15, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}, /* 0x37 */ + {0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}, /* 0x38 */ + {0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}, /* 0x39 */ + {0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}, /* 0x3a */ + {0xdc, 0x9f, 0x9f, 0x00, 0xab, 0x19, 0xe6, 0xef, + 0xc0, 0xc3, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}, /* 0x3b */ + {0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}, /* 0x3c */ + {0x7b, 0x59, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x3f, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01} /* 0x3d */ +}; + +typedef struct _SiS310_MCLKDataStruct { + UCHAR SR28, SR29, SR2A; + USHORT CLOCK; +} SiS310_MCLKDataStruct; +SiS310_MCLKDataStruct SiS310_MCLKData[] = { + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166} +}; + +typedef struct _SiS310_ECLKDataStruct { + UCHAR SR2E, SR2F, SR30; + USHORT CLOCK; +} SiS310_ECLKDataStruct; +SiS310_ECLKDataStruct SiS310_ECLKData[] = { + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166}, + {0x5c, 0x23, 0x01, 166} +}; + +typedef struct _SiS310_VCLKDataStruct { + UCHAR SR2B, SR2C; + USHORT CLOCK; +} SiS310_VCLKDataStruct; +SiS310_VCLKDataStruct SiS310_VCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x0 */ + {0x4e, 0xe4, 28}, /* 0x1 */ + {0x57, 0xe4, 31}, /* 0x2 */ + {0xc3, 0xc8, 36}, /* 0x3 */ + {0x42, 0xe2, 40}, /* 0x4 */ + {0xfe, 0xcd, 43}, /* 0x5 */ + {0x5d, 0xc4, 44}, /* 0x6 */ + {0x52, 0xe2, 49}, /* 0x7 */ + {0x53, 0xe2, 50}, /* 0x8 */ + {0x74, 0x67, 52}, /* 0x9 */ + {0x6d, 0x66, 56}, /* 0xa */ + {0x6c, 0xc3, 65}, /* 0xb */ + {0x46, 0x44, 67}, /* 0xc */ + {0xb1, 0x46, 68}, /* 0xd */ + {0xd3, 0x4a, 72}, /* 0xe */ + {0x29, 0x61, 75}, /* 0xf */ + {0x6e, 0x46, 76}, /* 0x10 */ + {0x2b, 0x61, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x41, 104}, /* 0x17 */ + {0x3a, 0x23, 105}, /* 0x18 */ + {0x70, 0x44, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0x54, 0x42, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x62, 0x06, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a */ + {0x52, 0x6a, 27}, /* 0x3b */ + {0x62, 0x24, 70}, /* 0x3c */ + {0x62, 0x64, 70}, /* 0x3d */ + {0xa8, 0x4c, 30}, /* 0x3e */ + {0x20, 0x26, 33}, /* 0x3f */ + {0x31, 0xc2, 39} /* 0x40 */ +}; + +typedef struct _SiS310_VBVCLKDataStruct { + UCHAR Part4_A, Part4_B; + USHORT CLOCK; +} SiS310_VBVCLKDataStruct; +SiS310_VBVCLKDataStruct SiS310_VBVCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x0 */ + {0x4e, 0xe4, 28}, /* 0x1 */ + {0x57, 0xe4, 31}, /* 0x2 */ + {0xc3, 0xc8, 36}, /* 0x3 */ + {0x42, 0x47, 40}, /* 0x4 */ + {0xfe, 0xcd, 43}, /* 0x5 */ + {0x5d, 0xc4, 44}, /* 0x6 */ + {0x52, 0x47, 49}, /* 0x7 */ + {0x53, 0x47, 50}, /* 0x8 */ + {0x74, 0x67, 52}, /* 0x9 */ + {0x6d, 0x66, 56}, /* 0xa */ + {0x5a, 0x64, 65}, /* 0xb */ + {0x46, 0x44, 67}, /* 0xc */ + {0xb1, 0x46, 68}, /* 0xd */ + {0xd3, 0x4a, 72}, /* 0xe */ + {0x29, 0x61, 75}, /* 0xf */ + {0x6d, 0x46, 75}, /* 0x10 */ + {0x41, 0x43, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x22, 104}, /* 0x17 */ + {0x49, 0x24, 105}, /* 0x18 */ + {0xf8, 0x2f, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0xd4, 0x28, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x70, 0x07, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a */ + {0x52, 0x6a, 27}, /* 0x3b */ + {0x62, 0x24, 70}, /* 0x3c */ + {0x62, 0x64, 70}, /* 0x3d */ + {0xa8, 0x4c, 30}, /* 0x3e */ + {0x20, 0x26, 33}, /* 0x3f */ + {0x31, 0xc2, 39} /* 0x40 */ +}; + +UCHAR SiS310_ScreenOffset[] = + { 0x14, 0x19, 0x20, 0x28, 0x32, 0x40, 0x50, 0x64, 0x78, 0x80, 0x2d, 0x35 }; + +typedef struct _SiS310_StResInfoStruct { + USHORT HTotal; + USHORT VTotal; +} SiS310_StResInfoStruct; +SiS310_StResInfoStruct SiS310_StResInfo[] = { + {640, 400}, + {640, 350}, + {720, 400}, + {720, 350}, + {640, 480} +}; + +typedef struct _SiS310_ModeResInfoStruct { + USHORT HTotal; + USHORT VTotal; + UCHAR XChar; + UCHAR YChar; +} SiS310_ModeResInfoStruct; +SiS310_ModeResInfoStruct SiS310_ModeResInfo[] = { + {320, 200, 8, 8}, + {320, 240, 8, 8}, + {320, 400, 8, 8}, + {400, 300, 8, 8}, + {512, 384, 8, 8}, + {640, 400, 8, 16}, + {640, 480, 8, 16}, + {800, 600, 8, 16}, + {1024, 768, 8, 16}, + {1280, 1024, 8, 16}, + {1600, 1200, 8, 16}, + {1920, 1440, 8, 16}, + {2048, 1536, 8, 16}, + {720, 480, 8, 16}, + {720, 576, 8, 16}, + {1280, 960, 8, 16}, + {800, 480, 8, 16}, + {1024, 576, 8, 16}, + {1280, 720, 8, 16} +}; + +UCHAR SiS310_OutputSelect = 0; +UCHAR SiS310_SoftSetting = 30; +UCHAR SiS310_SR07 = 0x18; +UCHAR SiS310_SR15[8][4] = { + {0x0, 0x4, 0x60, 0x60}, + {0xf, 0xf, 0xf, 0xf}, + {0xba, 0xba, 0xba, 0xba}, + {0xa9, 0xa9, 0xac, 0xac}, + {0xa0, 0xa0, 0xa0, 0xa8}, + {0x0, 0x0, 0x2, 0x2}, + {0x30, 0x30, 0x40, 0x40}, + {0x0, 0xa5, 0xfb, 0xf6} +}; +UCHAR SiS310_CR40[5][4] = { + {0x77, 0x77, 0x33, 0x33}, + {0x77, 0x77, 0x33, 0x33}, + {0x0, 0x0, 0x0, 0x0}, + {0x5b, 0x5b, 0x3, 0x3}, + {0x0, 0x0, 0xf0, 0xf8} +}; +UCHAR SiS310_CR49[] = { 0xaa, 0x88 }; +UCHAR SiS310_SR1F = 0x0; +UCHAR SiS310_SR21 = 0xa5; +UCHAR SiS310_SR22 = 0xfb; +UCHAR SiS310_SR23 = 0xf6; +UCHAR SiS310_SR24 = 0xd; +UCHAR SiS310_SR25[] = { 0x33, 0x3 }; +UCHAR SiS310_SR31 = 0x0; +UCHAR SiS310_SR32 = 0x11; +UCHAR SiS310_SR33 = 0x0; +UCHAR SiS310_CRT2Data_1_2 = 0x0; +UCHAR SiS310_CRT2Data_4_D = 0x0; +UCHAR SiS310_CRT2Data_4_E = 0x0; +UCHAR SiS310_CRT2Data_4_10 = 0x80; +USHORT SiS310_RGBSenseData = 0xd1; +USHORT SiS310_VideoSenseData = 0xb9; +USHORT SiS310_YCSenseData = 0xb3; +USHORT SiS310_RGBSenseData2 = 0x0190; /*301b */ +USHORT SiS310_VideoSenseData2 = 0x0174; +USHORT SiS310_YCSenseData2 = 0x016b; +UCHAR SiS310_NTSCPhase[] = { 0x21, 0xed, 0x8a, 0x8 }; + +UCHAR SiS310_PALPhase[] = { 0x2a, 0x5, 0xd3, 0x0 }; + +typedef struct _SiS310_LCDDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS310_LCDDataStruct; +SiS310_LCDDataStruct SiS310_StLCD1024x768Data[] = { + {62, 25, 800, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {104, 45, 945, 496, 1344, 806}, + {62, 25, 800, 546, 1344, 806}, + {31, 18, 1008, 624, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_ExtLCD1024x768Data[] = { + {12, 5, 896, 512, 1344, 806}, + {12, 5, 896, 510, 1344, 806}, + {32, 15, 1008, 505, 1344, 806}, + {32, 15, 1008, 514, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806}, + {12, 5, 896, 500, 1344, 806}, + {42, 25, 1024, 625, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_St2LCD1024x768Data[] = { + {62, 25, 800, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {32, 15, 930, 546, 1344, 806}, + {104, 45, 945, 496, 1344, 806}, + {62, 25, 800, 546, 1344, 806}, + {31, 18, 1008, 624, 1344, 806}, + {1, 1, 1344, 806, 1344, 806} +}; + +SiS310_LCDDataStruct SiS310_StLCD1280x1024Data[] = { + {22, 5, 800, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_ExtLCD1280x1024Data[] = { + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 501, 1688, 1066}, + {211, 60, 1024, 508, 1688, 1066}, + {211, 60, 1024, 500, 1688, 1066}, + {211, 75, 1024, 625, 1688, 1066}, + {211, 120, 1280, 798, 1688, 1066}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_St2LCD1280x1024Data[] = { + {22, 5, 800, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {176, 45, 900, 510, 1650, 1088}, + {22, 5, 800, 510, 1650, 1088}, + {13, 5, 1024, 675, 1560, 1152}, + {16, 9, 1266, 804, 1688, 1072}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_NoScaleData[] = { + {1, 1, 800, 449, 800, 449}, + {1, 1, 800, 449, 800, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 900, 449, 900, 449}, + {1, 1, 800, 525, 800, 525}, + {1, 1, 1056, 628, 1056, 628}, + {1, 1, 1344, 806, 1344, 806}, + {1, 1, 1688, 1066, 1688, 1066} +}; + +SiS310_LCDDataStruct SiS310_LCD1280x960Data[] = { + {9, 2, 800, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {4, 1, 900, 500, 1800, 1000}, + {9, 2, 800, 500, 1800, 1000}, + {30, 11, 1056, 625, 1800, 1000}, + {5, 3, 1350, 800, 1800, 1000}, + {1, 1, 1576, 1050, 1576, 1050}, + {1, 1, 1800, 1000, 1800, 1000} +}; + +typedef struct _SiS310_TVDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT TVHDE; + USHORT TVVDE; + USHORT RVBHRS; + UCHAR FlickerMode; + USHORT HALFRVBHRS; + UCHAR RY1COE; + UCHAR RY2COE; + UCHAR RY3COE; + UCHAR RY4COE; +} SiS310_TVDataStruct; +SiS310_TVDataStruct SiS310_StPALData[] = { + {1, 1, 864, 525, 1270, 400, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 350, 100, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 864, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 864, 525, 1270, 480, 50, 0, 760, 0xf4, 0xff, 0x1c, 0x22}, + {1, 1, 864, 525, 1270, 600, 50, 0, 0, 0xf4, 0xff, 0x1c, 0x22} +}; + +SiS310_TVDataStruct SiS310_ExtPALData[] = { + {27, 10, 848, 448, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {108, 35, 848, 398, 1270, 530, 50, 0, 50, 0xf4, 0xff, 0x1c, 0x22}, + {12, 5, 954, 448, 1270, 530, 50, 0, 50, 0xf1, 0x04, 0x1f, 0x18}, + {9, 4, 960, 463, 1644, 438, 50, 0, 50, 0xf4, 0x0b, 0x1c, 0x0a}, + {9, 4, 848, 528, 1270, 530, 0, 0, 50, 0xf5, 0xfb, 0x1b, 0x2a}, + {36, 25, 1060, 648, 1316, 530, 438, 0, 438, 0xeb, 0x05, 0x25, 0x16}, + {3, 2, 1080, 619, 1270, 540, 438, 0, 438, 0xf3, 0x00, 0x1d, 0x20}, + {1, 1, 1170, 821, 1270, 520, 686, 0, 686, 0xF3, 0x00, 0x1D, 0x20} /*301b */ +}; + +SiS310_TVDataStruct SiS310_StNTSCData[] = { + {1, 1, 858, 525, 1270, 400, 50, 0, 760, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 50, 0, 640, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 400, 0, 0, 720, 0xf1, 0x04, 0x1f, 0x18}, + {1, 1, 858, 525, 1270, 350, 0, 0, 720, 0xf4, 0x0b, 0x1c, 0x0a}, + {1, 1, 858, 525, 1270, 480, 0, 0, 760, 0xf1, 0x04, 0x1f, 0x18} +}; + +SiS310_TVDataStruct SiS310_ExtNTSCData[] = { + {143, 65, 858, 443, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {88, 35, 858, 393, 1270, 440, 171, 0, 171, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 443, 1270, 440, 92, 0, 92, 0xf1, 0x04, 0x1f, 0x18}, + {143, 70, 924, 393, 1270, 440, 92, 0, 92, 0xf4, 0x0b, 0x1c, 0x0a}, + {143, 76, 836, 523, 1270, 440, 224, 0, 0, 0xf1, 0x05, 0x1f, 0x16}, + {143, 120, 1056, 643, 1288, 440, 0, 128, 0, 0xf4, 0x10, 0x1c, 0x00}, + {2, 1, 858, 503, 1270, 480, 0, 128, 0, 0xee, 0x0c, 0x22, 0x08}, + {65, 64, 1056, 791, 1270, 480, 638, 0, 0, 0xEE, 0x0C, 0x22, 0x08} /*301b */ +}; + +SiS310_TVDataStruct SiS310_St1HiTVData[] = { + 0x00 +}; + +SiS310_TVDataStruct SiS310_St2HiTVData[] = { + 0x00 +}; + +SiS310_TVDataStruct SiS310_ExtHiTVData[] = { + 0x00 +}; + +UCHAR SiS310_NTSCTiming[] = { + 0x17, 0x1d, 0x03, 0x09, 0x05, 0x06, 0x0c, 0x0c, + 0x94, 0x49, 0x01, 0x0a, 0x06, 0x0d, 0x04, 0x0a, + 0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x1b, + 0x0c, 0x50, 0x00, 0x97, 0x00, 0xda, 0x4a, 0x17, + 0x7d, 0x05, 0x4b, 0x00, 0x00, 0xe2, 0x00, 0x02, + 0x03, 0x0a, 0x65, 0x9d, 0x08, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x50, + 0x00, 0x40, 0x44, 0x00, 0xdb, 0x02, 0x3b, 0x00 +}; + +UCHAR SiS310_PALTiming[] = { + 0x19, 0x52, 0x35, 0x6e, 0x04, 0x38, 0x3d, 0x70, + 0x94, 0x49, 0x01, 0x12, 0x06, 0x3e, 0x35, 0x6d, + 0x06, 0x14, 0x3e, 0x35, 0x6d, 0x00, 0x45, 0x2b, + 0x70, 0x50, 0x00, 0x9b, 0x00, 0xd9, 0x5d, 0x17, + 0x7d, 0x05, 0x45, 0x00, 0x00, 0xe8, 0x00, 0x02, + 0x0d, 0x00, 0x68, 0xb0, 0x0b, 0x92, 0x8f, 0x40, + 0x60, 0x80, 0x14, 0x90, 0x8c, 0x60, 0x14, 0x63, + 0x00, 0x40, 0x3e, 0x00, 0xe1, 0x02, 0x28, 0x00 +}; + +UCHAR SiS310_HiTVExtTiming[] = { 0x00 }; + +UCHAR SiS310_HiTVSt1Timing[] = { 0x00 }; + +UCHAR SiS310_HiTVSt2Timing[] = { 0x00 }; + +UCHAR SiS310_HiTVTextTiming[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Data[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Simu[] = { 0x00 }; + +UCHAR SiS310_HiTVGroup3Text[] = { 0x00 }; + +typedef struct _SiS310_PanelDelayTblStruct { + UCHAR timer[2]; +} SiS310_PanelDelayTblStruct; +SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[] = { {0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00}, +{0x00, 0x00} +}; + +typedef struct _SiS310_LVDSDataStruct { + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS310_LVDSDataStruct; +SiS310_LVDSDataStruct SiS310_LVDS800x600Data_1[] = { + {848, 433, 1060, 629}, + {848, 389, 1060, 629}, + {848, 433, 1060, 629}, + {848, 389, 1060, 629}, + {848, 518, 1060, 629}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {800, 449, 1000, 644}, + {800, 525, 1000, 635} +}; + +SiS310_LVDSDataStruct SiS310_LVDS800x600Data_2[] = { + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {800, 449, 1000, 644}, + {800, 525, 1000, 635} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1024x768Data_1[] = { + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 518, 1344, 806}, + {1050, 638, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1024x768Data_2[] = { + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1280x1024Data_1[] = { + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 438, 1344, 806}, + {840, 409, 1344, 806}, + {840, 518, 1344, 806}, + {1050, 638, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS1280x1024Data_2[] = { + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {1344, 806, 1344, 806}, + {800, 449, 1280, 801}, + {800, 525, 1280, 813} +}; + +SiS310_LVDSDataStruct SiS310_LVDS640x480Data_1[] = { + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 449, 800, 449}, + {800, 525, 800, 525}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628}, + {1056, 628, 1056, 628} +}; + +SiS310_LVDSDataStruct SiS310_CHTVUNTSCData[] = { + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {840, 600, 840, 600}, + {784, 600, 784, 600}, + {1064, 750, 1064, 750} +}; + +SiS310_LVDSDataStruct SiS310_CHTVONTSCData[] = { + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {840, 525, 840, 525}, + {784, 525, 784, 525}, + {1040, 700, 1040, 700} +}; + +SiS310_LVDSDataStruct SiS310_CHTVUPALData[] = { + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {840, 750, 840, 750}, + {936, 836, 936, 836} +}; + +SiS310_LVDSDataStruct SiS310_CHTVOPALData[] = { + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {1008, 625, 1008, 625}, + {840, 625, 840, 625}, + {960, 750, 960, 750} +}; + +typedef struct _SiS310_LVDSDesStruct { + USHORT LCDHDES; + USHORT LCDVDES; +} SiS310_LVDSDesStruct; +SiS310_LVDSDesStruct SiS310_PanelType00_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType01_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType02_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType03_1[] = { + {8, 436}, + {8, 440}, + {8, 436}, + {8, 440}, + {8, 512}, + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794} +}; + +SiS310_LVDSDesStruct SiS310_PanelType04_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType05_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType06_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType07_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType08_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType09_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0a_1[] = { + {1059, 626}, + {1059, 624}, + {1059, 626}, + {1059, 624}, + {1059, 624}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0b_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0c_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0d_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0e_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0f_1[] = { + {1343, 798}, + {1343, 794}, + {1343, 798}, + {1343, 794}, + {1343, 0}, + {1343, 0}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType00_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType01_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType02_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType03_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {1152, 622}, + {1152, 597} +}; + +SiS310_LVDSDesStruct SiS310_PanelType04_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType05_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType06_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType07_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType08_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType09_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0a_2[] = { + {976, 527}, + {976, 502}, + {976, 527}, + {976, 502}, + {976, 567}, + {0, 627}, + {0, 627}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0b_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0c_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0d_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0e_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_PanelType0f_2[] = { + {1152, 622}, + {1152, 597}, + {1152, 622}, + {1152, 597}, + {1152, 662}, + {1232, 722}, + {0, 805}, + {0, 794}, + {0, 0} +}; +/*301b*/ +SiS310_LVDSDesStruct SiS310_PanelType1076_1[] = { + 0x00, 0x00 +}; +SiS310_LVDSDesStruct SiS310_PanelType1210_1[] = { + 0x00, 0x00 +}; +SiS310_LVDSDesStruct SiS310_PanelType1296_1[] = { + 0x00, 0x00 +}; +SiS310_LVDSDesStruct SiS310_PanelType1076_2[] = { + 0x00, 0x00 +}; +SiS310_LVDSDesStruct SiS310_PanelType1210_2[] = { + 0x00, 0x00 +}; +SiS310_LVDSDesStruct SiS310_PanelType1296_2[] = { + 0x00, 0x00 +}; +/*end 301b*/ + +SiS310_LVDSDesStruct SiS310_CHTVUNTSCDesData[] = { + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVONTSCDesData[] = { + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVUPALDesData[] = { + {256, 0}, + {256, 0}, + {256, 0}, + {256, 0}, + {0, 0}, + {0, 0} +}; + +SiS310_LVDSDesStruct SiS310_CHTVOPALDesData[] = { + {256, 0}, + {256, 0}, + {256, 0}, + {256, 0}, + {0, 0}, + {0, 0} +}; + +typedef struct _SiS310_LVDSCRT1DataStruct { + UCHAR CR[17]; +} SiS310_LVDSCRT1DataStruct; +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1[] = + { {0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}, +{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}, +{0x65, 0x4f, 0x89, 0x56, 0x83, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x05, + 0x00}, +{0x65, 0x4f, 0x89, 0x56, 0x83, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x05, + 0x00}, +{0x65, 0x4f, 0x89, 0x56, 0x83, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x05, + 0x00}, +{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1[] = + { {0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}, +{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}, +{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x05, + 0x00}, +{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x97, 0x1f, + 0x60, 0x87, 0x5d, 0x5d, 0x83, 0x10, 0x00, 0x05, + 0x00}, +{0x73, 0x4f, 0x4f, 0x97, 0x55, 0x86, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0xDf, 0x05, 0x00, 0x00, 0x05, + 0x00}, +{0x87, 0x63, 0x63, 0x8B, 0x69, 0x1A, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x57, 0x7D, 0x20, 0x00, 0x26, + 0x01}, +{0xA3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0xFf, 0x25, 0x10, 0x00, 0x02, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1[] = + { {0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}, +{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}, +{0x63, 0x4f, 0x87, 0x54, 0x9f, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x01, + 0x00}, +{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x01, + 0x00}, +{0x63, 0x4f, 0x87, 0x54, 0x9f, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x01, + 0x00}, +{0x7e, 0x63, 0x82, 0x68, 0x15, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x26, + 0x01}, +{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1_H[] = + { {0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}, +{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}, +{0x30, 0x27, 0x94, 0x2c, 0x92, 0xaf, 0x1f, + 0x90, 0x85, 0x8f, 0xab, 0x30, 0x00, 0x04, + 0x00}, +{0x30, 0x27, 0x94, 0x2c, 0x92, 0x83, 0x1f, + 0x5e, 0x83, 0x5d, 0x79, 0x10, 0x00, 0x04, + 0x00}, +{0x30, 0x27, 0x94, 0x2c, 0x92, 0x04, 0x3e, + 0xe0, 0x85, 0xdf, 0xfb, 0x10, 0x00, 0x04, + 0x00}, +{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1_H[] = + { {0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}, +{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}, +{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0xc4, 0x1f, + 0x92, 0x89, 0x8f, 0x8f, 0xb5, 0x30, 0x00, 0x44, + 0x00}, +{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x97, 0x1f, + 0x60, 0x87, 0x5D, 0x5D, 0x83, 0x01, 0x00, 0x44, + 0x00}, +{0x37, 0x27, 0x27, 0x9B, 0x2b, 0x94, 0x04, 0x3e, + 0xE2, 0x89, 0xDf, 0xDf, 0x05, 0x00, 0x00, 0x44, + 0x00}, +{0x41, 0x31, 0x31, 0x85, 0x35, 0x1d, 0x7c, 0xf0, + 0x5A, 0x8F, 0x57, 0x57, 0x7D, 0x20, 0x00, 0x55, + 0x01}, +{0x4f, 0x3F, 0x3F, 0x93, 0x45, 0x0D, 0x24, 0xf5, + 0x02, 0x88, 0xFf, 0xFf, 0x25, 0x10, 0x00, 0x01, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1_H[] = + { {0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}, +{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}, +{0x2f, 0x27, 0x93, 0x2b, 0x90, 0xb4, 0x1f, + 0x92, 0x89, 0x8f, 0xb5, 0x30, 0x00, 0x04, + 0x00}, +{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x82, 0x1f, + 0x60, 0x87, 0x5d, 0x83, 0x10, 0x00, 0x04, + 0x00}, +{0x2f, 0x27, 0x93, 0x2b, 0x90, 0x04, 0x3e, + 0xe2, 0x89, 0xdf, 0x05, 0x00, 0x00, 0x04, + 0x00}, +{0x3c, 0x31, 0x80, 0x35, 0x1c, 0x7c, 0xf0, + 0x5a, 0x8f, 0x57, 0x7d, 0x20, 0x00, 0x55, + 0x01}, +{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2[] = + { {0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}, +{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}, +{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x06, + 0x00}, +{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x06, + 0x00}, +{0x7f, 0x4f, 0x83, 0x62, 0x12, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x00}, +{0x7f, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2[] = + { {0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}, +{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2[] = + { {0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x4f, 0x87, 0x6e, 0x9f, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x06, + 0x00}, +{0xa3, 0x63, 0x87, 0x78, 0x89, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x02, + 0x01}, +{0xa3, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2_H[] = + { {0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}, +{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}, +{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0x3e, + 0xf4, 0x88, 0x8f, 0x73, 0x20, 0x00, 0x05, + 0x00}, +{0x3d, 0x27, 0x81, 0x3a, 0x1a, 0x72, 0x3e, + 0xdb, 0x8f, 0x5d, 0x73, 0x20, 0x00, 0x05, + 0x00}, +{0x3d, 0x27, 0x81, 0x32, 0x1a, 0x72, 0xba, + 0x1c, 0x80, 0xdf, 0x73, 0x00, 0x00, 0x05, + 0x00}, +{0x3d, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2_H[] = + { {0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x01, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x31, 0x93, 0x3e, 0x06, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}, +{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2_H[] = + { {0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x4a, 0x80, 0x8f, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x31, 0x87, 0x5d, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x27, 0x93, 0x39, 0x81, 0x24, 0xbb, + 0x72, 0x88, 0xdf, 0x25, 0x30, 0x00, 0x01, + 0x00}, +{0x4f, 0x31, 0x93, 0x3e, 0x86, 0x24, 0xf1, + 0xae, 0x84, 0x57, 0x25, 0x30, 0x00, 0x01, + 0x01}, +{0x4f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1UNTSC[] = + { {0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xe8, 0x84, 0x8f, 0x57, 0x20, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xd0, 0x82, 0x5d, 0x57, 0x00, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xe8, 0x84, 0x8f, 0x57, 0x20, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x56, 0x9f, 0x56, 0x3e, + 0xd0, 0x82, 0x5d, 0x57, 0x00, 0x00, 0x01, + 0x00}, +{0x5d, 0x4f, 0x81, 0x53, 0x9c, 0x56, 0xba, + 0x18, 0x84, 0xdf, 0x57, 0x00, 0x00, 0x01, + 0x00}, +{0x80, 0x63, 0x84, 0x6c, 0x17, 0xec, 0xf0, + 0x90, 0x8c, 0x57, 0xed, 0x20, 0x00, 0x06, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1ONTSC[] = + { {0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xc0, 0x84, 0x8f, 0x0c, 0x20, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xb0, 0x8d, 0x5d, 0x0c, 0x00, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xc0, 0x84, 0x8f, 0x0c, 0x20, 0x00, 0x01, + 0x00}, +{0x64, 0x4f, 0x88, 0x5a, 0x9f, 0x0b, 0x3e, + 0xb0, 0x8d, 0x5d, 0x0c, 0x00, 0x00, 0x01, + 0x00}, +{0x5d, 0x4f, 0x81, 0x56, 0x9c, 0x0b, 0x3e, + 0xe8, 0x84, 0xdf, 0x0c, 0x00, 0x00, 0x01, + 0x00}, +{0x7d, 0x63, 0x81, 0x6a, 0x16, 0xba, 0xf0, + 0x7f, 0x86, 0x57, 0xbb, 0x00, 0x00, 0x06, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1UPAL[] = + { {0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf8, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf8, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}, +{0x64, 0x4f, 0x88, 0x55, 0x80, 0xec, 0xba, + 0x50, 0x84, 0xdf, 0xed, 0x00, 0x00, 0x05, + 0x00}, +{0x70, 0x63, 0x94, 0x68, 0x8d, 0x42, 0xf1, + 0xc8, 0x8c, 0x57, 0xe9, 0x20, 0x00, 0x05, + 0x01} +}; + +SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1OPAL[] = + { {0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf0, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xf0, 0x83, 0x8f, 0x70, 0x20, 0x00, 0x05, + 0x00}, +{0x79, 0x4f, 0x9d, 0x5a, 0x90, 0x6f, 0x3e, + 0xde, 0x81, 0x5d, 0x70, 0x00, 0x00, 0x05, + 0x00}, +{0x64, 0x4f, 0x88, 0x55, 0x80, 0x6f, 0xba, + 0x20, 0x83, 0xdf, 0x70, 0x00, 0x00, 0x05, + 0x00}, +{0x73, 0x63, 0x97, 0x69, 0x8e, 0xec, 0xf0, + 0x90, 0x8c, 0x57, 0xed, 0x20, 0x00, 0x05, + 0x01} +}; + +typedef struct _SiS310_CHTVRegDataStruct { + UCHAR Reg[5]; +} SiS310_CHTVRegDataStruct; +SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = { + 0x00 +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = { + 0x00 +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = { + 0x00 +}; + +SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = { + 0x00 +}; + +UCHAR SiS310_CHTVVCLKUNTSC[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKONTSC[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKUPAL[] = { 0x00 }; + +UCHAR SiS310_CHTVVCLKOPAL[] = { 0x00 }; diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/Makefile linux/drivers/video/sis/Makefile --- v2.4.14/linux/drivers/video/sis/Makefile Tue Oct 9 17:06:53 2001 +++ linux/drivers/video/sis/Makefile Fri Nov 9 14:11:14 2001 @@ -6,7 +6,7 @@ export-objs := sis_main.o -obj-y := sis_main.o sis_300.o sis_301.o +obj-y := sis_main.o init.o init301.o obj-m := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/init.c linux/drivers/video/sis/init.c --- v2.4.14/linux/drivers/video/sis/init.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/init.c Fri Nov 9 14:11:14 2001 @@ -0,0 +1,3784 @@ +/* Function: Support NT X.0 MM function */ +/* Version : V 0.80 [ynlai] 04/12/98 */ + +#include "init.h" +#ifdef CONFIG_FB_SIS_300 +#include "300vtbl.h" +#endif +#ifdef CONFIG_FB_SIS_315 +#include "310vtbl.h" +#endif + +BOOLEAN SiSInit (PSIS_HW_DEVICE_INFO HwDeviceExtension); +BOOLEAN SiSSetMode (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo); + +#if defined(ALLOC_PRAGMA) +#pragma alloc_text(PAGE,SiSSetMode) +#pragma alloc_text(PAGE,SiSInit) +#endif + +void SiS_SetReg1 (USHORT, USHORT, USHORT); +void SiS_SetReg2 (USHORT, USHORT, USHORT); +void SiS_SetReg3 (USHORT, USHORT); +void SiS_SetReg4 (USHORT, ULONG); +UCHAR SiS_GetReg1 (USHORT, USHORT); +UCHAR SiS_GetReg2 (USHORT); +ULONG SiS_GetReg3 (USHORT); +void SiS_ClearDAC (ULONG); + +#ifdef CONFIG_FB_SIS_300 +void +InitTo300Pointer (void) +{ + SiS_SModeIDTable = (SiS_StStruct *) SiS300_SModeIDTable; + SiS_VBModeIDTable = (SiS_VBModeStruct *) SiS300_VBModeIDTable; /*add for 300 oem util */ + SiS_StandTable = (SiS_StandTableStruct *) SiS300_StandTable; + SiS_EModeIDTable = (SiS_ExtStruct *) SiS300_EModeIDTable; + SiS_RefIndex = (SiS_Ext2Struct *) SiS300_RefIndex; + SiS_CRT1Table = (SiS_CRT1TableStruct *) SiS300_CRT1Table; + SiS_MCLKData = (SiS_MCLKDataStruct *) SiS300_MCLKData; + SiS_ECLKData = (SiS_ECLKDataStruct *) SiS300_ECLKData; + SiS_VCLKData = (SiS_VCLKDataStruct *) SiS300_VCLKData; + SiS_VBVCLKData = (SiS_VBVCLKDataStruct *) SiS300_VCLKData; + SiS_ScreenOffset = SiS300_ScreenOffset; + SiS_StResInfo = (SiS_StResInfoStruct *) SiS300_StResInfo; + SiS_ModeResInfo = (SiS_ModeResInfoStruct *) SiS300_ModeResInfo; + + pSiS_OutputSelect = &SiS300_OutputSelect; + pSiS_SoftSetting = &SiS300_SoftSetting; + pSiS_SR07 = &SiS300_SR07; + SiS_SR15 = SiS300_SR15; + SiS_CR40 = SiS300_CR40; + SiS_CR49 = SiS300_CR49; + pSiS_SR1F = &SiS300_SR1F; + pSiS_SR21 = &SiS300_SR21; + pSiS_SR22 = &SiS300_SR22; + pSiS_SR23 = &SiS300_SR23; + pSiS_SR24 = &SiS300_SR24; + SiS_SR25 = SiS300_SR25; + pSiS_SR31 = &SiS300_SR31; + pSiS_SR32 = &SiS300_SR32; + pSiS_SR33 = &SiS300_SR33; + pSiS_CRT2Data_1_2 = &SiS300_CRT2Data_1_2; + pSiS_CRT2Data_4_D = &SiS300_CRT2Data_4_D; + pSiS_CRT2Data_4_E = &SiS300_CRT2Data_4_E; + pSiS_CRT2Data_4_10 = &SiS300_CRT2Data_4_10; + pSiS_RGBSenseData = &SiS300_RGBSenseData; + pSiS_VideoSenseData = &SiS300_VideoSenseData; + pSiS_YCSenseData = &SiS300_YCSenseData; + pSiS_RGBSenseData2 = &SiS300_RGBSenseData2; + pSiS_VideoSenseData2 = &SiS300_VideoSenseData2; + pSiS_YCSenseData2 = &SiS300_YCSenseData2; + + SiS_NTSCPhase = SiS300_NTSCPhase; + SiS_PALPhase = SiS300_PALPhase; + SiS_NTSCPhase2 = SiS300_NTSCPhase2; + SiS_PALPhase2 = SiS300_PALPhase2; + SiS_PALMPhase = SiS300_PALMPhase; /*add for PALMN */ + SiS_PALNPhase = SiS300_PALNPhase; + + SiS_StLCD1024x768Data = (SiS_LCDDataStruct *) SiS300_StLCD1024x768Data; + SiS_ExtLCD1024x768Data = + (SiS_LCDDataStruct *) SiS300_ExtLCD1024x768Data; + SiS_St2LCD1024x768Data = + (SiS_LCDDataStruct *) SiS300_St2LCD1024x768Data; + SiS_StLCD1280x1024Data = + (SiS_LCDDataStruct *) SiS300_StLCD1280x1024Data; + SiS_ExtLCD1280x1024Data = + (SiS_LCDDataStruct *) SiS300_ExtLCD1280x1024Data; + SiS_St2LCD1280x1024Data = + (SiS_LCDDataStruct *) SiS300_St2LCD1280x1024Data; + SiS_NoScaleData = (SiS_LCDDataStruct *) SiS300_NoScaleData; + SiS_LCD1280x960Data = (SiS_LCDDataStruct *) SiS300_LCD1280x960Data; + SiS_StPALData = (SiS_TVDataStruct *) SiS300_StPALData; + SiS_ExtPALData = (SiS_TVDataStruct *) SiS300_ExtPALData; + SiS_StNTSCData = (SiS_TVDataStruct *) SiS300_StNTSCData; + SiS_ExtNTSCData = (SiS_TVDataStruct *) SiS300_ExtNTSCData; + SiS_St1HiTVData = (SiS_TVDataStruct *) SiS300_St1HiTVData; + SiS_St2HiTVData = (SiS_TVDataStruct *) SiS300_St2HiTVData; + SiS_ExtHiTVData = (SiS_TVDataStruct *) SiS300_ExtHiTVData; + SiS_NTSCTiming = SiS300_NTSCTiming; + SiS_PALTiming = SiS300_PALTiming; + SiS_HiTVSt1Timing = SiS300_HiTVSt1Timing; + SiS_HiTVSt2Timing = SiS300_HiTVSt2Timing; + SiS_HiTVTextTiming = SiS300_HiTVTextTiming; + SiS_HiTVGroup3Data = SiS300_HiTVGroup3Data; + SiS_HiTVGroup3Simu = SiS300_HiTVGroup3Simu; + SiS_HiTVGroup3Text = SiS300_HiTVGroup3Text; + + SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *) SiS300_PanelDelayTbl; + SiS_LVDS800x600Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS800x600Data_1; + SiS_LVDS800x600Data_2 = (SiS_LVDSDataStruct *) SiS300_LVDS800x600Data_2; + SiS_LVDS1024x768Data_1 = + (SiS_LVDSDataStruct *) SiS300_LVDS1024x768Data_1; + SiS_LVDS1024x768Data_2 = + (SiS_LVDSDataStruct *) SiS300_LVDS1024x768Data_2; + SiS_LVDS1280x1024Data_1 = + (SiS_LVDSDataStruct *) SiS300_LVDS1280x1024Data_1; + SiS_LVDS1280x1024Data_2 = + (SiS_LVDSDataStruct *) SiS300_LVDS1280x1024Data_2; + SiS_LVDS640x480Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS640x480Data_1; + SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *) SiS300_CHTVUNTSCData; + SiS_CHTVONTSCData = (SiS_LVDSDataStruct *) SiS300_CHTVONTSCData; + SiS_CHTVUPALData = (SiS_LVDSDataStruct *) SiS300_CHTVUPALData; + SiS_CHTVOPALData = (SiS_LVDSDataStruct *) SiS300_CHTVOPALData; + SiS_PanelType00_1 = (SiS_LVDSDesStruct *) SiS300_PanelType00_1; + SiS_PanelType01_1 = (SiS_LVDSDesStruct *) SiS300_PanelType01_1; + SiS_PanelType02_1 = (SiS_LVDSDesStruct *) SiS300_PanelType02_1; + SiS_PanelType03_1 = (SiS_LVDSDesStruct *) SiS300_PanelType03_1; + SiS_PanelType04_1 = (SiS_LVDSDesStruct *) SiS300_PanelType04_1; + SiS_PanelType05_1 = (SiS_LVDSDesStruct *) SiS300_PanelType05_1; + SiS_PanelType06_1 = (SiS_LVDSDesStruct *) SiS300_PanelType06_1; + SiS_PanelType07_1 = (SiS_LVDSDesStruct *) SiS300_PanelType07_1; + SiS_PanelType08_1 = (SiS_LVDSDesStruct *) SiS300_PanelType08_1; + SiS_PanelType09_1 = (SiS_LVDSDesStruct *) SiS300_PanelType09_1; + SiS_PanelType0a_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0a_1; + SiS_PanelType0b_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0b_1; + SiS_PanelType0c_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0c_1; + SiS_PanelType0d_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0d_1; + SiS_PanelType0e_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0e_1; + SiS_PanelType0f_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0f_1; + SiS_PanelType00_2 = (SiS_LVDSDesStruct *) SiS300_PanelType00_2; + SiS_PanelType01_2 = (SiS_LVDSDesStruct *) SiS300_PanelType01_2; + SiS_PanelType02_2 = (SiS_LVDSDesStruct *) SiS300_PanelType02_2; + SiS_PanelType03_2 = (SiS_LVDSDesStruct *) SiS300_PanelType03_2; + SiS_PanelType04_2 = (SiS_LVDSDesStruct *) SiS300_PanelType04_2; + SiS_PanelType05_2 = (SiS_LVDSDesStruct *) SiS300_PanelType05_2; + SiS_PanelType06_2 = (SiS_LVDSDesStruct *) SiS300_PanelType06_2; + SiS_PanelType07_2 = (SiS_LVDSDesStruct *) SiS300_PanelType07_2; + SiS_PanelType08_2 = (SiS_LVDSDesStruct *) SiS300_PanelType08_2; + SiS_PanelType09_2 = (SiS_LVDSDesStruct *) SiS300_PanelType09_2; + SiS_PanelType0a_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0a_2; + SiS_PanelType0b_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0b_2; + SiS_PanelType0c_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0c_2; + SiS_PanelType0d_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0d_2; + SiS_PanelType0e_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0e_2; + SiS_PanelType0f_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0f_2; + SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *) SiS300_CHTVUNTSCDesData; + SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *) SiS300_CHTVONTSCDesData; + SiS_CHTVUPALDesData = (SiS_LVDSDesStruct *) SiS300_CHTVUPALDesData; + SiS_CHTVOPALDesData = (SiS_LVDSDesStruct *) SiS300_CHTVOPALDesData; + SiS_LVDSCRT1800x600_1 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_1; + SiS_LVDSCRT11024x768_1 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_1; + SiS_LVDSCRT11280x1024_1 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_1; + SiS_LVDSCRT1800x600_1_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_1_H; + SiS_LVDSCRT11024x768_1_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_1_H; + SiS_LVDSCRT11280x1024_1_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_1_H; + SiS_LVDSCRT1800x600_2 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_2; + SiS_LVDSCRT11024x768_2 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_2; + SiS_LVDSCRT11280x1024_2 = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_2; + SiS_LVDSCRT1800x600_2_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_2_H; + SiS_LVDSCRT11024x768_2_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_2_H; + SiS_LVDSCRT11280x1024_2_H = + (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_2_H; + SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1UNTSC; + SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1ONTSC; + SiS_CHTVCRT1UPAL = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1UPAL; + SiS_CHTVCRT1OPAL = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1OPAL; + SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_UNTSC; + SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_ONTSC; + SiS_CHTVReg_UPAL = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_UPAL; + SiS_CHTVReg_OPAL = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_OPAL; + SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC; + SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC; + SiS_CHTVVCLKUPAL = SiS300_CHTVVCLKUPAL; + SiS_CHTVVCLKOPAL = SiS300_CHTVVCLKOPAL; + /* 300 customization related */ +} +#endif + +#ifdef CONFIG_FB_SIS_315 +void +InitTo310Pointer (void) +{ + SiS_SModeIDTable = (SiS_StStruct *) SiS310_SModeIDTable; + SiS_StandTable = (SiS_StandTableStruct *) SiS310_StandTable; + SiS_EModeIDTable = (SiS_ExtStruct *) SiS310_EModeIDTable; + SiS_RefIndex = (SiS_Ext2Struct *) SiS310_RefIndex; + SiS_CRT1Table = (SiS_CRT1TableStruct *) SiS310_CRT1Table; + SiS_MCLKData = (SiS_MCLKDataStruct *) SiS310_MCLKData; + SiS_ECLKData = (SiS_ECLKDataStruct *) SiS310_ECLKData; + SiS_VCLKData = (SiS_VCLKDataStruct *) SiS310_VCLKData; + SiS_VBVCLKData = (SiS_VBVCLKDataStruct *) SiS310_VBVCLKData; + SiS_ScreenOffset = SiS310_ScreenOffset; + SiS_StResInfo = (SiS_StResInfoStruct *) SiS310_StResInfo; + SiS_ModeResInfo = (SiS_ModeResInfoStruct *) SiS310_ModeResInfo; + + pSiS_OutputSelect = &SiS310_OutputSelect; + pSiS_SoftSetting = &SiS310_SoftSetting; + pSiS_SR07 = &SiS310_SR07; + SiS_SR15 = SiS310_SR15; + SiS_CR40 = SiS310_CR40; + SiS_CR49 = SiS310_CR49; + pSiS_SR1F = &SiS310_SR1F; + pSiS_SR21 = &SiS310_SR21; + pSiS_SR22 = &SiS310_SR22; + pSiS_SR23 = &SiS310_SR23; + pSiS_SR24 = &SiS310_SR24; + SiS_SR25 = SiS310_SR25; + pSiS_SR31 = &SiS310_SR31; + pSiS_SR32 = &SiS310_SR32; + pSiS_SR33 = &SiS310_SR33; + pSiS_CRT2Data_1_2 = &SiS310_CRT2Data_1_2; + pSiS_CRT2Data_4_D = &SiS310_CRT2Data_4_D; + pSiS_CRT2Data_4_E = &SiS310_CRT2Data_4_E; + pSiS_CRT2Data_4_10 = &SiS310_CRT2Data_4_10; + pSiS_RGBSenseData = &SiS310_RGBSenseData; + pSiS_VideoSenseData = &SiS310_VideoSenseData; + pSiS_YCSenseData = &SiS310_YCSenseData; + pSiS_RGBSenseData2 = &SiS310_RGBSenseData2; + pSiS_VideoSenseData2 = &SiS310_VideoSenseData2; + pSiS_YCSenseData2 = &SiS310_YCSenseData2; + SiS_NTSCPhase = SiS310_NTSCPhase; + SiS_PALPhase = SiS310_PALPhase; + SiS_NTSCPhase2 = SiS310_NTSCPhase2; + SiS_PALPhase2 = SiS310_PALPhase2; + SiS_PALMPhase = SiS310_PALMPhase; /*add for PALMN */ + SiS_PALNPhase = SiS310_PALNPhase; + + SiS_StLCD1024x768Data = (SiS_LCDDataStruct *) SiS310_StLCD1024x768Data; + SiS_ExtLCD1024x768Data = + (SiS_LCDDataStruct *) SiS310_ExtLCD1024x768Data; + SiS_St2LCD1024x768Data = + (SiS_LCDDataStruct *) SiS310_St2LCD1024x768Data; + SiS_StLCD1280x1024Data = + (SiS_LCDDataStruct *) SiS310_StLCD1280x1024Data; + SiS_ExtLCD1280x1024Data = + (SiS_LCDDataStruct *) SiS310_ExtLCD1280x1024Data; + SiS_St2LCD1280x1024Data = + (SiS_LCDDataStruct *) SiS310_St2LCD1280x1024Data; + SiS_NoScaleData = (SiS_LCDDataStruct *) SiS310_NoScaleData; + SiS_LCD1280x960Data = (SiS_LCDDataStruct *) SiS310_LCD1280x960Data; + SiS_StPALData = (SiS_TVDataStruct *) SiS310_StPALData; + SiS_ExtPALData = (SiS_TVDataStruct *) SiS310_ExtPALData; + SiS_StNTSCData = (SiS_TVDataStruct *) SiS310_StNTSCData; + SiS_ExtNTSCData = (SiS_TVDataStruct *) SiS310_ExtNTSCData; + SiS_St1HiTVData = (SiS_TVDataStruct *) SiS310_St1HiTVData; + SiS_St2HiTVData = (SiS_TVDataStruct *) SiS310_St2HiTVData; + SiS_ExtHiTVData = (SiS_TVDataStruct *) SiS310_ExtHiTVData; + SiS_NTSCTiming = SiS310_NTSCTiming; + SiS_PALTiming = SiS310_PALTiming; + SiS_HiTVSt1Timing = SiS310_HiTVSt1Timing; + SiS_HiTVSt2Timing = SiS310_HiTVSt2Timing; + SiS_HiTVTextTiming = SiS310_HiTVTextTiming; + SiS_HiTVGroup3Data = SiS310_HiTVGroup3Data; + SiS_HiTVGroup3Simu = SiS310_HiTVGroup3Simu; + SiS_HiTVGroup3Text = SiS310_HiTVGroup3Text; + + SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *) SiS310_PanelDelayTbl; + SiS_LVDS800x600Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS800x600Data_1; + SiS_LVDS800x600Data_2 = (SiS_LVDSDataStruct *) SiS310_LVDS800x600Data_2; + SiS_LVDS1024x768Data_1 = + (SiS_LVDSDataStruct *) SiS310_LVDS1024x768Data_1; + SiS_LVDS1024x768Data_2 = + (SiS_LVDSDataStruct *) SiS310_LVDS1024x768Data_2; + SiS_LVDS1280x1024Data_1 = + (SiS_LVDSDataStruct *) SiS310_LVDS1280x1024Data_1; + SiS_LVDS1280x1024Data_2 = + (SiS_LVDSDataStruct *) SiS310_LVDS1280x1024Data_2; + SiS_LVDS640x480Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS640x480Data_1; + SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *) SiS310_CHTVUNTSCData; + SiS_CHTVONTSCData = (SiS_LVDSDataStruct *) SiS310_CHTVONTSCData; + SiS_CHTVUPALData = (SiS_LVDSDataStruct *) SiS310_CHTVUPALData; + SiS_CHTVOPALData = (SiS_LVDSDataStruct *) SiS310_CHTVOPALData; + SiS_PanelType00_1 = (SiS_LVDSDesStruct *) SiS310_PanelType00_1; + SiS_PanelType01_1 = (SiS_LVDSDesStruct *) SiS310_PanelType01_1; + SiS_PanelType02_1 = (SiS_LVDSDesStruct *) SiS310_PanelType02_1; + SiS_PanelType03_1 = (SiS_LVDSDesStruct *) SiS310_PanelType03_1; + SiS_PanelType04_1 = (SiS_LVDSDesStruct *) SiS310_PanelType04_1; + SiS_PanelType05_1 = (SiS_LVDSDesStruct *) SiS310_PanelType05_1; + SiS_PanelType06_1 = (SiS_LVDSDesStruct *) SiS310_PanelType06_1; + SiS_PanelType07_1 = (SiS_LVDSDesStruct *) SiS310_PanelType07_1; + SiS_PanelType08_1 = (SiS_LVDSDesStruct *) SiS310_PanelType08_1; + SiS_PanelType09_1 = (SiS_LVDSDesStruct *) SiS310_PanelType09_1; + SiS_PanelType0a_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0a_1; + SiS_PanelType0b_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0b_1; + SiS_PanelType0c_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0c_1; + SiS_PanelType0d_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0d_1; + SiS_PanelType0e_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0e_1; + SiS_PanelType0f_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0f_1; + SiS_PanelType00_2 = (SiS_LVDSDesStruct *) SiS310_PanelType00_2; + SiS_PanelType01_2 = (SiS_LVDSDesStruct *) SiS310_PanelType01_2; + SiS_PanelType02_2 = (SiS_LVDSDesStruct *) SiS310_PanelType02_2; + SiS_PanelType03_2 = (SiS_LVDSDesStruct *) SiS310_PanelType03_2; + SiS_PanelType04_2 = (SiS_LVDSDesStruct *) SiS310_PanelType04_2; + SiS_PanelType05_2 = (SiS_LVDSDesStruct *) SiS310_PanelType05_2; + SiS_PanelType06_2 = (SiS_LVDSDesStruct *) SiS310_PanelType06_2; + SiS_PanelType07_2 = (SiS_LVDSDesStruct *) SiS310_PanelType07_2; + SiS_PanelType08_2 = (SiS_LVDSDesStruct *) SiS310_PanelType08_2; + SiS_PanelType09_2 = (SiS_LVDSDesStruct *) SiS310_PanelType09_2; + SiS_PanelType0a_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0a_2; + SiS_PanelType0b_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0b_2; + SiS_PanelType0c_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0c_2; + SiS_PanelType0d_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0d_2; + SiS_PanelType0e_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0e_2; + SiS_PanelType0f_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0f_2; + /*301b */ + LVDS1024x768Des_1 = (SiS_LVDSDesStruct *) SiS310_PanelType1076_1; + LVDS1280x1024Des_1 = (SiS_LVDSDesStruct *) SiS310_PanelType1210_1; + LVDS1280x960Des_1 = (SiS_LVDSDesStruct *) SiS310_PanelType1296_1; + LVDS1024x768Des_2 = (SiS_LVDSDesStruct *) SiS310_PanelType1076_2; + LVDS1280x1024Des_2 = (SiS_LVDSDesStruct *) SiS310_PanelType1210_2; + LVDS1280x960Des_2 = (SiS_LVDSDesStruct *) SiS310_PanelType1296_2; + /*end 301b */ + + SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *) SiS310_CHTVUNTSCDesData; + SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *) SiS310_CHTVONTSCDesData; + SiS_CHTVUPALDesData = (SiS_LVDSDesStruct *) SiS310_CHTVUPALDesData; + SiS_CHTVOPALDesData = (SiS_LVDSDesStruct *) SiS310_CHTVOPALDesData; + SiS_LVDSCRT1800x600_1 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_1; + SiS_LVDSCRT11024x768_1 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_1; + SiS_LVDSCRT11280x1024_1 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_1; + SiS_LVDSCRT1800x600_1_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_1_H; + SiS_LVDSCRT11024x768_1_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_1_H; + SiS_LVDSCRT11280x1024_1_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_1_H; + SiS_LVDSCRT1800x600_2 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_2; + SiS_LVDSCRT11024x768_2 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_2; + SiS_LVDSCRT11280x1024_2 = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_2; + SiS_LVDSCRT1800x600_2_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_2_H; + SiS_LVDSCRT11024x768_2_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_2_H; + SiS_LVDSCRT11280x1024_2_H = + (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_2_H; + SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1UNTSC; + SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1ONTSC; + SiS_CHTVCRT1UPAL = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1UPAL; + SiS_CHTVCRT1OPAL = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1OPAL; + SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_UNTSC; + SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_ONTSC; + SiS_CHTVReg_UPAL = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_UPAL; + SiS_CHTVReg_OPAL = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_OPAL; + /*add for LCDA */ + SiS_LCDACRT1800x600_1 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_1; + SiS_LCDACRT11024x768_1 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_1; + SiS_LCDACRT11280x1024_1 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_1; + SiS_LCDACRT1800x600_1_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_1_H; + SiS_LCDACRT11024x768_1_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_1_H; + SiS_LCDACRT11280x1024_1_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_1_H; + SiS_LCDACRT1800x600_2 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_2; + SiS_LCDACRT11024x768_2 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_2; + SiS_LCDACRT11280x1024_2 = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_2; + SiS_LCDACRT1800x600_2_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_2_H; + SiS_LCDACRT11024x768_2_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_2_H; + SiS_LCDACRT11280x1024_2_H = + (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_2_H; + /*end for 301b */ + + SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC; + SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC; + SiS_CHTVVCLKUPAL = SiS310_CHTVVCLKUPAL; + SiS_CHTVVCLKOPAL = SiS310_CHTVVCLKOPAL; + /* 310 customization related */ + +} +#endif + +BOOLEAN +SiSInit (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + ULONG ROMAddr = (ULONG) HwDeviceExtension->pjVirtualRomBase; + ULONG FBAddr = (ULONG) HwDeviceExtension->pjVideoMemoryAddress; + USHORT BaseAddr = (USHORT) HwDeviceExtension->ulIOAddress; + UCHAR i, temp = 0; + UCHAR SR11, temp1; + ULONG base; + UCHAR SR12 = 0, SR13 = 0, SR14 = 0, SR16 = 0, SR17 = 0, SR18 = 0, SR19 = + 0, SR1A = 0; +#ifdef CONFIG_FB_SIS_315 + /* ULONG j, k; */ + UCHAR CR39 = 0, CR3A = 0, CR3B = 0, CR3C = 0, CR3D = 0, CR3E = 0, CR3F = + 0; + UCHAR CR79 = 0, CR7A = 0, CR7B = 0, CR7C = 0; + PSIS_DSReg pSR; + ULONG Temp; +#endif + UCHAR VBIOSVersion[5]; + +/* if(ROMAddr==0) return (FALSE);*/ + if (FBAddr == 0) + return (FALSE); + if (BaseAddr == 0) + return (FALSE); + + SiS_SetReg3 ((USHORT) (BaseAddr + 0x12), 0x67); /* 3c2 <- 67 ,ynlai */ +#ifdef CONFIG_FB_SIS_315 + /*if(HwDeviceExtension->jChipType > SIS_315H) */ + if (HwDeviceExtension->jChipType > SIS_315PRO) { + if (!HwDeviceExtension->bIntegratedMMEnabled) + return (FALSE); /* alan */ + } +#endif + + SiS_MemoryCopy (VBIOSVersion, HwDeviceExtension->szVBIOSVer, 4); + + VBIOSVersion[4] = 0x0; + /* 09/07/99 modify by domao */ + +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO) || + (HwDeviceExtension->jChipType == SIS_550) || /* 05/02/01 ynlai for 550 */ + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) /* 09/03/01 chiawen for 650 */ + InitTo310Pointer (); +#endif + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730) || + (HwDeviceExtension->jChipType == SIS_300)) + InitTo300Pointer (); +#endif + + SiS_P3c4 = BaseAddr + 0x14; + SiS_P3d4 = BaseAddr + 0x24; + SiS_P3c0 = BaseAddr + 0x10; + SiS_P3ce = BaseAddr + 0x1e; + SiS_P3c2 = BaseAddr + 0x12; + SiS_P3ca = BaseAddr + 0x1a; + SiS_P3c6 = BaseAddr + 0x16; + SiS_P3c7 = BaseAddr + 0x17; + SiS_P3c8 = BaseAddr + 0x18; + SiS_P3c9 = BaseAddr + 0x19; + SiS_P3da = BaseAddr + 0x2A; + SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; + SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10; + SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12; + SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14; + SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2; + SiS_Set_LVDS_TRUMPION (HwDeviceExtension); /*2/29/00 by Mars Wen for LVDS and Trumpion */ + + SiS_SetReg1 (SiS_P3c4, 0x05, 0x86); /* 1.Openkey */ + +#ifdef LINUX_KERNEL +#ifdef CONFIG_FB_SIS_300 /* add to set SR14 */ + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + base = 0x80000060; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 >> (16 + 8 + 4); + temp1 = temp1 & (0x07); + temp1 = temp1 + 1; + temp1 = 1 << temp1; + SR14 = temp1 - 1; + base = 0x80000064; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 & (0x00000020); + if (temp1) + SR14 = (0x10000000) | SR14; + else + SR14 = (0x01000000) | SR14; + } +#endif + +#ifdef CONFIG_FB_SIS_315 /* add to set SR14 */ + if ((HwDeviceExtension->jChipType == SIS_550)) { + base = 0x80000060; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 >> (16 + 8 + 4); + temp1 = temp1 & (0x07); + temp1 = temp1 + 1; + temp1 = 1 << temp1; + SR14 = temp1 - 1; + base = 0x80000064; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 & (0x00000020); + if (temp1) + SR14 = (0x10000000) | SR14; + else + SR14 = (0x01000000) | SR14; + } + + if ((HwDeviceExtension->jChipType == SIS_640) + || (HwDeviceExtension->jChipType == SIS_740)) { + base = 0x80000064; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp >> 4; + temp1 = temp1 & (0x07); + if (temp1 > 2) { + temp = temp1; + switch (temp) { + case 3: + temp1 = 0x07; + break; + case 4: + temp1 = 0x0F; + break; + case 5: + temp1 = 0x1F; + break; + case 6: + temp1 = 0x05; + break; + case 7: + temp1 = 0x17; + break; + case 8: + break; + case 9: + break; + } + } + SR14 = temp1; + base = 0x8000007C; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 & (0x00000020); + if (temp1) + SR14 = (0x10000000) | SR14; + } +#endif + +#endif + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + SR12 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x12); + SR13 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x13); + SR14 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x14); + SR16 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x16); + SR17 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x17); + SR18 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x18); + SR19 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x19); + SR1A = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x1A); + } else { + SR13 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x13); + SR14 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x14); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_550)) { + CR39 = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x39); + CR3A = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3A); + CR3B = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3B); + CR3C = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3C); + CR3D = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3D); + CR3E = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3E); + CR3F = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x3F); + CR79 = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x79); + CR7A = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x7A); + CR7B = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x7B); + CR7C = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x7C); + } else if ((HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) { + SR12 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x12); + SR13 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x13); + SR14 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x14); + SR16 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x16); + SR17 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x17); + SR18 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x18); + SR19 = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x19); + SR1A = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x1A); + } +#endif +/* ResetExtReg begin */ + for (i = 0x06; i < 0x20; i++) + SiS_SetReg1 (SiS_P3c4, i, 0); /* 2.Reset Extended register */ + for (i = 0x21; i <= 0x27; i++) + SiS_SetReg1 (SiS_P3c4, i, 0); /* Reset Extended register */ + for (i = 0x31; i <= 0x3D; i++) + SiS_SetReg1 (SiS_P3c4, i, 0); + +#ifdef CONFIG_FB_SIS_300H + for (i = 0x38; i <= 0x3F; i++) + SiS_SetReg1 (SiS_P3d4, i, 0); +#endif + +#ifdef CONFIG_FB_SIS_315 + for (i = 0x37; i <= 0x3F; i++) + SiS_SetReg1 (SiS_P3d4, i, 0); + for (i = 0x79; i <= 0x7C; i++) + SiS_SetReg1 (SiS_P3d4, i, 0); +#endif +/* ResetExtReg end */ +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + SiS_SetReg1 (SiS_P3c4, 0x12, SR12); + SiS_SetReg1 (SiS_P3c4, 0x13, SR13); + SiS_SetReg1 (SiS_P3c4, 0x14, SR14); + SiS_SetReg1 (SiS_P3c4, 0x16, SR16); + SiS_SetReg1 (SiS_P3c4, 0x17, SR17); + SiS_SetReg1 (SiS_P3c4, 0x18, SR18); + SiS_SetReg1 (SiS_P3c4, 0x19, SR19); + SiS_SetReg1 (SiS_P3c4, 0x1A, SR1A); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_550)) { + SiS_SetReg1 (SiS_P3d4, 0x39, CR39); + SiS_SetReg1 (SiS_P3d4, 0x3A, CR3A); + SiS_SetReg1 (SiS_P3d4, 0x3B, CR3B); + SiS_SetReg1 (SiS_P3d4, 0x3C, CR3C); + SiS_SetReg1 (SiS_P3d4, 0x3D, CR3D); + SiS_SetReg1 (SiS_P3d4, 0x3E, CR3E); + SiS_SetReg1 (SiS_P3d4, 0x3F, CR3F); + SiS_SetReg1 (SiS_P3d4, 0x79, CR79); + SiS_SetReg1 (SiS_P3d4, 0x7A, CR7A); + SiS_SetReg1 (SiS_P3d4, 0x7B, CR7B); + SiS_SetReg1 (SiS_P3d4, 0x7C, CR7C); + } else if ((HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) { + SiS_SetReg1 (SiS_P3c4, 0x12, SR12); + SiS_SetReg1 (SiS_P3c4, 0x13, SR13); + SiS_SetReg1 (SiS_P3c4, 0x14, SR14); + SiS_SetReg1 (SiS_P3c4, 0x16, SR16); + SiS_SetReg1 (SiS_P3c4, 0x17, SR17); + SiS_SetReg1 (SiS_P3c4, 0x18, SR18); + SiS_SetReg1 (SiS_P3c4, 0x19, SR19); + SiS_SetReg1 (SiS_P3c4, 0x1A, SR1A); + } +#endif + +/* detect ExtChip Type */ + SiS_Set_LVDS_TRUMPION (HwDeviceExtension); /*2/29/00 by Mars Wen for LVDS and Trumpion */ + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + temp = (UCHAR) SR1A; + } else +#endif + { + if ((*pSiS_SoftSetting & SoftDRAMType) == 0) { + temp = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x3A); + } + } + + SiS_RAMType = temp & 0x03; + SiS_SetMemoryClock (ROMAddr); + +/* SetDefExt1Regs begin */ + SiS_SetReg1 (SiS_P3c4, 0x07, *pSiS_SR07); + if ((HwDeviceExtension->jChipType != SIS_540) && + (HwDeviceExtension->jChipType != SIS_630) && + (HwDeviceExtension->jChipType != SIS_730)) { + for (i = 0x15; i < 0x1C; i++) { + SiS_SetReg1 (SiS_P3c4, i, + SiS_SR15[i - 0x15][SiS_RAMType]); + } + } +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO)) { + for (i = 0x40; i <= 0x44; i++) { + SiS_SetReg1 (SiS_P3d4, i, + SiS_CR40[i - 0x40][SiS_RAMType]); + } + SiS_SetReg1 (SiS_P3d4, 0x48, 0x23); + SiS_SetReg1 (SiS_P3d4, 0x49, SiS_CR49[0]); + /* /SiS_SetReg1(SiS_P3c4,0x25,SiS_SR25[0]); */ + } +#endif + + SiS_SetReg1 (SiS_P3c4, 0x1F, *pSiS_SR1F); + /*SiS_SetReg1(SiS_P3c4,0x20,0x20); */ + SiS_SetReg1 (SiS_P3c4, 0x20, 0xA0); /* alan, 2001/6/26 Frame buffer can read/write */ + SiS_SetReg1 (SiS_P3c4, 0x23, *pSiS_SR23); + SiS_SetReg1 (SiS_P3c4, 0x24, *pSiS_SR24); + SiS_SetReg1 (SiS_P3c4, 0x25, SiS_SR25[0]); +#ifdef CONFIG_FB_SIS_300 + if (HwDeviceExtension->jChipType == SIS_300) { + SiS_SetReg1 (SiS_P3c4, 0x21, 0x84); + SiS_SetReg1 (SiS_P3c4, 0x22, 0x00); + } +#endif + SR11 = 0x0F; + SiS_SetReg1 (SiS_P3c4, 0x11, SR11); + + SiS_UnLockCRT2 (HwDeviceExtension, BaseAddr); + SiS_SetReg1 (SiS_Part1Port, 0x00, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x02, *pSiS_CRT2Data_1_2); +#ifdef CONFIG_FB_SIS_315 /* 05/02/01 ynlai for sis550 */ + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO) || + (HwDeviceExtension->jChipType == SIS_550) || + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) + /* 09/03/01 chiawen for 650 */ + SiS_SetReg1 (SiS_Part1Port, 0x2E, 0x08); /* use VB */ +#endif + + temp = *pSiS_SR32; + if (SiS_BridgeIsOn (BaseAddr)) { + temp = temp & 0xEF; + } + SiS_SetReg1 (SiS_P3c4, 0x32, temp); + +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO)) { + HwDeviceExtension->pQueryVGAConfigSpace (HwDeviceExtension, + 0x50, 0, &Temp); /* Get */ + + Temp >>= 20; + Temp &= 0xF; + if (Temp != 1) { + SiS_SetReg1 (SiS_P3c4, 0x25, SiS_SR25[1]); + SiS_SetReg1 (SiS_P3d4, 0x49, SiS_CR49[1]); + } + + SiS_SetReg1 (SiS_P3c4, 0x27, 0x1F); + + SiS_SetReg1 (SiS_P3c4, 0x31, *pSiS_SR31); + SiS_SetReg1 (SiS_P3c4, 0x32, *pSiS_SR32); + SiS_SetReg1 (SiS_P3c4, 0x33, *pSiS_SR33); + } +#endif + + if (SiS_BridgeIsOn (BaseAddr) == 1) { + if (SiS_IF_DEF_LVDS == 0) { + SiS_SetReg1 (SiS_Part2Port, 0x00, 0x1C); + SiS_SetReg1 (SiS_Part4Port, 0x0D, *pSiS_CRT2Data_4_D); + SiS_SetReg1 (SiS_Part4Port, 0x0E, *pSiS_CRT2Data_4_E); + SiS_SetReg1 (SiS_Part4Port, 0x10, *pSiS_CRT2Data_4_10); + SiS_SetReg1 (SiS_Part4Port, 0x0F, 0x3F); + } + SiS_LockCRT2 (HwDeviceExtension, BaseAddr); + } + SiS_SetReg1 (SiS_P3d4, 0x83, 0x00); +/* SetDefExt1Regs end */ + +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO) + ) { /* 05/02/01 ynlai */ + /* For SiS 300,310 Chip */ + if (HwDeviceExtension->bSkipDramSizing == TRUE) { + SiS_SetDRAMModeRegister (ROMAddr); + pSR = HwDeviceExtension->pSR; + if (pSR != NULL) { + while (pSR->jIdx != 0xFF) { + SiS_SetReg1 (SiS_P3c4, pSR->jIdx, + pSR->jVal); + pSR++; + } + } + } else + SiS_SetDRAMSize_310 (HwDeviceExtension); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_550)) { /* 05/02/01 ynlai For SiS 550 */ + /* SetDRAMConfig begin */ +/* SiS_SetReg1(SiS_P3c4,0x12,SR12); + SiS_SetReg1(SiS_P3c4,0x13,SR13); + SiS_SetReg1(SiS_P3c4,0x14,SR14); + SiS_SetReg1(SiS_P3c4,0x16,SR16); + SiS_SetReg1(SiS_P3c4,0x17,SR17); + SiS_SetReg1(SiS_P3c4,0x18,SR18); + SiS_SetReg1(SiS_P3c4,0x19,SR19); + SiS_SetReg1(SiS_P3c4,0x1A,SR1A); */ + /* SetDRAMConfig end */ + } +#endif +#ifdef CONFIG_FB_SIS_300 + if (HwDeviceExtension->jChipType == SIS_300) { /* For SiS 300 Chip */ + if (HwDeviceExtension->bSkipDramSizing == TRUE) { +/* SiS_SetDRAMModeRegister(ROMAddr); + temp = (HwDeviceExtension->pSR)->jVal; + SiS_SetReg1(SiS_P3c4,0x13,temp); + temp = (HwDeviceExtension->pSR)->jVal; + SiS_SetReg1(SiS_P3c4,0x14,temp); */ + } else { +#ifdef TC + SiS_SetReg1 (SiS_P3c4, 0x13, SR13); + SiS_SetReg1 (SiS_P3c4, 0x14, SR14); + SiS_SetRegANDOR (SiS_P3c4, 0x15, 0xFF, 0x04); +#else + SiS_SetDRAMSize_300 (HwDeviceExtension); + SiS_SetDRAMSize_300 (HwDeviceExtension); +#endif + } + } + if ((HwDeviceExtension->jChipType == SIS_540) || /* For SiS 630/540/730 Chip */ + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + /* SetDRAMConfig begin */ +/* SiS_SetReg1(SiS_P3c4,0x12,SR12); + SiS_SetReg1(SiS_P3c4,0x13,SR13); + SiS_SetReg1(SiS_P3c4,0x14,SR14); + SiS_SetReg1(SiS_P3c4,0x16,SR16); + SiS_SetReg1(SiS_P3c4,0x17,SR17); + SiS_SetReg1(SiS_P3c4,0x18,SR18); + SiS_SetReg1(SiS_P3c4,0x19,SR19); + SiS_SetReg1(SiS_P3c4,0x1A,SR1A); */ + /* SetDRAMConfig end */ + } +/* SetDRAMSize end */ +#endif + +/* SetDefExt2Regs begin */ +/* AGP=1; + temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x3A); + temp=temp&0x30; + if(temp==0x30) AGP=0; + if(AGP==0) *pSiS_SR21=*pSiS_SR21&0xEF; + SiS_SetReg1(SiS_P3c4,0x21,*pSiS_SR21); + if(AGP==1) *pSiS_SR22=*pSiS_SR22&0x20; + SiS_SetReg1(SiS_P3c4,0x22,*pSiS_SR22); */ + + SiS_SetReg1 (SiS_P3c4, 0x21, *pSiS_SR21); + SiS_SetReg1 (SiS_P3c4, 0x22, *pSiS_SR22); +/* SetDefExt2Regs end */ + +/* SiS_SetReg3(SiS_P3c6,0xff); + SiS_ClearDAC(SiS_P3c8); [ynlai] 05/22/01 */ + + SiS_DetectMonitor (HwDeviceExtension, BaseAddr); + SiS_GetSenseStatus (HwDeviceExtension, ROMAddr); /* sense CRT2 */ + + return (TRUE); +} + +void +SiS_Set_LVDS_TRUMPION (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp; + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + temp = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x1A); + temp = (temp & 0xE0) >> 4; + SiS_SetRegANDOR (SiS_P3d4, 0x37, 0xF1, temp); + temp = temp >> 1; + if ((temp == 0) || (temp == 1)) { /* for 301 */ + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_CH7005 = 0; + SiS_IF_DEF_TRUMPION = 0; + } + if ((temp >= 2) && (temp <= 5)) { + SiS_IF_DEF_LVDS = 1; + } + if (temp == 3) + SiS_IF_DEF_TRUMPION = 1; + if ((temp == 4) || (temp == 5)) + SiS_IF_DEF_CH7005 = 1; + } else { + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_TRUMPION = 0; + SiS_IF_DEF_CH7005 = 0; + } +#else + if ((HwDeviceExtension->jChipType == SIS_550) || + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) + { /* 09/03/01 chiawen for 650 */ + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_TRUMPION = 0; + SiS_IF_DEF_CH7005 = 0; + } +#endif +} + +/* =============== for 300 dram sizing begin =============== */ +#ifdef CONFIG_FB_SIS_300 +void +SiS_SetDRAMSize_300 (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + /*ULONG ROMAddr = (ULONG)HwDeviceExtension->pjVirtualRomBase; */ + ULONG FBAddr = (ULONG) HwDeviceExtension->pjVideoMemoryAddress; + /*USHORT BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress; */ + USHORT SR13, SR14 = 0, buswidth, Done; + SHORT i, j, k; + USHORT data, TotalCapacity, PhysicalAdrOtherPage = 0; + ULONG Addr; + UCHAR temp; + + int PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount; + int RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank; + /*int PageCapacity,PhysicalAdrHigh,PhysicalAdrHalfPage,PhysicalAdrAnotherPage; */ + int PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage; + + SiSSetMode (HwDeviceExtension, 0x2e); + data = SiS_GetReg1 (SiS_P3c4, 0x1); + data = data | 0x20; + SiS_SetReg1 (SiS_P3c4, 0x01, data); /* Turn OFF Display */ + + SiS_SetReg1 (SiS_P3c4, 0x13, 0x00); + SiS_SetReg1 (SiS_P3c4, 0x14, 0xBF); + buswidth = SiS_ChkBUSWidth_300 (FBAddr); + + MB2Bank = 16; + Done = 0; + for (i = 6; i >= 0; i--) { + if (Done == 1) + break; + PseudoRankCapacity = 1 << i; + for (j = 4; j >= 1; j--) { + if (Done == 1) + break; + PseudoTotalCapacity = PseudoRankCapacity * j; + PseudoAdrPinCount = 15 - j; + if (PseudoTotalCapacity <= 64) { + for (k = 0; k <= 16; k++) { + if (Done == 1) + break; + RankCapacity = + buswidth * SiS_DRAMType[k][3]; + AdrPinCount = + SiS_DRAMType[k][2] + + SiS_DRAMType[k][0]; + if (RankCapacity == PseudoRankCapacity) + if (AdrPinCount <= + PseudoAdrPinCount) { + if (j == 3) { /* Rank No */ + BankNumHigh = + RankCapacity + * MB2Bank * + 3 - 1; + BankNumMid = + RankCapacity + * MB2Bank * + 1 - 1; + } else { + BankNumHigh = + RankCapacity + * MB2Bank * + j - 1; + BankNumMid = + RankCapacity + * MB2Bank * + j / 2 - 1; + } + PageCapacity = + (1 << + SiS_DRAMType[k][1]) + * buswidth * 4; + PhysicalAdrHigh = + BankNumHigh; + PhysicalAdrHalfPage = + (PageCapacity / 2 + + PhysicalAdrHigh) % + PageCapacity; + PhysicalAdrOtherPage = + PageCapacity * + SiS_DRAMType[k][2] + + PhysicalAdrHigh; + /* Write data */ + /*Test */ + temp = + (UCHAR) + SiS_GetReg1 + (SiS_P3c4, 0x15); + SiS_SetReg1 (SiS_P3c4, + 0x15, + (USHORT) + (temp & + 0xFB)); + + temp = + (UCHAR) + SiS_GetReg1 + (SiS_P3c4, 0x15); + SiS_SetReg1 (SiS_P3c4, + 0x15, + (USHORT) + (temp | + 0x04)); + /*Test */ + TotalCapacity = + SiS_DRAMType[k][3] * + buswidth; + SR13 = + SiS_DRAMType[k][4]; + if (buswidth == 4) + SR14 = + (TotalCapacity + - + 1) | 0x80; + if (buswidth == 2) + SR14 = + (TotalCapacity + - + 1) | 0x40; + if (buswidth == 1) + SR14 = + (TotalCapacity + - + 1) | 0x00; + SiS_SetReg1 (SiS_P3c4, + 0x13, + SR13); + SiS_SetReg1 (SiS_P3c4, + 0x14, + SR14); + + Addr = + FBAddr + + (BankNumHigh) * 64 * + 1024 + + PhysicalAdrHigh; + *((USHORT *) (Addr)) = + (USHORT) + PhysicalAdrHigh; + Addr = + FBAddr + + (BankNumMid) * 64 * + 1024 + + PhysicalAdrHigh; + *((USHORT *) (Addr)) = + (USHORT) BankNumMid; + Addr = + FBAddr + + (BankNumHigh) * 64 * + 1024 + + PhysicalAdrHalfPage; + *((USHORT *) (Addr)) = + (USHORT) + PhysicalAdrHalfPage; + Addr = + FBAddr + + (BankNumHigh) * 64 * + 1024 + + PhysicalAdrOtherPage; + *((USHORT *) (Addr)) = + PhysicalAdrOtherPage; + + /* Read data */ + Addr = + FBAddr + + (BankNumHigh) * 64 * + 1024 + + PhysicalAdrHigh; + data = + *((USHORT *) + (Addr)); + if (data == + PhysicalAdrHigh) + Done = 1; + } /* if struct */ + } /* for loop (k) */ + } /* if struct */ + } /* for loop (j) */ + } /* for loop (i) */ +} + +USHORT +SiS_ChkBUSWidth_300 (ULONG FBAddress) +{ + /*USHORT data; */ + PULONG pVideoMemory; + + pVideoMemory = (PULONG) FBAddress; + + pVideoMemory[0] = 0x01234567L; + pVideoMemory[1] = 0x456789ABL; + pVideoMemory[2] = 0x89ABCDEFL; + pVideoMemory[3] = 0xCDEF0123L; + if (pVideoMemory[3] == 0xCDEF0123L) { /*ChannelA128Bit */ + return (4); + } + if (pVideoMemory[1] == 0x456789ABL) { /*ChannelB64Bit */ + return (2); + } + return (1); +} +#endif + +/* =============== for 300 dram sizing end =============== */ + +/* ============== alan ====================== */ +#ifdef CONFIG_FB_SIS_315 +UCHAR +SiS_Get310DRAMType (ULONG ROMAddr) +{ + UCHAR data; + + /* + index=SiS_GetReg1(SiS_P3c4,0x1A); + index=index&07; + */ + if (*pSiS_SoftSetting & SoftDRAMType) + data = *pSiS_SoftSetting & 0x03; + else + data = SiS_GetReg1 (SiS_P3c4, 0x3a) & 0x03; + + return data; +} + +void +SiS_Delay15us (ULONG ulMicrsoSec) +{ +} + +void +SiS_SDR_MRS (void) +{ + USHORT data; + + data = SiS_GetReg1 (SiS_P3c4, 0x16); + data = data & 0x3F; /*/ SR16 D7=0,D6=0 */ + SiS_SetReg1 (SiS_P3c4, 0x16, data); /*/ enable mode register set(MRS) low */ + SiS_Delay15us (0x100); + data = data | 0x80; /*/ SR16 D7=1,D6=0 */ + SiS_SetReg1 (SiS_P3c4, 0x16, data); /*/ enable mode register set(MRS) high */ + SiS_Delay15us (0x100); +} + +void +SiS_DDR_MRS (void) +{ + USHORT data; + + /* SR16 <- 1F,DF,2F,AF */ + + /* enable DLL of DDR SD/SGRAM , SR16 D4=1 */ + data = SiS_GetReg1 (SiS_P3c4, 0x16); + data &= 0x0F; + data |= 0x10; + SiS_SetReg1 (SiS_P3c4, 0x16, data); + + if (!(SiS_SR15[1][SiS_RAMType] & 0x10)) { + data &= 0x0F; + } + /* SR16 D7=1,D6=1 */ + data |= 0xC0; + SiS_SetReg1 (SiS_P3c4, 0x16, data); + + /* SR16 D7=1,D6=0,D5=1,D4=0 */ + data &= 0x0F; + data |= 0x20; + SiS_SetReg1 (SiS_P3c4, 0x16, data); + if (!(SiS_SR15[1][SiS_RAMType] & 0x10)) { + data &= 0x0F; + } + /* SR16 D7=1 */ + data |= 0x80; + SiS_SetReg1 (SiS_P3c4, 0x16, data); +} + +void +SiS_SetDRAMModeRegister (ULONG ROMAddr) +{ + + if (SiS_Get310DRAMType (ROMAddr) < 2) { + SiS_SDR_MRS (); + } else { + /* SR16 <- 0F,CF,0F,8F */ + SiS_DDR_MRS (); + } +} + +void +SiS_DisableRefresh (void) +{ + USHORT data; + + data = SiS_GetReg1 (SiS_P3c4, 0x17); + data &= 0xF8; + SiS_SetReg1 (SiS_P3c4, 0x17, data); + + data = SiS_GetReg1 (SiS_P3c4, 0x19); + data |= 0x03; + SiS_SetReg1 (SiS_P3c4, 0x19, data); + +} + +void +SiS_EnableRefresh (ULONG ROMAddr) +{ + + SiS_SetReg1 (SiS_P3c4, 0x17, SiS_SR15[2][SiS_RAMType]); /* SR17 */ + + SiS_SetReg1 (SiS_P3c4, 0x19, SiS_SR15[4][SiS_RAMType]); /* SR19 */ + +} + +void +SiS_DisableChannelInterleaving (int index, USHORT SiS_DDRDRAM_TYPE[][5]) +{ + USHORT data; + + data = SiS_GetReg1 (SiS_P3c4, 0x15); + data &= 0x1F; + switch (SiS_DDRDRAM_TYPE[index][3]) { + case 64: + data |= 0; + break; + case 32: + data |= 0x20; + break; + case 16: + data |= 0x40; + break; + case 4: + data |= 0x60; + break; + } + SiS_SetReg1 (SiS_P3c4, 0x15, data); + +} + +void +SiS_SetDRAMSizingType (int index, USHORT DRAMTYPE_TABLE[][5]) +{ + USHORT data; + + data = DRAMTYPE_TABLE[index][4]; + SiS_SetReg1 (SiS_P3c4, 0x13, data); + + /* should delay 50 ns */ + +} + +void +SiS_CheckBusWidth_310 (ULONG ROMAddress, ULONG FBAddress) +{ + USHORT data; + PULONG volatile pVideoMemory; + + pVideoMemory = (PULONG) FBAddress; + if (SiS_Get310DRAMType (ROMAddress) < 2) { + + SiS_SetReg1 (SiS_P3c4, 0x13, 0x00); + SiS_SetReg1 (SiS_P3c4, 0x14, 0x12); + /* should delay */ + SiS_SDR_MRS (); + + SiS_ChannelAB = 0; + SiS_DataBusWidth = 128; + pVideoMemory[0] = 0x01234567L; + pVideoMemory[1] = 0x456789ABL; + pVideoMemory[2] = 0x89ABCDEFL; + pVideoMemory[3] = 0xCDEF0123L; + pVideoMemory[4] = 0x55555555L; + pVideoMemory[5] = 0x55555555L; + pVideoMemory[6] = 0xFFFFFFFFL; + pVideoMemory[7] = 0xFFFFFFFFL; + if ((pVideoMemory[3] != 0xCDEF0123L) + || (pVideoMemory[2] != 0x89ABCDEFL)) { + /*ChannelA64Bit */ + SiS_DataBusWidth = 64; + SiS_ChannelAB = 0; + data = SiS_GetReg1 (SiS_P3c4, 0x14); + SiS_SetReg1 (SiS_P3c4, 0x14, (USHORT) (data & 0xFD)); + } + + if ((pVideoMemory[1] != 0x456789ABL) + || (pVideoMemory[0] != 0x01234567L)) { + /*ChannelB64Bit */ + SiS_DataBusWidth = 64; + SiS_ChannelAB = 1; + data = SiS_GetReg1 (SiS_P3c4, 0x14); + SiS_SetReg1 (SiS_P3c4, 0x14, + (USHORT) ((data & 0xFD) | 0x01)); + } + return; + + } else { + /* DDR Dual channel */ + SiS_SetReg1 (SiS_P3c4, 0x13, 0x00); + SiS_SetReg1 (SiS_P3c4, 0x14, 0x02); /* Channel A, 64bit */ + /* should delay */ + SiS_DDR_MRS (); + + SiS_ChannelAB = 0; + SiS_DataBusWidth = 64; + pVideoMemory[0] = 0x01234567L; + pVideoMemory[1] = 0x456789ABL; + pVideoMemory[2] = 0x89ABCDEFL; + pVideoMemory[3] = 0xCDEF0123L; + pVideoMemory[4] = 0x55555555L; + pVideoMemory[5] = 0x55555555L; + pVideoMemory[6] = 0xAAAAAAAAL; + pVideoMemory[7] = 0xAAAAAAAAL; + + if (pVideoMemory[1] == 0x456789ABL) { + if (pVideoMemory[0] == 0x01234567L) { + /* Channel A 64bit */ + return; + } + } else { + if (pVideoMemory[0] == 0x01234567L) { + /* Channel A 32bit */ + SiS_DataBusWidth = 32; + SiS_SetReg1 (SiS_P3c4, 0x14, 0x00); + return; + } + + } + + SiS_SetReg1 (SiS_P3c4, 0x14, 0x03); /* Channel B, 64bit */ + SiS_DDR_MRS (); + + SiS_ChannelAB = 1; + SiS_DataBusWidth = 64; + pVideoMemory[0] = 0x01234567L; + pVideoMemory[1] = 0x456789ABL; + pVideoMemory[2] = 0x89ABCDEFL; + pVideoMemory[3] = 0xCDEF0123L; + pVideoMemory[4] = 0x55555555L; + pVideoMemory[5] = 0x55555555L; + pVideoMemory[6] = 0xAAAAAAAAL; + pVideoMemory[7] = 0xAAAAAAAAL; + if (pVideoMemory[1] == 0x456789ABL) { + /* Channel B 64 */ + if (pVideoMemory[0] == 0x01234567L) { + /* Channel B 64bit */ + return; + } else { + /* error */ + } + } else { + if (pVideoMemory[0] == 0x01234567L) { + /* Channel B 32 */ + SiS_DataBusWidth = 32; + SiS_SetReg1 (SiS_P3c4, 0x14, 0x01); + } else { + /* error */ + } + } + } +} + +int +SiS_SetRank (int index, UCHAR RankNo, UCHAR SiS_ChannelAB, + USHORT DRAMTYPE_TABLE[][5]) +{ + USHORT data; + int RankSize; + + if ((RankNo == 2) && (DRAMTYPE_TABLE[index][0] == 2)) + return 0; + + RankSize = DRAMTYPE_TABLE[index][3] / 2 * SiS_DataBusWidth / 32; + + if (RankNo * RankSize <= 128) { + data = 0; + while ((RankSize >>= 1) > 0) { + data += 0x10; + } + data |= (RankNo - 1) << 2; + data |= (SiS_DataBusWidth / 64) & 2; + data |= SiS_ChannelAB; + SiS_SetReg1 (SiS_P3c4, 0x14, data); + /* should delay */ + SiS_SDR_MRS (); + return 1; + } else + return 0; + +} + +int +SiS_SetDDRChannel (int index, UCHAR ChannelNo, UCHAR SiS_ChannelAB, + USHORT DRAMTYPE_TABLE[][5]) +{ + USHORT data; + int RankSize; + + RankSize = DRAMTYPE_TABLE[index][3] / 2 * SiS_DataBusWidth / 32; + /* RankSize = DRAMTYPE_TABLE[index][3]; */ + if (ChannelNo * RankSize <= 128) { + data = 0; + while ((RankSize >>= 1) > 0) { + data += 0x10; + } + if (ChannelNo == 2) + data |= 0x0C; + + data |= (SiS_DataBusWidth / 32) & 2; + data |= SiS_ChannelAB; + SiS_SetReg1 (SiS_P3c4, 0x14, data); + /* should delay */ + SiS_DDR_MRS (); + return 1; + } else + return 0; + +} + +int +SiS_CheckColumn (int index, USHORT DRAMTYPE_TABLE[][5], ULONG FBAddress) +{ + int i; + ULONG Increment, Position; + + /*Increment = 1<<(DRAMTYPE_TABLE[index][2] + SiS_DataBusWidth / 64 + 1); */ + Increment = 1 << (10 + SiS_DataBusWidth / 64); + + for (i = 0, Position = 0; i < 2; i++) { + *((PULONG) (FBAddress + Position)) = Position; + Position += Increment; + } + + for (i = 0, Position = 0; i < 2; i++) { +/* if (FBAddress[Position]!=Position) */ + if ((*(PULONG) (FBAddress + Position)) != Position) + return 0; + Position += Increment; + } + return 1; +} + +int +SiS_CheckBanks (int index, USHORT DRAMTYPE_TABLE[][5], ULONG FBAddress) +{ + int i; + ULONG Increment, Position; + Increment = 1 << (DRAMTYPE_TABLE[index][2] + SiS_DataBusWidth / 64 + 2); + + for (i = 0, Position = 0; i < 4; i++) { +/* FBAddress[Position]=Position; */ + *((PULONG) (FBAddress + Position)) = Position; + Position += Increment; + } + + for (i = 0, Position = 0; i < 4; i++) { +/* if (FBAddress[Position]!=Position) */ + if ((*(PULONG) (FBAddress + Position)) != Position) + return 0; + Position += Increment; + } + return 1; +} + +int +SiS_CheckRank (int RankNo, int index, USHORT DRAMTYPE_TABLE[][5], + ULONG FBAddress) +{ + int i; + ULONG Increment, Position; + Increment = 1 << (DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] + + DRAMTYPE_TABLE[index][0] + SiS_DataBusWidth / 64 + + RankNo); + + for (i = 0, Position = 0; i < 2; i++) { +/* FBAddress[Position]=Position; */ + *((PULONG) (FBAddress + Position)) = Position; + /* *((PULONG)(FBAddress))=Position; */ + Position += Increment; + } + + for (i = 0, Position = 0; i < 2; i++) { +/* if (FBAddress[Position]!=Position) */ + if ((*(PULONG) (FBAddress + Position)) != Position) + /*if ( (*(PULONG) (FBAddress )) !=Position) */ + return 0; + Position += Increment; + } + return 1; + +} + +int +SiS_CheckDDRRank (int RankNo, int index, USHORT DRAMTYPE_TABLE[][5], + ULONG FBAddress) +{ + ULONG Increment, Position; + USHORT data; + + Increment = 1 << (DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] + + DRAMTYPE_TABLE[index][0] + SiS_DataBusWidth / 64 + + RankNo); + + Increment += Increment / 2; + + Position = 0; + *((PULONG) (FBAddress + Position + 0)) = 0x01234567; + *((PULONG) (FBAddress + Position + 1)) = 0x456789AB; + *((PULONG) (FBAddress + Position + 2)) = 0x55555555; + *((PULONG) (FBAddress + Position + 3)) = 0x55555555; + *((PULONG) (FBAddress + Position + 4)) = 0xAAAAAAAA; + *((PULONG) (FBAddress + Position + 5)) = 0xAAAAAAAA; + + if ((*(PULONG) (FBAddress + 1)) == 0x456789AB) + return 1; + + if ((*(PULONG) (FBAddress + 0)) == 0x01234567) + return 0; + + data = SiS_GetReg1 (SiS_P3c4, 0x14); + data &= 0xF3; + data |= 0x08; + SiS_SetReg1 (SiS_P3c4, 0x14, data); + data = SiS_GetReg1 (SiS_P3c4, 0x15); + data += 0x20; + SiS_SetReg1 (SiS_P3c4, 0x15, data); + + return 1; + +} + +int +SiS_CheckRanks (int RankNo, int index, USHORT DRAMTYPE_TABLE[][5], + ULONG FBAddress) +{ + int r; + + for (r = RankNo; r >= 1; r--) { + if (!SiS_CheckRank (r, index, DRAMTYPE_TABLE, FBAddress)) + return 0; + } + if (!SiS_CheckBanks (index, DRAMTYPE_TABLE, FBAddress)) + return 0; + + if (!SiS_CheckColumn (index, DRAMTYPE_TABLE, FBAddress)) + return 0; + return 1; + +} + +int +SiS_CheckDDRRanks (int RankNo, int index, USHORT DRAMTYPE_TABLE[][5], + ULONG FBAddress) +{ + int r; + + for (r = RankNo; r >= 1; r--) { + if (!SiS_CheckDDRRank (r, index, DRAMTYPE_TABLE, FBAddress)) + return 0; + } + if (!SiS_CheckBanks (index, DRAMTYPE_TABLE, FBAddress)) + return 0; + + if (!SiS_CheckColumn (index, DRAMTYPE_TABLE, FBAddress)) + return 0; + return 1; + +} + +int +SiS_SDRSizing (ULONG FBAddress) +{ + int i; + UCHAR j; + + for (i = 0; i < 13; i++) { + SiS_SetDRAMSizingType (i, SiS_SDRDRAM_TYPE); + for (j = 2; j > 0; j--) { + + if (!SiS_SetRank + (i, (UCHAR) j, SiS_ChannelAB, + SiS_SDRDRAM_TYPE)) continue; + else { + if (SiS_CheckRanks + (j, i, SiS_SDRDRAM_TYPE, + FBAddress)) return 1; + } + } + } + return 0; +} + +int +SiS_DDRSizing (ULONG FBAddress) +{ + + int i; + UCHAR j; + + for (i = 0; i < 4; i++) { + SiS_SetDRAMSizingType (i, SiS_DDRDRAM_TYPE); + SiS_DisableChannelInterleaving (i, SiS_DDRDRAM_TYPE); + for (j = 2; j > 0; j--) { + SiS_SetDDRChannel (i, j, SiS_ChannelAB, + SiS_DDRDRAM_TYPE); + if (!SiS_SetRank + (i, (UCHAR) j, SiS_ChannelAB, + SiS_DDRDRAM_TYPE)) continue; + else { + if (SiS_CheckDDRRanks + (j, i, SiS_DDRDRAM_TYPE, + FBAddress)) return 1; + } + } + } + return 0; +} + +/* + + check if read cache pointer is correct + +*/ +void +SiS_VerifyMclk (ULONG FBAddr) +{ + PUCHAR pVideoMemory = (PUCHAR) FBAddr; + UCHAR i, j; + USHORT Temp, SR21; + + pVideoMemory[0] = 0xaa; /* alan */ + pVideoMemory[16] = 0x55; /* note: PCI read cache is off */ + + if ((pVideoMemory[0] != 0xaa) || (pVideoMemory[16] != 0x55)) { + for (i = 0, j = 16; i < 2; i++, j += 16) { + SR21 = SiS_GetReg1 (SiS_P3c4, 0x21); + Temp = SR21 & 0xFB; /* disable PCI post write buffer empty gating */ + SiS_SetReg1 (SiS_P3c4, 0x21, Temp); + + Temp = SiS_GetReg1 (SiS_P3c4, 0x3C); + Temp = Temp | 0x01; /*MCLK reset */ + SiS_SetReg1 (SiS_P3c4, 0x3C, Temp); + Temp = SiS_GetReg1 (SiS_P3c4, 0x3C); + Temp = Temp & 0xFE; /* MCLK normal operation */ + SiS_SetReg1 (SiS_P3c4, 0x3C, Temp); + SiS_SetReg1 (SiS_P3c4, 0x21, SR21); + + pVideoMemory[16 + j] = j; + if (pVideoMemory[16 + j] == j) { + pVideoMemory[j] = j; + break; + } + } + } + +} + +int +Is315E (void) +{ + USHORT data; + + data = SiS_GetReg1 (SiS_P3d4, 0x5F); + if (data & 0x10) + return 1; + else + return 0; +} + +void +SiS_SetDRAMSize_310 (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + ULONG ROMAddr = (ULONG) HwDeviceExtension->pjVirtualRomBase; + ULONG FBAddr = (ULONG) HwDeviceExtension->pjVideoMemoryAddress; + /*USHORT BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress; */ + USHORT data; + +#ifdef SIS301 + /*SiS_SetReg1(SiS_P3d4,0x30,0x40); */ +#endif +#ifdef SIS302 + SiS_SetReg1 (SiS_P3d4, 0x30, 0x4D); /* alan,should change value */ + SiS_SetReg1 (SiS_P3d4, 0x31, 0xc0); /* alan,should change value */ + SiS_SetReg1 (SiS_P3d4, 0x34, 0x3F); /* alan,should change value */ +#endif + + SiSSetMode (HwDeviceExtension, 0x2e); + + data = SiS_GetReg1 (SiS_P3c4, 0x21); + SiS_SetReg1 (SiS_P3c4, 0x21, (USHORT) (data & 0xDF)); /* disable read cache */ + + data = SiS_GetReg1 (SiS_P3c4, 0x1); + data = data | 0x20; + SiS_SetReg1 (SiS_P3c4, 0x01, data); /* Turn OFF Display */ + + data = SiS_GetReg1 (SiS_P3c4, 0x16); + SiS_SetReg1 (SiS_P3c4, 0x16, (USHORT) (data | 0x0F)); /* assume lowest speed DRAM */ + + SiS_SetDRAMModeRegister (ROMAddr); + SiS_DisableRefresh (); + SiS_CheckBusWidth_310 (ROMAddr, FBAddr); + + SiS_VerifyMclk (FBAddr); /* alan 2000/7/3 */ + + if (SiS_Get310DRAMType (ROMAddr) < 2) { + SiS_SDRSizing (FBAddr); + } else { + SiS_DDRSizing (FBAddr); + } + + if (Is315E ()) { + data = SiS_GetReg1 (SiS_P3c4, 0x14); + if ((data & 0x0C) == 0x0C) { /* dual channel */ + if ((data & 0xF0) > 0x40) + data = (data & 0x0F) | 0x40; + } else { /* single channel */ + + if ((data & 0xF0) > 0x50) + data = (data & 0x0F) | 0x50; + } + + } + + SiS_SetReg1 (SiS_P3c4, 0x16, SiS_SR15[1][SiS_RAMType]); /* restore SR16 */ + + SiS_EnableRefresh (ROMAddr); + data = SiS_GetReg1 (SiS_P3c4, 0x21); + SiS_SetReg1 (SiS_P3c4, 0x21, (USHORT) (data | 0x20)); /* enable read cache */ + +} +#endif + +void +SiS_SetMemoryClock (ULONG ROMAddr) +{ + SiS_SetReg1 (SiS_P3c4, 0x28, SiS_MCLKData[SiS_RAMType].SR28); + SiS_SetReg1 (SiS_P3c4, 0x29, SiS_MCLKData[SiS_RAMType].SR29); + SiS_SetReg1 (SiS_P3c4, 0x2A, SiS_MCLKData[SiS_RAMType].SR2A); + SiS_SetReg1 (SiS_P3c4, 0x2E, SiS_ECLKData[SiS_RAMType].SR2E); + SiS_SetReg1 (SiS_P3c4, 0x2F, SiS_ECLKData[SiS_RAMType].SR2F); + SiS_SetReg1 (SiS_P3c4, 0x30, SiS_ECLKData[SiS_RAMType].SR30); + +#ifdef CONFIG_FB_SIS_315 + if (Is315E ()) { + SiS_SetReg1 (SiS_P3c4, 0x28, 0x3B); /* 143 */ + SiS_SetReg1 (SiS_P3c4, 0x29, 0x22); + SiS_SetReg1 (SiS_P3c4, 0x2E, 0x3B); /* 143 */ + SiS_SetReg1 (SiS_P3c4, 0x2F, 0x22); + } +#endif + +} + +/* +========================================= + ======== SiS SetMode Function ========== +========================================= +*/ +BOOLEAN +SiSSetMode (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo) +{ + ULONG temp; + USHORT ModeIdIndex, KeepLockReg; + ULONG ROMAddr = (ULONG) HwDeviceExtension->pjVirtualRomBase; + /*ULONG FBAddr = (ULONG)HwDeviceExtension->pjVideoMemoryAddress; */ + USHORT BaseAddr = (USHORT) HwDeviceExtension->ulIOAddress; + +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || /* 05/02/01 ynlai for sis550 */ + (HwDeviceExtension->jChipType == SIS_315PRO) || + (HwDeviceExtension->jChipType == SIS_550) || + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) /* 09/03/01 chiawen for 650 */ + InitTo310Pointer (); +#endif + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730) || + (HwDeviceExtension->jChipType == SIS_300)) + InitTo300Pointer (); +#endif + + SiS_P3c4 = BaseAddr + 0x14; + SiS_P3d4 = BaseAddr + 0x24; + SiS_P3c0 = BaseAddr + 0x10; + SiS_P3ce = BaseAddr + 0x1e; + SiS_P3c2 = BaseAddr + 0x12; + SiS_P3ca = BaseAddr + 0x1a; + SiS_P3c6 = BaseAddr + 0x16; + SiS_P3c7 = BaseAddr + 0x17; + SiS_P3c8 = BaseAddr + 0x18; + SiS_P3c9 = BaseAddr + 0x19; + SiS_P3da = BaseAddr + 0x2A; + SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; + SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10; + SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12; + SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14; + SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2; + + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_CH7005 = 0; + SiS_IF_DEF_HiVision = 0; + SiS_IF_DEF_DSTN = 0; /*for 550 dstn */ + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730) || + (HwDeviceExtension->jChipType == SIS_550) || + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) { /* 09/03/01 chiawen for 650 */ + temp = SiS_GetReg1 (SiS_P3d4, 0x37); + temp = (temp & 0x0E) >> 1; + if ((temp == 0) || (temp == 1)) { /* for 301 */ + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_CH7005 = 0; + SiS_IF_DEF_TRUMPION = 0; + } + if ((temp >= 2) && (temp <= 5)) { + SiS_IF_DEF_LVDS = 1; + } + if (temp == 3) + SiS_IF_DEF_TRUMPION = 1; + if ((temp == 4) || (temp == 5)) + SiS_IF_DEF_CH7005 = 1; + } else { + SiS_IF_DEF_LVDS = 0; + SiS_IF_DEF_TRUMPION = 0; + SiS_IF_DEF_CH7005 = 0; + } + + if (ModeNo & 0x80) { + ModeNo = ModeNo & 0x7F; + flag_clearbuffer = 0; + } else { + flag_clearbuffer = 1; + } + + SiS_PresetScratchregister (SiS_P3d4, HwDeviceExtension); /*add for CRT2 */ + KeepLockReg = SiS_GetReg1 (SiS_P3c4, 0x05); + SiS_SetReg1 (SiS_P3c4, 0x05, 0x86); /* 1.Openkey */ + temp = SiS_SearchModeID (ROMAddr, ModeNo, &ModeIdIndex); /* 2.Get ModeID Table */ + if (temp == 0) + return (0); + /*301b */ + SiS_GetVBType (BaseAddr); + /*end 301b */ + SiS_GetVBInfo301 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, HwDeviceExtension); /*add for CRT2 */ + SiS_GetLCDResInfo301 (ROMAddr, SiS_P3d4, ModeNo, ModeIdIndex); /*add for CRT2 */ + + temp = SiS_CheckMemorySize (ROMAddr, HwDeviceExtension, ModeNo, ModeIdIndex); /*3.Check memory size */ + if (temp == 0) + return (0); + if (SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) { /*301b */ + SiS_SetCRT1Group (ROMAddr, HwDeviceExtension, ModeNo, + ModeIdIndex); + } else { + if (!(SiS_VBInfo & SwitchToCRT2)) { + SiS_SetCRT1Group (ROMAddr, HwDeviceExtension, ModeNo, + ModeIdIndex); + } + } + + if (SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA)) { /*301b */ + switch (HwDeviceExtension->ujVBChipID) { +/*karl*/ + case VB_CHIP_301: + case VB_CHIP_301B: + SiS_SetCRT2Group301 (BaseAddr, ROMAddr, ModeNo, HwDeviceExtension); /*add for CRT2 */ + break; + case VB_CHIP_302: + SiS_SetCRT2Group301 (BaseAddr, ROMAddr, ModeNo, + HwDeviceExtension); + break; + case VB_CHIP_303: +/* SetCRT2Group302(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension); add for CRT2 */ + break; + case VB_CHIP_UNKNOWN: /*add for lvds ch7005 */ + temp = SiS_GetReg1 (SiS_P3d4, 0x37); + if (temp & + (ExtChipLVDS | ExtChipTrumpion | ExtChipCH7005)) { + SiS_SetCRT2Group301 (BaseAddr, ROMAddr, ModeNo, + HwDeviceExtension); + } + break; + } + } + if (KeepLockReg == 0xA1) + SiS_SetReg1 (SiS_P3c4, 0x05, 0x86); /* 05/02/01 ynlai */ + else + SiS_SetReg1 (SiS_P3c4, 0x05, 0x00); + return TRUE; +} + +void +SiS_SetCRT1Group (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT StandTableIndex, RefreshRateTableIndex; + USHORT temp; + + /*SiS_SetReg1(SiS_P3d4,0x34,ModeNo); */ + SiS_CRT1Mode = ModeNo; + /* set CR34->CRT1 ModeNofor CRT2 FIFO */ + StandTableIndex = SiS_GetModePtr (ROMAddr, ModeNo, ModeIdIndex); /* 4.GetModePtr */ + SiS_SetSeqRegs (ROMAddr, StandTableIndex); /* 5.SetSeqRegs */ + SiS_SetMiscRegs (ROMAddr, StandTableIndex); /* 6.SetMiscRegs */ + SiS_SetCRTCRegs (ROMAddr, HwDeviceExtension, StandTableIndex); /* 7.SetCRTCRegs */ + SiS_SetATTRegs (ROMAddr, StandTableIndex); /* 8.SetATTRegs */ + SiS_SetGRCRegs (ROMAddr, StandTableIndex); /* 9.SetGRCRegs */ + SiS_ClearExt1Regs (); /* 10.Clear Ext1Regs */ + temp = ~ProgrammingCRT2; /* 11.GetRatePtr */ + SiS_SetFlag = SiS_SetFlag & temp; + SiS_SelectCRT2Rate = 0; + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetFlag = SiS_SetFlag | ProgrammingCRT2; + /* SiS_SelectCRT2Rate=4; */ + } + } + /*end 301b */ + + RefreshRateTableIndex = SiS_GetRatePtrCRT2 (ROMAddr, ModeNo, ModeIdIndex); /* 11.GetRatePtr */ + + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (!(SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_SetFlag = SiS_SetFlag & (~ProgrammingCRT2); + } + } + /*end 301b */ + + if (RefreshRateTableIndex != 0xFFFF) { + SiS_SetSync (ROMAddr, RefreshRateTableIndex); /* 12.SetSync */ + SiS_SetCRT1CRTC (ROMAddr, ModeNo, ModeIdIndex, RefreshRateTableIndex); /* 13.SetCRT1CRTC */ + SiS_SetCRT1Offset (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); /* 14.SetCRT1Offset */ + SiS_SetCRT1VCLK (ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension, RefreshRateTableIndex); /* 15.SetCRT1VCLK */ + } +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_540)) { + SiS_SetCRT1FIFO2 (ROMAddr, ModeNo, HwDeviceExtension, + RefreshRateTableIndex); + } +#endif +#ifdef CONFIG_FB_SIS_315 + if (HwDeviceExtension->jChipType >= SIS_315H) { + SiS_SetCRT1FIFO (ROMAddr, ModeNo, HwDeviceExtension); + } +#endif + SiS_SetCRT1ModeRegs (ROMAddr, HwDeviceExtension, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + SiS_SetVCLKState (ROMAddr, HwDeviceExtension, ModeNo, + RefreshRateTableIndex); +#ifdef CONFIG_FB_SIS_315 + if (HwDeviceExtension->jChipType > SIS_315H) + SiS_SetInterlace (ROMAddr, ModeNo, RefreshRateTableIndex); +#endif + SiS_LoadDAC (ROMAddr, ModeNo, ModeIdIndex); + if (flag_clearbuffer) + SiS_ClearBuffer (HwDeviceExtension, ModeNo); + + if (!(SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA))) { /*301b */ + SiS_LongWait (); + SiS_DisplayOn (); + } +} + +void +SiS_GetVBType (USHORT BaseAddr) +{ + USHORT flag; + + flag = SiS_GetReg1 (SiS_Part4Port, 0x00); + if (flag >= 2) + SiS_VBType = VB_SIS302B; + else { + flag = SiS_GetReg1 (SiS_Part4Port, 0x01); + if (flag >= 0xB0) + SiS_VBType = VB_SIS301B; + else + SiS_VBType = VB_SIS301; + + flag = SiS_GetReg1 (SiS_Part4Port, 0x23); /*301dlvds */ + if (!(flag & 0x02)) + SiS_VBType = SiS_VBType | VB_NoLCD; + } + +} + +/* win2000 MM adapter not support standard mode */ +BOOLEAN +SiS_SearchModeID (ULONG ROMAddr, USHORT ModeNo, USHORT * ModeIdIndex) +{ + PUCHAR VGA_INFO = "\0x11"; + + if (ModeNo <= 5) + ModeNo |= 1; + if (ModeNo <= 0x13) { + /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(SiS_SModeIDTable)/sizeof(SiS_StStruct);(*ModeIdIndex)++) */ + for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { + if (SiS_SModeIDTable[*ModeIdIndex].St_ModeID == ModeNo) + break; + if (SiS_SModeIDTable[*ModeIdIndex].St_ModeID == 0xFF) + return FALSE; + } + +#ifdef TC + VGA_INFO = (PUCHAR) MK_FP (0, 0x489); +#endif + if (ModeNo == 0x07) { + if ((*VGA_INFO & 0x10) != 0) + (*ModeIdIndex)++; /* 400 lines */ + /* else 350 lines */ + } + if (ModeNo <= 3) { + if ((*VGA_INFO & 0x80) == 0) { + (*ModeIdIndex)++; + if ((*VGA_INFO & 0x10) != 0) + (*ModeIdIndex)++;; /* 400 lines */ + /* else 350 lines */ + } + /* else 200 lines */ + } + } else { + /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(SiS_EModeIDTable)/sizeof(SiS_ExtStruct);(*ModeIdIndex)++) */ + for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { + if (SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == ModeNo) + break; + if (SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF) + return FALSE; + } + } + return TRUE; +} + +/*add for 300 oem util for search VBModeID*/ +BOOLEAN +SiS_SearchVBModeID (ULONG ROMAddr, USHORT ModeNo) +{ + USHORT ModeIdIndex; + + // PUCHAR VGA_INFO; + + if (ModeNo <= 5) + ModeNo |= 1; + /* for (ModeIdIndex=0;ModeIdIndex<sizeof(SiS_SModeIDTable)/sizeof(SiS_StStruct);(*ModeIdIndex)++) */ + for (ModeIdIndex = 0;; (ModeIdIndex)++) { + if (SiS_VBModeIDTable[ModeIdIndex].ModeID == ModeNo) + break; + if (SiS_VBModeIDTable[ModeIdIndex].ModeID == 0xFF) + return FALSE; + } +#ifdef TC + VGA_INFO = (PUCHAR) MK_FP (0, 0x489); + if (ModeNo == 0x07) { + if ((*VGA_INFO & 0x10) != 0) + (ModeIdIndex)++; /* 400 lines */ + /* else 350 lines */ + } + if (ModeNo <= 3) { + if ((*VGA_INFO & 0x80) == 0) { + (ModeIdIndex)++; + if ((*VGA_INFO & 0x10) != 0) + (ModeIdIndex)++;; /* 400 lines */ + /* else 350 lines */ + } + /* else 200 lines */ + } +#endif + return ((BOOLEAN) ModeIdIndex); +} + +/*end*/ + +/* win2000 MM adapter not support standard mode! */ + +BOOLEAN +SiS_CheckMemorySize (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT memorysize; + USHORT modeflag; + USHORT temp; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + +/* ModeType=modeflag&ModeInfoFlag; Get mode type */ + + memorysize = modeflag & MemoryInfoFlag; + memorysize = memorysize > MemorySizeShift; + memorysize++; /* Get memory size */ + + temp = SiS_GetReg1 (SiS_P3c4, 0x14); /* Get DRAM Size */ + if ((HwDeviceExtension->jChipType == SIS_315H) || + (HwDeviceExtension->jChipType == SIS_315PRO)) { + temp = 1 << ((temp & 0x0F0) >> 4); + if ((temp & 0x0c) == 0x08) { /* DDR asymetric */ + temp += temp / 2; + } else { + if ((temp & 0x0c) != 0) { + temp <<= 1; + } + } + } else { /* 300, 540 , 630 */ + + temp = temp & 0x3F; + temp++; + /* temp=1 << ((temp&0x0F0)>>4); */ + } + + if ((HwDeviceExtension->jChipType == SIS_550) || /* 05/02/01 ynlai for sis550 */ + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) { /* 09/03/01 chiawen for 650 */ + return (TRUE); + } + + if (temp < memorysize) + return (FALSE); + else + return (TRUE); +} + +UCHAR +SiS_GetModePtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + UCHAR index; + + if (ModeNo <= 0x13) { + index = SiS_SModeIDTable[ModeIdIndex].St_StTableIndex; + } else { + if (SiS_ModeType <= 0x02) + index = 0x1B; /* 02 -> ModeEGA */ + else + index = 0x0F; + } + + return index; /* Get SiS_StandTable index */ +} + +void +SiS_SetSeqRegs (ULONG ROMAddr, USHORT StandTableIndex) +{ + UCHAR SRdata; + USHORT i; + + SiS_SetReg1 (SiS_P3c4, 0x00, 0x03); /* Set SR0 */ + SRdata = SiS_StandTable[StandTableIndex].SR[0]; + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetCRT2ToLCDA) { + SRdata = SRdata | 0x01; + } + } + + /*end 301b */ + + if (SiS_IF_DEF_LVDS == 1) { + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_VBInfo & SetInSlaveMode) { + SRdata = SRdata | 0x01; /* 8 dot clock */ + } + } + } + if (SiS_VBInfo & SetCRT2ToLCD) { + if (SiS_VBInfo & SetInSlaveMode) { + SRdata = SRdata | 0x01; /* 8 dot clock */ + } + } + } + + SRdata = SRdata | 0x20; /* screen off */ + SiS_SetReg1 (SiS_P3c4, 0x01, SRdata); /* Set SR1 */ + for (i = 02; i <= 04; i++) { + SRdata = SiS_StandTable[StandTableIndex].SR[i - 1]; /* Get SR2,3,4 from file */ + SiS_SetReg1 (SiS_P3c4, i, SRdata); /* Set SR2 3 4 */ + } +} + +void +SiS_SetMiscRegs (ULONG ROMAddr, USHORT StandTableIndex) +{ + UCHAR Miscdata; + + Miscdata = SiS_StandTable[StandTableIndex].MISC; /* Get Misc from file */ + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetCRT2ToLCDA) { + Miscdata = Miscdata | 0x0C; + } + } + /*end 301b */ + SiS_SetReg3 (SiS_P3c2, Miscdata); /* Set Misc(3c2) */ +} + +void +SiS_SetCRTCRegs (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT StandTableIndex) +{ + UCHAR CRTCdata; + USHORT i; + + CRTCdata = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x11); + CRTCdata = CRTCdata & 0x7f; + SiS_SetReg1 (SiS_P3d4, 0x11, CRTCdata); /* Unlock CRTC */ + + for (i = 0; i <= 0x18; i++) { + CRTCdata = SiS_StandTable[StandTableIndex].CRTC[i]; /* Get CRTC from file */ + SiS_SetReg1 (SiS_P3d4, i, CRTCdata); /* Set CRTC(3d4) */ + } + if ((HwDeviceExtension->jChipType == SIS_630) && + (HwDeviceExtension->jChipRevision == 0x30)) { /* for 630S0 */ + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { + SiS_SetReg1 (SiS_P3d4, 0x18, 0xFE); + } + } + } +} + +void +SiS_SetATTRegs (ULONG ROMAddr, USHORT StandTableIndex) +{ + UCHAR ARdata; + USHORT i; + + for (i = 0; i <= 0x13; i++) { + ARdata = SiS_StandTable[StandTableIndex].ATTR[i]; /* Get AR for file */ + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetCRT2ToLCDA) { + if (i == 0x13) { + ARdata = 0; + } + } + } + /*end 301b */ + if (SiS_IF_DEF_LVDS == 1) { /*for LVDS */ + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_VBInfo & SetInSlaveMode) { + if (i == 0x13) { + ARdata = 0; + } + } + } + } + if (SiS_VBInfo & SetCRT2ToLCD) { + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_LCDInfo & LCDNonExpanding) { + if (i == 0x13) { + ARdata = 0; + } + } + } + } + } + SiS_GetReg2 (SiS_P3da); /* reset 3da */ + SiS_SetReg3 (SiS_P3c0, i); /* set index */ + SiS_SetReg3 (SiS_P3c0, ARdata); /* set data */ + } + SiS_GetReg2 (SiS_P3da); /* reset 3da */ + SiS_SetReg3 (SiS_P3c0, 0x14); /* set index */ + SiS_SetReg3 (SiS_P3c0, 0x00); /* set data */ + + SiS_GetReg2 (SiS_P3da); /* Enable Attribute */ + SiS_SetReg3 (SiS_P3c0, 0x20); +} + +void +SiS_SetGRCRegs (ULONG ROMAddr, USHORT StandTableIndex) +{ + UCHAR GRdata; + USHORT i; + + for (i = 0; i <= 0x08; i++) { + GRdata = SiS_StandTable[StandTableIndex].GRC[i]; /* Get GR from file */ + SiS_SetReg1 (SiS_P3ce, i, GRdata); /* Set GR(3ce) */ + } + + if (SiS_ModeType > ModeVGA) { + GRdata = (UCHAR) SiS_GetReg1 (SiS_P3ce, 0x05); + GRdata = GRdata & 0xBF; /* 256 color disable */ + SiS_SetReg1 (SiS_P3ce, 0x05, GRdata); + } +} + +void +SiS_ClearExt1Regs () +{ + USHORT i; + + for (i = 0x0A; i <= 0x0E; i++) + SiS_SetReg1 (SiS_P3c4, i, 0x00); /* Clear SR0A-SR0E */ +} + +void +SiS_SetSync (ULONG ROMAddr, USHORT RefreshRateTableIndex) +{ + USHORT sync; + USHORT temp; + + sync = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8; /* di+0x00 */ + + sync = sync & 0xC0; + temp = 0x2F; + temp = temp | sync; + SiS_SetReg3 (SiS_P3c2, temp); /* Set Misc(3c2) */ +} + +void +SiS_SetCRT1CRTC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + UCHAR index; + UCHAR data; + USHORT temp, tempah, i, modeflag, j; + USHORT ResInfo, DisplayType; + SiS_LCDACRT1DataStruct *LCDACRT1Ptr = NULL; + if ((SiS_VBType & VB_SIS302B) && (SiS_VBInfo & SetCRT2ToLCDA)) { + /*add crt1ptr */ + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + temp = + SiS_GetLCDACRT1Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &ResInfo, + &DisplayType); + + switch (DisplayType) { + case 0: + LCDACRT1Ptr = SiS_LCDACRT1800x600_1; + break; + case 1: + LCDACRT1Ptr = SiS_LCDACRT11024x768_1; + break; + case 2: + LCDACRT1Ptr = SiS_LCDACRT11280x1024_1; + break; + case 3: + LCDACRT1Ptr = SiS_LCDACRT1800x600_1_H; + break; + case 4: + LCDACRT1Ptr = SiS_LCDACRT11024x768_1_H; + break; + case 5: + LCDACRT1Ptr = SiS_LCDACRT11280x1024_1_H; + break; + case 6: + LCDACRT1Ptr = SiS_LCDACRT1800x600_2; + break; + case 7: + LCDACRT1Ptr = SiS_LCDACRT11024x768_2; + break; + case 8: + LCDACRT1Ptr = SiS_LCDACRT11280x1024_2; + break; + case 9: + LCDACRT1Ptr = SiS_LCDACRT1800x600_2_H; + break; + case 10: + LCDACRT1Ptr = SiS_LCDACRT11024x768_2_H; + break; + case 11: + LCDACRT1Ptr = SiS_LCDACRT11280x1024_2_H; + break; + /*case 12: LCDACRT1Ptr = SiS_CHTVCRT1UNTSC; break; + case 13: LCDACRT1Ptr = SiS_CHTVCRT1ONTSC; break; + case 14: LCDACRT1Ptr = SiS_CHTVCRT1UPAL; break; + case 15: LCDACRT1Ptr = SiS_CHTVCRT1OPAL; break; */ + } + + tempah = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x11); /*unlock cr0-7 */ + tempah = tempah & 0x7F; + SiS_SetReg1 (SiS_P3d4, 0x11, tempah); + tempah = (LCDACRT1Ptr + ResInfo)->CR[0]; + SiS_SetReg1 (SiS_P3d4, 0x0, tempah); + for (i = 0x01, j = 1; i <= 0x07; i++, j++) { + tempah = (LCDACRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } +/* for(i=0x06,j=5;i<=0x07;i++,j++){ + tempah = (LCDACRT1Ptr+ResInfo)->CR[j]; + SiS_SetReg1(SiS_P3d4,i,tempah); + }*/ + for (i = 0x10, j = 8; i <= 0x12; i++, j++) { + tempah = (LCDACRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x15, j = 11; i <= 0x16; i++, j++) { + tempah = (LCDACRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + + for (i = 0x0A, j = 13; i <= 0x0C; i++, j++) { + tempah = (LCDACRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3c4, i, tempah); + } + + tempah = (LCDACRT1Ptr + ResInfo)->CR[16]; + tempah = tempah & 0x0E0; + SiS_SetReg1 (SiS_P3c4, 0x0E, tempah); + + tempah = (LCDACRT1Ptr + ResInfo)->CR[16]; + tempah = tempah & 0x01; + tempah = tempah << 5; + if (modeflag & DoubleScanMode) { + tempah = tempah | 0x080; + } + SiS_SetRegANDOR (SiS_P3d4, 0x09, ~0x020, tempah); + if (SiS_ModeType > 0x03) + SiS_SetReg1 (SiS_P3d4, 0x14, 0x4F); +/*end 301b*/ + } else { + index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; /* Get index */ + index = index & 0x3F; + + data = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x11); + data = data & 0x7F; + SiS_SetReg1 (SiS_P3d4, 0x11, data); /* Unlock CRTC */ + + for (i = 0, j = 0; i <= 07; i++, j++) { + data = SiS_CRT1Table[index].CR[i]; + SiS_SetReg1 (SiS_P3d4, j, data); + } + for (j = 0x10; i <= 10; i++, j++) { + data = SiS_CRT1Table[index].CR[i]; + SiS_SetReg1 (SiS_P3d4, j, data); + } + for (j = 0x15; i <= 12; i++, j++) { + data = SiS_CRT1Table[index].CR[i]; + SiS_SetReg1 (SiS_P3d4, j, data); + } + for (j = 0x0A; i <= 15; i++, j++) { + data = SiS_CRT1Table[index].CR[i]; + SiS_SetReg1 (SiS_P3c4, j, data); + } + + data = SiS_CRT1Table[index].CR[16]; + data = data & 0xE0; + SiS_SetReg1 (SiS_P3c4, 0x0E, data); + + data = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x09); + data = data & 0xDF; /* clear CR9 D[5] */ + i = SiS_CRT1Table[index].CR[16]; + i = i & 0x01; + i = i << 5; + data = data | i; + + if (ModeNo <= 0x13) + i = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + else + i = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + + i = i & DoubleScanMode; + if (i) + data = data | 0x80; + SiS_SetReg1 (SiS_P3d4, 0x09, data); + + if (SiS_ModeType > 0x03) + SiS_SetReg1 (SiS_P3d4, 0x14, 0x4F); + } +} +void +SiS_SetCRT1Offset (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp, ah, al; + USHORT temp2, i; + USHORT DisplayUnit; + + /* Alan */ + temp = SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo; + if (HwDeviceExtension->jChipType >= SIS_315H) { + temp = temp >> 8; /* sis310 *//* index */ + } else { + temp = temp >> 4; /* sis300 *//* index */ + } + temp = SiS_ScreenOffset[temp]; + if ((ModeNo >= 0x7C) && (ModeNo <= 0x7E)) { + temp = 0x6B; + temp2 = ModeNo - 0x7C; + } else { + temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + temp2 = temp2 & InterlaceMode; + if (temp2) + temp = temp << 1; + temp2 = SiS_ModeType - ModeEGA; + } + switch (temp2) { + case 0: + temp2 = 1; + break; + case 1: + temp2 = 2; + break; + case 2: + temp2 = 4; + break; + case 3: + temp2 = 4; + break; + case 4: + temp2 = 6; + break; + case 5: + temp2 = 8; + break; + } + temp = temp * temp2; + DisplayUnit = temp; + + temp2 = temp; + temp = temp >> 8; /* ah */ + temp = temp & 0x0F; + i = SiS_GetReg1 (SiS_P3c4, 0x0E); + i = i & 0xF0; + i = i | temp; + SiS_SetReg1 (SiS_P3c4, 0x0E, i); + + temp = (UCHAR) temp2; + temp = temp & 0xFF; /* al */ + SiS_SetReg1 (SiS_P3d4, 0x13, temp); + + temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + temp2 = temp2 & InterlaceMode; + if (temp2) + DisplayUnit >>= 1; + + DisplayUnit = DisplayUnit << 5; + ah = (DisplayUnit & 0xff00) >> 8; + al = DisplayUnit & 0x00ff; + if (al == 0) + ah = ah + 1; + else + ah = ah + 2; + SiS_SetReg1 (SiS_P3c4, 0x10, ah); +} + +void +SiS_SetCRT1VCLK (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + UCHAR index, data; + USHORT vclkindex; + if (SiS_IF_DEF_LVDS == 1) { + vclkindex = + SiS_GetVCLK2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + data = SiS_GetReg1 (SiS_P3c4, 0x31) & 0xCF; + SiS_SetReg1 (SiS_P3c4, 0x31, data); + + data = SiS_VCLKData[vclkindex].SR2B; + SiS_SetReg1 (SiS_P3c4, 0x2B, data); + data = SiS_VCLKData[vclkindex].SR2C; + SiS_SetReg1 (SiS_P3c4, 0x2C, data); + + if (HwDeviceExtension->jChipType < SIS_315H) + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x80); + else + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x01); + + } + else + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA) && (SiS_IF_DEF_LVDS == 0)) { + vclkindex = + SiS_GetVCLK2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + data = SiS_GetReg1 (SiS_P3c4, 0x31) & 0xCF; + SiS_SetReg1 (SiS_P3c4, 0x31, data); + + data = SiS_VBVCLKData[vclkindex].Part4_A; + SiS_SetReg1 (SiS_P3c4, 0x2B, data); + data = SiS_VBVCLKData[vclkindex].Part4_B; + SiS_SetReg1 (SiS_P3c4, 0x2C, data); + + if (HwDeviceExtension->jChipType < SIS_315H) + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x80); /* for300 series */ + else + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x01); + + } else { + index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + /*if(HwDeviceExtension->jChipType < SIS_315H) { */ + index = index & 0x3F; + /*} */ + data = SiS_GetReg1 (SiS_P3c4, 0x31) & 0xCF; +/*SiS_SetReg1(SiS_P3c4,0x31,0x00); *//* for300 */ + SiS_SetReg1 (SiS_P3c4, 0x31, data); + SiS_SetReg1 (SiS_P3c4, 0x2B, SiS_VCLKData[index].SR2B); + SiS_SetReg1 (SiS_P3c4, 0x2C, SiS_VCLKData[index].SR2C); + if (HwDeviceExtension->jChipType < SIS_315H) + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x80); /* for300 series */ + else + SiS_SetReg1 (SiS_P3c4, 0x2D, 0x01); /* for310 series */ + } +} +void +SiS_IsLowResolution (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT data; + USHORT ModeFlag; + + data = SiS_GetReg1 (SiS_P3c4, 0x0F); + data = data & 0x7F; + SiS_SetReg1 (SiS_P3c4, 0x0F, data); + + if (ModeNo > 0x13) { + ModeFlag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + if ((ModeFlag & HalfDCLK) && (ModeFlag & DoubleScanMode)) { + data = SiS_GetReg1 (SiS_P3c4, 0x0F); + data = data | 0x80; + SiS_SetReg1 (SiS_P3c4, 0x0F, data); + data = SiS_GetReg1 (SiS_P3c4, 0x01); + data = data & 0xF7; + SiS_SetReg1 (SiS_P3c4, 0x01, data); + } + } +} + +void +SiS_SetCRT1ModeRegs (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT data, data2, data3; + USHORT infoflag = 0, modeflag; + USHORT resindex, xres; + + if (ModeNo > 0x13) { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + } else { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ModeFlag */ + } + SiS_SetRegANDOR (SiS_P3c4, 0x1F, 0x3F, 0x00); + if (ModeNo > 0x13) + data = infoflag; + else + data = 0; + data2 = 0; + if (ModeNo > 0x13) { + if (SiS_ModeType > 0x02) { + data2 = data2 | 0x02; + data3 = SiS_ModeType - ModeVGA; + data3 = data3 << 2; + data2 = data2 | data3; + } + } + data = data & InterlaceMode; + if (data) + data2 = data2 | 0x20; + SiS_SetReg1 (SiS_P3c4, 0x06, data2); + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_730)) { + resindex = SiS_GetResInfo (ROMAddr, ModeNo, ModeIdIndex); + if (ModeNo <= 0x13) { + xres = SiS_StResInfo[resindex].HTotal; + } else { + xres = SiS_ModeResInfo[resindex].HTotal; /* xres->ax */ + } + data = 0x0000; + if (infoflag & InterlaceMode) { + if (xres == 1024) + data = 0x0035; + if (xres == 1280) + data = 0x0048; + } + data2 = data & 0x00FF; + SiS_SetRegANDOR (SiS_P3d4, 0x19, 0xFF, data2); + data2 = (data & 0xFF00) >> 8; + SiS_SetRegANDOR (SiS_P3d4, 0x19, 0xFC, data2); + } + if (modeflag & HalfDCLK) { + SiS_SetRegANDOR (SiS_P3c4, 0x01, 0xFF, 0x01); + } + + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_730)) { + } else { + if (modeflag & LineCompareOff) { + SiS_SetRegANDOR (SiS_P3c4, 0x0F, 0xF7, 0x08); + } else { + SiS_SetRegANDOR (SiS_P3c4, 0x0F, 0xF7, 0x00); + } + } + + data = 0x60; + if (SiS_ModeType != ModeText) { + data = data ^ 0x60; + if (SiS_ModeType != ModeEGA) { + data = data ^ 0xA0; + } + } + SiS_SetRegANDOR (SiS_P3c4, 0x21, 0x1F, data); +} + +void +SiS_SetVCLKState (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT RefreshRateTableIndex) +{ + USHORT data, data2 = 0; + USHORT VCLK; + UCHAR index; + + if (ModeNo <= 0x13) + VCLK = 0; + else { + index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + /*if(HwDeviceExtension->jChipType < SIS_315H) { */ + index = index & 0x3F; + /*} */ + VCLK = SiS_VCLKData[index].CLOCK; + } + + if (HwDeviceExtension->jChipType < SIS_315H) { + data2 = 0x00; + if (VCLK > 150) + data2 = data2 | 0x80; + SiS_SetRegANDOR (SiS_P3c4, 0x07, 0x7B, data2); + + data2 = 0x00; + if (VCLK >= 150) + data2 = data2 | 0x08; /* VCLK > 150 */ + SiS_SetRegANDOR (SiS_P3c4, 0x32, 0xF7, data2); + } else { /* 310 series */ + + data = SiS_GetReg1 (SiS_P3c4, 0x32); + data = data & 0xf3; + if (VCLK >= 200) + data = data | 0x0c; /* VCLK > 200 */ + SiS_SetReg1 (SiS_P3c4, 0x32, data); + data = SiS_GetReg1 (SiS_P3c4, 0x1F); + data &= 0xE7; + if (VCLK < 200) + data |= 0x10; + SiS_SetReg1 (SiS_P3c4, 0x1F, data); + } + + if ((VCLK >= 0) && (VCLK < 135)) + data2 = 0x03; + if ((VCLK >= 135) && (VCLK < 160)) + data2 = 0x02; + if ((VCLK >= 160) && (VCLK < 260)) + data2 = 0x01; + if (VCLK > 260) + data2 = 0x00; + /* disable 24bit palette RAM gamma correction */ + + if (HwDeviceExtension->jChipType == SIS_540) { + if ((VCLK == 203) || (VCLK < 234)) + data2 = 0x02; + } + SiS_SetRegANDOR (SiS_P3c4, 0x07, 0xFC, data2); +} + +void +SiS_LoadDAC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT data, data2; + USHORT time, i, j, k; + USHORT m, n, o; + USHORT si, di, bx, dl; + USHORT al, ah, dh; + USHORT *table = NULL; + + if (ModeNo <= 0x13) + data = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + else + data = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + + data = data & DACInfoFlag; + time = 64; + if (data == 0x00) + table = SiS_MDA_DAC; + if (data == 0x08) + table = SiS_CGA_DAC; + if (data == 0x10) + table = SiS_EGA_DAC; + if (data == 0x18) { + time = 256; + table = SiS_VGA_DAC; + } + if (time == 256) + j = 16; + else + j = time; + + SiS_SetReg3 (SiS_P3c6, 0xFF); + SiS_SetReg3 (SiS_P3c8, 0x00); + + for (i = 0; i < j; i++) { + data = table[i]; + for (k = 0; k < 3; k++) { + data2 = 0; + if (data & 0x01) + data2 = 0x2A; + if (data & 0x02) + data2 = data2 + 0x15; + SiS_SetReg3 (SiS_P3c9, data2); + data = data >> 2; + } + } + + if (time == 256) { + for (i = 16; i < 32; i++) { + data = table[i]; + for (k = 0; k < 3; k++) + SiS_SetReg3 (SiS_P3c9, data); + } + si = 32; + for (m = 0; m < 9; m++) { + di = si; + bx = si + 0x04; + dl = 0; + for (n = 0; n < 3; n++) { + for (o = 0; o < 5; o++) { + dh = table[si]; + ah = table[di]; + al = table[bx]; + si++; + SiS_WriteDAC (dl, ah, al, dh); + } /* for 5 */ + si = si - 2; + for (o = 0; o < 3; o++) { + dh = table[bx]; + ah = table[di]; + al = table[si]; + si--; + SiS_WriteDAC (dl, ah, al, dh); + } /* for 3 */ + dl++; + } /* for 3 */ + si = si + 5; + } /* for 9 */ + } +} + +void +SiS_WriteDAC (USHORT dl, USHORT ah, USHORT al, USHORT dh) +{ + USHORT temp; + USHORT bh, bl; + + bh = ah; + bl = al; + if (dl != 0) { + temp = bh; + bh = dh; + dh = temp; + if (dl == 1) { + temp = bl; + bl = dh; + dh = temp; + } else { + temp = bl; + bl = bh; + bh = temp; + } + } + SiS_SetReg3 (SiS_P3c9, (USHORT) dh); + SiS_SetReg3 (SiS_P3c9, (USHORT) bh); + SiS_SetReg3 (SiS_P3c9, (USHORT) bl); +} + +void +SiS_ClearBuffer (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo) +{ + PVOID VideoMemoryAddress = + (PVOID) HwDeviceExtension->pjVideoMemoryAddress; + ULONG AdapterMemorySize = (ULONG) HwDeviceExtension->ulVideoMemorySize; + PUSHORT pBuffer; + int i; + + if (SiS_ModeType >= ModeEGA) { + if (ModeNo > 0x13) { + SiS_SetMemory (VideoMemoryAddress, AdapterMemorySize, + 0); + } else { + pBuffer = VideoMemoryAddress; + for (i = 0; i < 0x4000; i++) + pBuffer[i] = 0x0000; + } + } else { + pBuffer = VideoMemoryAddress; + if (SiS_ModeType == ModeCGA) { + for (i = 0; i < 0x4000; i++) + pBuffer[i] = 0x0720; + } else { + for (i = 0; i < 0x4000; i++) + pBuffer[i] = 0x0000; + } + } +} + +void +SiS_DisplayOn (void) +{ + + SiS_SetRegANDOR (SiS_P3c4, 0x01, 0xDF, 0x00); +} + +void +SiS_DisplayOff (void) +{ + + SiS_SetRegANDOR (SiS_P3c4, 0x01, 0xDF, 0x20); +} + +/* ========================================== */ +/* SR CRTC GR */ +void +SiS_SetReg1 (USHORT port, USHORT index, USHORT data) +{ + OutPortByte (port, index); + OutPortByte (port + 1, data); + + /* + _asm + { + mov dx, port + mov ax, index + mov bx, data + out dx, al + mov ax, bx + inc dx + out dx, al + } + */ + +} + +/* ========================================== */ +/* AR(3C0) */ +void +SiS_SetReg2 (USHORT port, USHORT index, USHORT data) +{ + + InPortByte (port + 0x3da - 0x3c0); + OutPortByte (SiS_P3c0, index); + OutPortByte (SiS_P3c0, data); + OutPortByte (SiS_P3c0, 0x20); + + /* + _asm + { + mov dx, port + mov cx, index + mov bx, data + + add dx, 3dah-3c0h + in al, dx + + mov ax, cx + mov dx, 3c0h + out dx, al + mov ax, bx + out dx, al + + mov ax, 20h + out dx, al + } + */ + +} + +/* ========================================== */ +void +SiS_SetReg3 (USHORT port, USHORT data) +{ + + OutPortByte (port, data); + + /* + _asm + { + mov dx, port + mov ax, data + out dx, al + + } + */ + +} + +/* ========================================== */ +void +SiS_SetReg4 (USHORT port, ULONG data) +{ + + OutPortLong (port, data); + + /* + _asm + { + mov dx, port ;; port + mov eax, data ;; data + out dx, eax + + } + */ +} + +/* ========================================= */ +UCHAR SiS_GetReg1 (USHORT port, USHORT index) +{ + UCHAR data; + + OutPortByte (port, index); + data = InPortByte (port + 1); + + /* + _asm + { + mov dx, port ;; port + mov ax, index ;; index + + out dx, al + mov ax, bx + inc dx + xor eax, eax + in al, dx + mov data, al + } + */ + return (data); +} + +/* ========================================== */ +UCHAR SiS_GetReg2 (USHORT port) +{ + UCHAR data; + + data = InPortByte (port); + + /* + _asm + { + mov dx, port ;; port + xor eax, eax + in al, dx + mov data, al + } + */ + return (data); +} + +/* ========================================== */ +ULONG SiS_GetReg3 (USHORT port) +{ + ULONG data; + + data = InPortLong (port); + + /* + _asm + { + mov dx, port ;; port + xor eax, eax + in eax, dx + mov data, eax + } + */ + return (data); +} + +/* ========================================== */ +void +SiS_ClearDAC (ULONG port) +{ + int i; + + OutPortByte (port, 0); + port++; + for (i = 0; i < 256 * 3; i++) { + OutPortByte (port, 0); + } + +} + +/*========================================== */ + +void +SiS_SetInterlace (ULONG ROMAddr, USHORT ModeNo, USHORT RefreshRateTableIndex) +{ + ULONG Temp; + USHORT data, Temp2; + + Temp = (ULONG) SiS_GetReg1 (SiS_P3d4, 0x01); + Temp++; + Temp = Temp * 8; + + if (Temp == 1024) + data = 0x0035; + else if (Temp == 1280) + data = 0x0048; + else + data = 0x0000; + + Temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + Temp2 &= InterlaceMode; + if (Temp2 == 0) + data = 0x0000; + + SiS_SetReg1 (SiS_P3d4, 0x19, data); + + Temp = (ULONG) SiS_GetReg1 (SiS_P3d4, 0x1A); + Temp2 = (USHORT) (Temp & 0xFC); + SiS_SetReg1 (SiS_P3d4, 0x1A, (USHORT) Temp); + + Temp = (ULONG) SiS_GetReg1 (SiS_P3c4, 0x0f); + Temp2 = (USHORT) Temp & 0xBF; + if (ModeNo == 0x37) + Temp2 = Temp2 | 0x40; + SiS_SetReg1 (SiS_P3d4, 0x1A, (USHORT) Temp2); +} + +void +SiS_SetCRT1FIFO (ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + + USHORT data; + + data = SiS_GetReg1 (SiS_P3c4, 0x3D); + data &= 0xfe; + SiS_SetReg1 (SiS_P3c4, 0x3D, data); /* diable auto-threshold */ + if (ModeNo > 0x13) { + SiS_SetReg1 (SiS_P3c4, 0x08, 0x34); + data = SiS_GetReg1 (SiS_P3c4, 0x09); + data &= 0xF0; + SiS_SetReg1 (SiS_P3c4, 0x09, data); + + data = SiS_GetReg1 (SiS_P3c4, 0x3D); + data |= 0x01; + SiS_SetReg1 (SiS_P3c4, 0x3D, data); + } else { + SiS_SetReg1 (SiS_P3c4, 0x08, 0xAE); + data = SiS_GetReg1 (SiS_P3c4, 0x09); + data &= 0xF0; + SiS_SetReg1 (SiS_P3c4, 0x09, data); + } + +} + +USHORT +SiS_CalcDelay (ULONG ROMAddr, USHORT key) +{ + USHORT data, data2, temp0, temp1; + UCHAR ThLowA[] = { 61, 3, 52, 5, 68, 7, 100, 11, + 43, 3, 42, 5, 54, 7, 78, 11, + 34, 3, 37, 5, 47, 7, 67, 11 + }; + UCHAR ThLowB[] = { 81, 4, 72, 6, 88, 8, 120, 12, + 55, 4, 54, 6, 66, 8, 90, 12, + 42, 4, 45, 6, 55, 8, 75, 12 + }; + UCHAR ThTiming[] = { 1, 2, 2, 3, 0, 1, 1, 2 }; + + data = SiS_GetReg1 (SiS_P3c4, 0x16); + data = data >> 6; + data2 = SiS_GetReg1 (SiS_P3c4, 0x14); + data2 = (data2 >> 4) & 0x0C; + data = data | data2; + data = data < 1; + if (key == 0) { + temp0 = (USHORT) ThLowA[data]; + temp1 = (USHORT) ThLowA[data + 1]; + } else { + temp0 = (USHORT) ThLowB[data]; + temp1 = (USHORT) ThLowB[data + 1]; + } + + data2 = 0; + data = SiS_GetReg1 (SiS_P3c4, 0x18); + if (data & 0x02) + data2 = data2 | 0x01; + if (data & 0x20) + data2 = data2 | 0x02; + if (data & 0x40) + data2 = data2 | 0x04; + + data = temp1 * ThTiming[data2] + temp0; + return (data); +} + +void +SiS_SetCRT1FIFO2 (ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + USHORT i, index, data, VCLK, data2, MCLK, colorth = 0; + USHORT ah, bl, B; + ULONG eax; + USHORT ThresholdLow = 0; + UCHAR FQBQData[] = { 0x01, 0x21, 0x41, 0x61, 0x81, + 0x31, 0x51, 0x71, 0x91, 0xb1, + 0x00, 0x20, 0x40, 0x60, 0x80, + 0x30, 0x50, 0x70, 0x90, 0xb0, 0xFF + }; + + if (ModeNo >= 0x13) { + index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + if (HwDeviceExtension->jChipType < SIS_315H) { /* for300 serial */ + index = index & 0x3F; + } + VCLK = SiS_VCLKData[index].CLOCK; /* Get VCLK */ + index = SiS_GetReg1 (SiS_P3c4, 0x1A); + index = index & 07; + MCLK = SiS_MCLKData[index].CLOCK; /* Get MCLK */ + data2 = SiS_ModeType - 0x02; + switch (data2) { + case 0: + colorth = 1; + break; + case 1: + colorth = 2; + break; + case 2: + colorth = 4; + break; + case 3: + colorth = 4; + break; + case 4: + colorth = 6; + break; + case 5: + colorth = 8; + break; + } + + i = 0; + do { + B = + (SiS_CalcDelay2 (ROMAddr, FQBQData[i]) * VCLK * + colorth); + bl = B / (16 * MCLK); + if (B == bl * 16 * MCLK) { + bl = bl + 1; + } else { + bl = bl + 1; + } + + if (bl > 0x13) { + if (FQBQData[i + 1] == 0xFF) { + ThresholdLow = 0x13; + break; + } + i++; + } else { + ThresholdLow = bl; + break; + } + } while (FQBQData[i] != 0xFF); + } else { + ThresholdLow = 0x02; + } + + data2 = FQBQData[i]; + data2 = (data2 & 0xf0) >> 4; + data2 = data2 << 24; + + SiS_SetReg4 (0xcf8, 0x80000050); + eax = SiS_GetReg3 (0xcfc); + eax = eax & 0x0f0ffffff; + eax = eax | data2; + SiS_SetReg4 (0xcfc, eax); + + ah = ThresholdLow; + ah = ah << 4; + ah = ah | 0x0f; + SiS_SetReg1 (SiS_P3c4, 0x08, ah); + + data = ThresholdLow; + data = data & 0x10; + data = data << 1; + SiS_SetRegANDOR (SiS_P3c4, 0x0F, 0xDF, data); + SiS_SetReg1 (SiS_P3c4, 0x3B, 0x09); + + data = ThresholdLow + 3; + if (data > 0x0f) + data = 0x0f; + SiS_SetRegANDOR (SiS_P3c4, 0x09, 0x80, data); +} + +USHORT +SiS_CalcDelay2 (ULONG ROMAddr, UCHAR key) +{ + USHORT data, index; + UCHAR LatencyFactor[] = { 97, 88, 86, 79, 77, 00, /*; 64 bit BQ=2 */ + 00, 87, 85, 78, 76, 54, /*; 64 bit BQ=1 */ + 97, 88, 86, 79, 77, 00, /*; 128 bit BQ=2 */ + 00, 79, 77, 70, 68, 48, /*; 128 bit BQ=1 */ + 80, 72, 69, 63, 61, 00, /*; 64 bit BQ=2 */ + 00, 70, 68, 61, 59, 37, /*; 64 bit BQ=1 */ + 86, 77, 75, 68, 66, 00, /*; 128 bit BQ=2 */ + 00, 68, 66, 59, 57, 37 + }; /*; 128 bit BQ=1 */ + + index = (key & 0xE0) >> 5; + if (key & 0x10) + index = index + 6; + if (!(key & 0x01)) + index = index + 24; + data = SiS_GetReg1 (SiS_P3c4, 0x14); + if (data & 0x0080) + index = index + 12; + + data = LatencyFactor[index]; + return (data); +} + +void +SiS_CRT2AutoThreshold (USHORT BaseAddr) +{ + USHORT temp1; + USHORT Part1Port; + Part1Port = BaseAddr + SIS_CRT2_PORT_04; + temp1 = SiS_GetReg1 (SiS_Part1Port, 0x1); + temp1 |= 0x40; + SiS_SetReg1 (SiS_Part1Port, 0x1, temp1); +} + +/* ============= ynlai ============== */ +void +SiS_DetectMonitor (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr) +{ + UCHAR DAC_TEST_PARMS[] = { 0x0F, 0x0F, 0x0F }; + UCHAR DAC_CLR_PARMS[] = { 0x00, 0x00, 0x00 }; + USHORT SR1F; + + SR1F = SiS_GetReg1 (SiS_P3c4, 0x1F); + SiS_SetRegANDOR (SiS_P3c4, 0x1F, 0xFF, 0x04); + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_BridgeIsOn (BaseAddr)) { + SiS_SetReg1 (SiS_P3d4, 0x30, 0x41); + } + } + SiSSetMode (HwDeviceExtension, 0x03); /* InitMode */ + SiS_SetReg3 (SiS_P3c6, 0xff); + SiS_ClearDAC (SiS_P3c8); + SiS_LongWait (); + SiS_LongWait (); + SiS_SetRegANDOR (SiS_P3d4, 0x32, 0xDF, 0x00); + if (SiS_TestMonitorType + (DAC_TEST_PARMS[0], DAC_TEST_PARMS[1], DAC_TEST_PARMS[2])) { + SiS_SetRegANDOR (SiS_P3d4, 0x32, 0xDF, 0x20); + } + if (SiS_TestMonitorType + (DAC_TEST_PARMS[0], DAC_TEST_PARMS[1], DAC_TEST_PARMS[2])) { + SiS_SetRegANDOR (SiS_P3d4, 0x32, 0xDF, 0x20); + } + SiS_TestMonitorType (DAC_CLR_PARMS[0], DAC_CLR_PARMS[1], + DAC_CLR_PARMS[2]); + SiS_SetReg1 (SiS_P3c4, 0x1F, SR1F); +} + +USHORT +SiS_TestMonitorType (UCHAR R_DAC, UCHAR G_DAC, UCHAR B_DAC) +{ + USHORT temp, tempbx; + + tempbx = R_DAC * 0x4d + G_DAC * 0x97 + B_DAC * 0x1c; + if (tempbx > 0x80) + tempbx = tempbx + 0x100; + tempbx = (tempbx & 0xFF00) >> 8; + R_DAC = (UCHAR) tempbx; + G_DAC = (UCHAR) tempbx; + B_DAC = (UCHAR) tempbx; + + SiS_SetReg3 (SiS_P3c8, 0x00); + SiS_SetReg3 (SiS_P3c9, R_DAC); + SiS_SetReg3 (SiS_P3c9, G_DAC); + SiS_SetReg3 (SiS_P3c9, B_DAC); + SiS_LongWait (); + temp = SiS_GetReg2 (SiS_P3c2); + if (temp & 0x10) + return (1); + else + return (0); +} + +/* ---- test ----- */ +void +SiS_GetSenseStatus (PSIS_HW_DEVICE_INFO HwDeviceExtension, ULONG ROMAddr) +{ + USHORT tempax = 0, tempbx, tempcx, temp; + USHORT P2reg0 = 0, SenseModeNo = 0, OutputSelect = *pSiS_OutputSelect; + USHORT ModeIdIndex, i; + USHORT BaseAddr = (USHORT) HwDeviceExtension->ulIOAddress; + + if (SiS_IF_DEF_LVDS == 1) { + SiS_GetPanelID (); + temp = LCDSense; + temp = temp | SiS_SenseCHTV (); + tempbx = ~(LCDSense | AVIDEOSense | SVIDEOSense); + SiS_SetRegANDOR (SiS_P3d4, 0x32, tempbx, temp); + } else { /* for 301 */ + if (SiS_IF_DEF_HiVision == 1) { /* for HiVision */ + tempax = SiS_GetReg1 (SiS_P3c4, 0x38); + temp = tempax & 0x01; + tempax = SiS_GetReg1 (SiS_P3c4, 0x3A); + temp = temp | (tempax & 0x02); + SiS_SetRegANDOR (SiS_P3d4, 0x32, 0xA0, temp); + } else { + if (SiS_BridgeIsOn (BaseAddr)) { + P2reg0 = SiS_GetReg1 (SiS_Part2Port, 0x00); + if (!SiS_BridgeIsEnable + (BaseAddr, HwDeviceExtension)) { + SenseModeNo = 0x2e; + temp = + SiS_SearchModeID (ROMAddr, + SenseModeNo, + &ModeIdIndex); + SiS_SetFlag = 0x00; + SiS_ModeType = ModeVGA; + SiS_VBInfo = + SetCRT2ToRAMDAC | LoadDACFlag | + SetInSlaveMode; + SiS_SetCRT2Group301 (BaseAddr, ROMAddr, + SenseModeNo, + HwDeviceExtension); + for (i = 0; i < 20; i++) { + SiS_LongWait (); + } + } + SiS_SetReg1 (SiS_Part2Port, 0x00, 0x1c); + tempax = 0; + tempbx = *pSiS_RGBSenseData; + /*301b */ + if (!(SiS_Is301B (BaseAddr))) { + tempbx = *pSiS_RGBSenseData2; + } + /*end 301b */ + tempcx = 0x0E08; + if (SiS_Sense (SiS_Part4Port, tempbx, tempcx)) { + if (SiS_Sense + (SiS_Part4Port, tempbx, tempcx)) { + tempax = tempax | Monitor2Sense; + } + } + + tempbx = *pSiS_YCSenseData; + /*301b */ + if (!(SiS_Is301B (BaseAddr))) { + tempbx = *pSiS_YCSenseData2; + } + /*301b */ + tempcx = 0x0604; + if (SiS_Sense (SiS_Part4Port, tempbx, tempcx)) { + if (SiS_Sense + (SiS_Part4Port, tempbx, tempcx)) { + tempax = tempax | SVIDEOSense; + } + } + + if (OutputSelect & BoardTVType) { + tempbx = *pSiS_VideoSenseData; + /*301b */ + if (!(SiS_Is301B (BaseAddr))) { + tempbx = *pSiS_VideoSenseData2; + } + /*end 301b */ + tempcx = 0x0804; + if (SiS_Sense + (SiS_Part4Port, tempbx, tempcx)) { + if (SiS_Sense + (SiS_Part4Port, tempbx, + tempcx)) { + tempax = + tempax | + AVIDEOSense; + } + } + } else { + if (!(tempax & SVIDEOSense)) { + tempbx = *pSiS_VideoSenseData; + /*301b */ + if (!(SiS_Is301B (BaseAddr))) { + tempbx = + *pSiS_VideoSenseData2; + } + /*end 301b */ + tempcx = 0x0804; + if (SiS_Sense + (SiS_Part4Port, tempbx, + tempcx)) { + if (SiS_Sense + (SiS_Part4Port, + tempbx, tempcx)) { + tempax = + tempax | + AVIDEOSense; + } + } + } + } + } + + if (SiS_SenseLCD (HwDeviceExtension)) { + tempax = tempax | LCDSense; + } + + tempbx = 0; + tempcx = 0; + SiS_Sense (SiS_Part4Port, tempbx, tempcx); + + SiS_SetRegANDOR (SiS_P3d4, 0x32, ~0xDF, tempax); + SiS_SetReg1 (SiS_Part2Port, 0x00, P2reg0); + if (!(P2reg0 & 0x20)) { + SiS_VBInfo = DisableCRT2Display; + SiS_SetCRT2Group301 (BaseAddr, ROMAddr, + SenseModeNo, + HwDeviceExtension); + } + } + } +} + +BOOLEAN +SiS_Sense (USHORT Part4Port, USHORT tempbx, USHORT tempcx) +{ + USHORT temp, i, tempch; + + temp = tempbx & 0xFF; + SiS_SetReg1 (SiS_Part4Port, 0x11, temp); + temp = (tempbx & 0xFF00) >> 8; + temp = temp | (tempcx & 0x00FF); + SiS_SetRegANDOR (SiS_Part4Port, 0x10, ~0x1F, temp); + + for (i = 0; i < 10; i++) + SiS_LongWait (); + + tempch = (tempcx & 0x7F00) >> 8; /* ynlai [05/22/2001] */ + temp = SiS_GetReg1 (SiS_Part4Port, 0x03); + temp = temp ^ (0x0E); + temp = temp & tempch; /* ynlai [05/22/2001] */ + if (temp > 0) + return 1; + else + return 0; +} + +USHORT +SiS_SenseLCD (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ +/* USHORT SoftSetting; */ + USHORT temp; + + temp = SiS_GetPanelID (); + if (!temp) + temp = SiS_GetLCDDDCInfo (HwDeviceExtension); + return (temp); +} + +BOOLEAN +SiS_GetLCDDDCInfo (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp; + //add lcd sense + if (HwDeviceExtension->ulCRT2LCDType == LCD_UNKNOWN) + return 0; + else { + temp = (USHORT) HwDeviceExtension->ulCRT2LCDType; + SiS_SetReg1 (SiS_P3d4, 0x36, temp); + return 1; + } +} + +BOOLEAN +SiS_GetPanelID (void) +{ + USHORT PanelTypeTable[16] = + { SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType00, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType01, + SyncPP | PanelRGB18Bit | Panel800x600 | _PanelType02, + SyncNN | PanelRGB18Bit | Panel640x480 | _PanelType03, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType04, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType05, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType06, + SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType07, + SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType08, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType09, + SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType0A, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0B, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0C, + SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType0D, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0E, + SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0F + }; + USHORT tempax, tempbx, temp; +/* USHORT return_flag; */ + + tempax = SiS_GetReg1 (SiS_P3c4, 0x18); + tempbx = tempax & 0x0F; + if (!(tempax & 0x10)) { + if (SiS_IF_DEF_LVDS == 1) { + tempbx = 0; + temp = SiS_GetReg1 (SiS_P3c4, 0x38); + if (temp & 0x40) + tempbx = tempbx | 0x08; + if (temp & 0x20) + tempbx = tempbx | 0x02; + if (temp & 0x01) + tempbx = tempbx | 0x01; + temp = SiS_GetReg1 (SiS_P3c4, 0x39); + if (temp & 0x80) + tempbx = tempbx | 0x04; + } else { + return 0; + } + } + + tempbx = tempbx << 1; + tempbx = PanelTypeTable[tempbx]; + tempbx = tempbx | LCDSync; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_P3d4, 0x36, temp); + temp = (tempbx & 0xFF00) >> 8; + SiS_SetRegANDOR (SiS_P3d4, 0x37, ~(LCDSyncBit | LCDRGB18Bit), temp); + return 1; +} + +USHORT +SiS_SenseCHTV (void) +{ + USHORT temp, push0e, status; + + status = 0; + push0e = SiS_GetCH7005 (0x0e); + push0e = (push0e << 8) | 0x0e; + SiS_SetCH7005 (0x0b0e); + SiS_SetCH7005 (0x0110); + SiS_SetCH7005 (0x0010); + temp = SiS_GetCH7005 (0x10); + if (temp & 0x08) + status = status | SVIDEOSense; + if (temp & 0x02) + status = status | AVIDEOSense; + SiS_SetCH7005 (push0e); + return (status); +} + +/* ========================================== */ +#ifdef TC + +int +INT1AReturnCode (union REGS regs) +{ + if (regs.x.cflag) { + /*printf("Error to find pci device!\n"); */ + return 1; + } + + switch (regs.h.ah) { + case 0: + return 0; + break; + case 0x81: + printf ("Function not support\n"); + break; + case 0x83: + printf ("bad vendor id\n"); + break; + case 0x86: + printf ("device not found\n"); + break; + case 0x87: + printf ("bad register number\n"); + break; + case 0x88: + printf ("set failed\n"); + break; + case 0x89: + printf ("buffer too small"); + break; + } + return 1; +} + +unsigned +FindPCIIOBase (unsigned index, unsigned deviceid) +{ + union REGS regs; + + regs.h.ah = 0xb1; /*PCI_FUNCTION_ID */ + regs.h.al = 0x02; /*FIND_PCI_DEVICE */ + regs.x.cx = deviceid; + regs.x.dx = 0x1039; + regs.x.si = index; /* find n-th device */ + + int86 (0x1A, ®s, ®s); + + if (INT1AReturnCode (regs) != 0) + return 0; + +/* regs.h.bh *//* bus number */ +/* regs.h.bl *//* device number */ + regs.h.ah = 0xb1; /*PCI_FUNCTION_ID */ + regs.h.al = 0x09; /*READ_CONFIG_WORD */ + regs.x.cx = deviceid; + regs.x.dx = 0x1039; + regs.x.di = 0x18; /* register number */ + int86 (0x1A, ®s, ®s); + + if (INT1AReturnCode (regs) != 0) + return 0; + return regs.x.cx; +} + +void +main (int argc, char *argv[]) +/* void main() */ +{ + SIS_HW_DEVICE_INFO HwDeviceExtension; + USHORT temp; + USHORT ModeNo; + + /*HwDeviceExtension.pjVirtualRomBase =(PUCHAR) MK_FP(0xC000,0); */ + /*HwDeviceExtension.pjVideoMemoryAddress = (PUCHAR)MK_FP(0xA000,0); */ +#ifdef CONFIG_FB_SIS_300 + HwDeviceExtension.ulIOAddress = + (FindPCIIOBase (0, 0x6300) & 0xFF80) + 0x30; + HwDeviceExtension.jChipType = SIS_630; +#endif + +#ifdef CONFIG_FB_SIS_315 +// HwDeviceExtension.ulIOAddress = (FindPCIIOBase(0,0x5315)&0xFF80) + 0x30; +// HwDeviceExtension.jChipType = SIS_550; + HwDeviceExtension.ulIOAddress = + (FindPCIIOBase (0, 0x325) & 0xFF80) + 0x30; + HwDeviceExtension.jChipType = SIS_315H; +#endif + HwDeviceExtension.ujVBChipID = VB_CHIP_301; + strcpy (HwDeviceExtension.szVBIOSVer, "0.84"); + HwDeviceExtension.bSkipDramSizing = FALSE; + HwDeviceExtension.ulVideoMemorySize = 0; + if (argc == 2) { + ModeNo = atoi (argv[1]); + } else { + ModeNo = 0x2e; + /*ModeNo=0x37; 1024x768x 4bpp */ + /*ModeNo=0x38; 1024x768x 8bpp */ + /*ModeNo=0x4A; 1024x768x 16bpp */ + /*ModeNo=0x47; 800x600x 16bpp */ + } + // SiSInit(&HwDeviceExtension); + SiSSetMode (&HwDeviceExtension, ModeNo); + +} +#endif diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/init.h linux/drivers/video/sis/init.h --- v2.4.14/linux/drivers/video/sis/init.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/init.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,227 @@ +#ifndef _INIT_ +#define _INIT_ + +#include "osdef.h" +#include "initdef.h" +#include "vgatypes.h" +#include "vstruct.h" + +#include <linux/types.h> +#include <asm/io.h> +#include <linux/sisfb.h> + + +USHORT SiS_DRAMType[17][5] = { + {0x0C, 0x0A, 0x02, 0x40, 0x39}, + {0x0D, 0x0A, 0x01, 0x40, 0x48}, + {0x0C, 0x09, 0x02, 0x20, 0x35}, + {0x0D, 0x09, 0x01, 0x20, 0x44}, + {0x0C, 0x08, 0x02, 0x10, 0x31}, + {0x0D, 0x08, 0x01, 0x10, 0x40}, + {0x0C, 0x0A, 0x01, 0x20, 0x34}, + {0x0C, 0x09, 0x01, 0x08, 0x32}, + {0x0B, 0x08, 0x02, 0x08, 0x21}, + {0x0C, 0x08, 0x01, 0x08, 0x30}, + {0x0A, 0x08, 0x02, 0x04, 0x11}, + {0x0B, 0x0A, 0x01, 0x10, 0x28}, + {0x09, 0x08, 0x02, 0x02, 0x01}, + {0x0B, 0x09, 0x01, 0x08, 0x24}, + {0x0B, 0x08, 0x01, 0x04, 0x20}, + {0x0A, 0x08, 0x01, 0x02, 0x10}, + {0x09, 0x08, 0x01, 0x01, 0x00} +}; + +USHORT SiS_SDRDRAM_TYPE[13][5] = { + {2, 12, 9, 64, 0x35}, + {1, 13, 9, 64, 0x44}, + {2, 12, 8, 32, 0x31}, + {2, 11, 9, 32, 0x25}, + {1, 12, 9, 32, 0x34}, + {1, 13, 8, 32, 0x40}, + {2, 11, 8, 16, 0x21}, + {1, 12, 8, 16, 0x30}, + {1, 11, 9, 16, 0x24}, + {1, 11, 8, 8, 0x20}, + {2, 9, 8, 4, 0x01}, + {1, 10, 8, 4, 0x10}, + {1, 9, 8, 2, 0x00} +}; + +USHORT SiS_DDRDRAM_TYPE[4][5] = { + {2, 12, 9, 64, 0x35}, + {2, 12, 8, 32, 0x31}, + {2, 11, 8, 16, 0x21}, + {2, 9, 8, 4, 0x01} +}; + +UCHAR SiS_ChannelAB, SiS_DataBusWidth; + +USHORT SiS_MDA_DAC[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F +}; + +USHORT SiS_CGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F +}; + +USHORT SiS_EGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, + 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, + 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, + 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, + 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, + 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, + 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F +}; + +USHORT SiS_VGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, + 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, + + 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F, + 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00, + 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18, + 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04, + 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10, + 0x0B, 0x0C, 0x0D, 0x0F, 0x10 +}; + +USHORT SiS_P3c4, SiS_P3d4, SiS_P3c0, SiS_P3ce, SiS_P3c2; +USHORT SiS_P3ca, SiS_P3c6, SiS_P3c7, SiS_P3c8, SiS_P3c9, SiS_P3da; +USHORT SiS_Part1Port, SiS_Part2Port; +USHORT SiS_Part3Port, SiS_Part4Port, SiS_Part5Port; +USHORT SiS_CRT1Mode; + +USHORT flag_clearbuffer; /*0: no clear frame buffer 1:clear frame buffer */ +int SiS_RAMType; /*int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,REFIndex; */ +USHORT SiS_ModeType; +USHORT SiS_IF_DEF_LVDS, SiS_IF_DEF_TRUMPION, SiS_IF_DEF_DSTN; /*add for dstn */ +USHORT SiS_IF_DEF_CH7005, SiS_IF_DEF_HiVision; +USHORT SiS_VBInfo, SiS_LCDResInfo, SiS_LCDTypeInfo, SiS_LCDInfo, SiS_VBType; /*301b */ +USHORT SiS_SelectCRT2Rate; + +extern USHORT SiS_SetFlag; + +void SiS_SetMemoryClock (ULONG ROMAddr); +void SiS_SetDRAMModeRegister (ULONG ROMAddr); +void SiS_SetDRAMSize_310 (PSIS_HW_DEVICE_INFO); +void SiS_SetDRAMSize_300 (PSIS_HW_DEVICE_INFO HwDeviceExtension); +USHORT SiS_ChkBUSWidth_300 (ULONG FBAddress); +UCHAR SiS_Get310DRAMType (ULONG ROMAddr); + +void SiS_Delay15us (ULONG); +BOOLEAN SiS_SearchModeID (ULONG ROMAddr, USHORT ModeNo, USHORT * ModeIdIndex); +BOOLEAN SiS_CheckMemorySize (ULONG ROMAddr, + PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT ModeIdIndex); +UCHAR SiS_GetModePtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_SetSeqRegs (ULONG, USHORT StandTableIndex); +void SiS_SetMiscRegs (ULONG, USHORT StandTableIndex); +void SiS_SetCRTCRegs (ULONG, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT StandTableIndex); +void SiS_SetATTRegs (ULONG, USHORT StandTableIndex); +void SiS_SetGRCRegs (ULONG, USHORT StandTableIndex); +void SiS_ClearExt1Regs (void); +void SiS_SetSync (ULONG ROMAddr, USHORT RefreshRateTableIndex); +void SiS_SetCRT1CRTC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_SetCRT1VCLK (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO, USHORT RefreshRateTableIndex); +void SiS_SetVCLKState (ULONG ROMAddr, PSIS_HW_DEVICE_INFO, USHORT ModeNo, + USHORT RefreshRateTableIndex); +void SiS_LoadDAC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_DisplayOn (void); +void SiS_SetCRT1ModeRegs (ULONG ROMAddr, PSIS_HW_DEVICE_INFO, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex); +void SiS_WriteDAC (USHORT, USHORT, USHORT, USHORT); +void SiS_GetVBType (USHORT BaseAddr); /*301b */ +USHORT SiS_ChkBUSWidth (ULONG); +USHORT SiS_GetModeIDLength (ULONG, USHORT); +USHORT SiS_GetRefindexLength (ULONG, USHORT); +void SiS_SetInterlace (ULONG ROMAddr, USHORT ModeNo, + USHORT RefreshRateTableIndex); +USHORT SiS_CalcDelay2 (ULONG, UCHAR); +USHORT SiS_CalcDelay (ULONG, USHORT); +void SiS_Set_LVDS_TRUMPION (PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetCRT1Offset (ULONG, USHORT, USHORT, USHORT, PSIS_HW_DEVICE_INFO); +void SiS_SetCRT1FIFO (ULONG, USHORT, PSIS_HW_DEVICE_INFO); +void SiS_SetCRT1FIFO2 (ULONG, USHORT ModeNo, PSIS_HW_DEVICE_INFO, + USHORT RefreshRateTableIndex); +void SiS_CRT2AutoThreshold (USHORT BaseAddr); +void SiS_ClearBuffer (PSIS_HW_DEVICE_INFO, USHORT ModeNo); +void SiS_SetCRT1Group (ULONG ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo, USHORT ModeIdIndex); +void SiS_DetectMonitor (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr); +void SiS_GetSenseStatus (PSIS_HW_DEVICE_INFO HwDeviceExtension, ULONG ROMAddr); +USHORT SiS_TestMonitorType (UCHAR R_DAC, UCHAR G_DAC, UCHAR B_DAC); +USHORT SiS_SenseCHTV (VOID); +BOOLEAN SiS_Sense (USHORT Part4Port, USHORT tempbx, USHORT tempcx); +BOOLEAN SiS_GetPanelID (VOID); +BOOLEAN SiS_GetLCDDDCInfo (PSIS_HW_DEVICE_INFO); +USHORT SiS_SenseLCD (PSIS_HW_DEVICE_INFO); + +extern BOOLEAN SiS_SetCRT2Group301 (USHORT BaseAddr, ULONG ROMAddr, + USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern void SiS_PresetScratchregister (USHORT SiS_P3d4, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern void SiS_UnLockCRT2 (PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT BaseAddr); +extern void SiS_LockCRT2 (PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT BaseAddr); +extern BOOLEAN SiS_BridgeIsOn (USHORT BaseAddr); +extern BOOLEAN SiS_BridgeIsEnable (USHORT BaseAddr, PSIS_HW_DEVICE_INFO); +extern void SiS_SetTVSystem301 (VOID); +extern BOOLEAN SiS_GetLCDDDCInfo301 (PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern BOOLEAN SiS_GetSenseStatus301 (PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT BaseAddr, ULONG ROMAddr); +extern USHORT SiS_GetVCLKLen (ULONG ROMAddr, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern BOOLEAN SiS_SetCRT2Group302 (USHORT BaseAddr, ULONG ROMAddr, + USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern void SiS_GetVBInfo301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern BOOLEAN SiS_GetLCDResInfo301 (ULONG ROMAddr, USHORT P3d4, USHORT ModeNo, + USHORT ModeIdIndex); +extern USHORT SiS_VBInfo, LCDResInfo, LCDTypeInfo, LCDInfo; +extern USHORT SiS_GetRatePtrCRT2 (ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex); +extern void SiS_LongWait (VOID); +extern void SiS_SetRegANDOR (USHORT Port, USHORT Index, USHORT DataAND, + USHORT DataOR); +extern USHORT SiS_GetResInfo (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +extern void SiS_SetCH7005 (USHORT tempax); +extern USHORT SiS_GetCH7005 (USHORT tempax); +extern BOOLEAN SiS_GetLVDSCRT1Ptr (ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + USHORT * ResInfo, USHORT * DisplayType); +extern BOOLEAN SiS_GetLCDACRT1Ptr (ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + USHORT * ResInfo, USHORT * DisplayType); +extern USHORT SiS_GetVCLK2Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern BOOLEAN SiS_Is301B (USHORT BaseAddr); /*301b */ + +#endif diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/init301.c linux/drivers/video/sis/init301.c --- v2.4.14/linux/drivers/video/sis/init301.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/init301.c Fri Nov 9 14:11:14 2001 @@ -0,0 +1,6001 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.c,v 1.3 2000/12/02 01:16:16 dawes Exp $ */ + +#include "init301.h" +#ifdef CONFIG_FB_SIS_300 +#include "oem300.h" +#endif +#ifdef CONFIG_FB_SIS_315 +#include "oem310.h" +#endif + +BOOLEAN +SiS_SetCRT2Group301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT ModeIdIndex; + USHORT RefreshRateTableIndex; + + SiS_SetFlag = SiS_SetFlag | ProgrammingCRT2; + SiS_SearchModeID (ROMAddr, ModeNo, &ModeIdIndex); + SiS_SelectCRT2Rate = 4; + RefreshRateTableIndex = + SiS_GetRatePtrCRT2 (ROMAddr, ModeNo, ModeIdIndex); + SiS_SaveCRT2Info (ModeNo); + SiS_DisableBridge (HwDeviceExtension, BaseAddr); + SiS_UnLockCRT2 (HwDeviceExtension, BaseAddr); + SiS_SetCRT2ModeRegs (BaseAddr, ModeNo, HwDeviceExtension); + if (SiS_VBInfo & DisableCRT2Display) { + SiS_LockCRT2 (HwDeviceExtension, BaseAddr); + SiS_DisplayOn (); + return (FALSE); + } +/* SetDefCRT2ExtRegs(BaseAddr); */ + SiS_GetCRT2Data (ROMAddr, ModeNo, ModeIdIndex, RefreshRateTableIndex); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_GetLVDSDesData (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + } + /*end 301b */ + if (SiS_IF_DEF_LVDS == 1) { + SiS_GetLVDSDesData (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + } + + SiS_SetGroup1 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension, RefreshRateTableIndex); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA) && (SiS_IF_DEF_LVDS == 0)) { + } else if (SiS_IF_DEF_LVDS == 0 && (!(SiS_VBInfo & SetCRT2ToLCDA))) { + SiS_SetGroup2 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + SiS_SetGroup3 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension); + SiS_SetGroup4 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + SiS_SetGroup5 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex); + } else { + if (SiS_IF_DEF_CH7005 == 1) { + SiS_SetCHTVReg (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + } + SiS_ModCRT1CRTC (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + SiS_SetCRT2ECLK (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + } + +#ifdef CONFIG_FB_SIS_300 + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730) || + (HwDeviceExtension->jChipType == SIS_300)) + SiS_OEM300Setting (HwDeviceExtension, BaseAddr, ROMAddr, + ModeNo); + +#endif + +#ifdef CONFIG_FB_SIS_315 + if ((HwDeviceExtension->jChipType == SIS_315H) || /* 05/02/01 ynlai for sis550 */ + (HwDeviceExtension->jChipType == SIS_315PRO) || + (HwDeviceExtension->jChipType == SIS_550) || /* 05/02/01 ynlai for 550 */ + (HwDeviceExtension->jChipType == SIS_640) || /* 08/20/01 chiawen for 640/740 */ + (HwDeviceExtension->jChipType == SIS_740)) { /* 09/03/01 chiawen for 640/740 */ + SiS_OEM310Setting (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo, + ModeIdIndex); + SiS_CRT2AutoThreshold (BaseAddr); + } +#endif + + SiS_EnableBridge (HwDeviceExtension, BaseAddr); + SiS_DisplayOn (); + SiS_LockCRT2 (HwDeviceExtension, BaseAddr); + return 1; +} + +void +SiS_SetGroup1 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + USHORT temp = 0, tempax = 0, tempbx = 0, tempcx = 0; + USHORT pushbx = 0, CRT1Index = 0; + USHORT modeflag, resinfo = 0; + + if (ModeNo <= 0x13) { + } else { + CRT1Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index = CRT1Index & 0x3F; + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + } else { + SiS_SetCRT2Offset (SiS_Part1Port, ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + if (HwDeviceExtension->jChipType < SIS_315H) /* 300 series */ + SiS_SetCRT2FIFO (SiS_Part1Port, ROMAddr, ModeNo, + HwDeviceExtension); + else /* 310 series */ + SiS_SetCRT2FIFO2 (SiS_Part1Port, ROMAddr, ModeNo, + HwDeviceExtension); + + SiS_SetCRT2Sync (BaseAddr, ROMAddr, ModeNo, + RefreshRateTableIndex); + } + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_SetGroup1_LCDA (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension, RefreshRateTableIndex); + } + /*end 301b */ + else if (HwDeviceExtension->jChipType < SIS_315H) { /* 300 series */ + temp = (SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiS_SetReg1 (SiS_Part1Port, 0x08, temp); + temp = (((SiS_VGAHT - 1) & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR (SiS_Part1Port, 0x09, ~0x0F0, temp); + + temp = (SiS_VGAHDE + 12) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiS_SetReg1 (SiS_Part1Port, 0x0A, temp); + + pushbx = SiS_VGAHDE + 12; /* bx BTVGA@HRS 0x0B,0x0C */ + tempcx = (SiS_VGAHT - SiS_VGAHDE) >> 2; /* cx */ + tempbx = pushbx + tempcx; + tempcx = tempcx << 1; + tempcx = tempcx + tempbx; + + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempbx = SiS_CRT1Table[CRT1Index].CR[4]; + tempbx = + tempbx | + ((SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << + 2); + tempbx = (tempbx - 1) << 3; + tempcx = SiS_CRT1Table[CRT1Index].CR[5]; + tempcx = tempcx & 0x1F; + temp = SiS_CRT1Table[CRT1Index].CR[15]; + temp = (temp & 0x04) << (6 - 2); + tempcx = ((tempcx | temp) - 1) << 3; + } + } + /*add for hardware request */ + if ((SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)) { + if (SiS_VBInfo & SetPALTV) { + tempbx = 1040; + tempcx = 1042; + } else { + tempbx = 1040; + tempcx = 1042; + } + } + + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0B, temp); + + } else { /* 310 series */ + + if (modeflag & HalfDCLK) { /* for low resolution mode */ + temp = (SiS_VGAHT / 2 - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiS_SetReg1 (SiS_Part1Port, 0x08, temp); + temp = (((SiS_VGAHT / 2 - 1) & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR (SiS_Part1Port, 0x09, ~0x0F0, temp); + temp = (SiS_VGAHDE / 2 + 16) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiS_SetReg1 (SiS_Part1Port, 0x0A, temp); + + pushbx = SiS_VGAHDE / 2 + 16; + tempcx = ((SiS_VGAHT - SiS_VGAHDE) / 2) >> 2; /* cx */ + tempbx = pushbx + tempcx; /* bx BTVGA@HRS 0x0B,0x0C */ + tempcx = tempcx + tempbx; + + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempbx = SiS_CRT1Table[CRT1Index].CR[4]; + tempbx = + tempbx | + ((SiS_CRT1Table + [CRT1Index].CR[14] & 0xC0) << 2); + tempbx = (tempbx - 3) << 3; /*(VGAHRS-3)*8 */ + tempcx = SiS_CRT1Table[CRT1Index].CR[5]; + tempcx = tempcx & 0x1F; + temp = SiS_CRT1Table[CRT1Index].CR[15]; + temp = (temp & 0x04) << (5 - 2); /*VGAHRE D[5] */ + tempcx = ((tempcx | temp) - 3) << 3; /* (VGAHRE-3)*8 */ + } + } + tempbx += 4; + tempcx += 4; + if (tempcx > (SiS_VGAHT / 2)) + tempcx = SiS_VGAHT / 2; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0B, temp); + + } else { + temp = (SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiS_SetReg1 (SiS_Part1Port, 0x08, temp); + temp = (((SiS_VGAHT - 1) & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR (SiS_Part1Port, 0x09, ~0x0F0, temp); + temp = (SiS_VGAHDE + 16) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiS_SetReg1 (SiS_Part1Port, 0x0A, temp); + + pushbx = SiS_VGAHDE + 16; + tempcx = (SiS_VGAHT - SiS_VGAHDE) >> 2; /* cx */ + tempbx = pushbx + tempcx; /* bx BTVGA@HRS 0x0B,0x0C */ + tempcx = tempcx + tempbx; + + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempbx = SiS_CRT1Table[CRT1Index].CR[4]; + tempbx = + tempbx | + ((SiS_CRT1Table + [CRT1Index].CR[14] & 0xC0) << 2); + tempbx = (tempbx - 3) << 3; /*(VGAHRS-3)*8 */ + tempcx = SiS_CRT1Table[CRT1Index].CR[5]; + tempcx = tempcx & 0x1F; + temp = SiS_CRT1Table[CRT1Index].CR[15]; + temp = (temp & 0x04) << (5 - 2); /*VGAHRE D[5] */ + tempcx = ((tempcx | temp) - 3) << 3; /* (VGAHRE-3)*8 */ + tempbx += 16; + tempcx += 16; + + } + } + if (tempcx > SiS_VGAHT) + tempcx = SiS_VGAHT; + /*add for hardware request */ + if ((SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)) { + if (SiS_VBInfo & SetPALTV) { + tempbx = 1040; + tempcx = 1042; + } else { + tempbx = 1040; + tempcx = 1042; + } + } + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0B, temp); + } + + } + + tempax = (tempax & 0x00FF) | (tempbx & 0xFF00); + tempbx = pushbx; + tempbx = (tempbx & 0x00FF) | ((tempbx & 0xFF00) << 4); + tempax = tempax | (tempbx & 0xFF00); + temp = (tempax & 0xFF00) >> 8; + SiS_SetReg1 (SiS_Part1Port, 0x0C, temp); + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0D, temp); + tempcx = (SiS_VGAVT - 1); + temp = tempcx & 0x00FF; + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & 0x0C) { + temp--; + } + } + SiS_SetReg1 (SiS_Part1Port, 0x0E, temp); + tempbx = SiS_VGAVDE - 1; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0F, temp); + temp = ((tempbx & 0xFF00) << 3) >> 8; + temp = temp | ((tempcx & 0xFF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x12, temp); + + tempax = SiS_VGAVDE; + tempbx = SiS_VGAVDE; + tempcx = SiS_VGAVT; + tempbx = (SiS_VGAVT + SiS_VGAVDE) >> 1; /* BTVGA2VRS 0x10,0x11 */ + tempcx = ((SiS_VGAVT - SiS_VGAVDE) >> 4) + tempbx + 1; /* BTVGA2VRE 0x11 */ + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempbx = SiS_CRT1Table[CRT1Index].CR[8]; + temp = SiS_CRT1Table[CRT1Index].CR[7]; + if (temp & 0x04) + tempbx = tempbx | 0x0100; + if (temp & 0x080) + tempbx = tempbx | 0x0200; + temp = SiS_CRT1Table[CRT1Index].CR[13]; + if (temp & 0x08) + tempbx = tempbx | 0x0400; + temp = SiS_CRT1Table[CRT1Index].CR[9]; + tempcx = (tempcx & 0xFF00) | (temp & 0x00FF); + } + } + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x10, temp); + temp = ((tempbx & 0xFF00) >> 8) << 4; + temp = ((tempcx & 0x000F) | (temp)); + SiS_SetReg1 (SiS_Part1Port, 0x11, temp); + if (SiS_IF_DEF_LVDS == 0) { + temp = 0x20; + if (SiS_LCDResInfo == Panel1280x1024) + temp = 0x20; + if (SiS_LCDResInfo == Panel1280x960) + temp = 0x24; + if (SiS_VBInfo & SetCRT2ToTV) + temp = 0x08; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (SiS_VBInfo & SetInSlaveMode) + temp = 0x2c; + else + temp = 0x20; + } + } else { + temp = 0x20; + } + if (HwDeviceExtension->jChipType < SIS_315H) /* 300 series */ + SiS_SetRegANDOR (SiS_Part1Port, 0x13, ~0x03C, temp); + else { /* 310 series */ + + temp >>= 2; + temp = 0x11; /* ynlai 05/30/2001 for delay compenation */ + SiS_SetReg1 (SiS_Part1Port, 0x2D, temp); + /*SiS_SetRegANDOR(SiS_Part1Port,0x2D,~0x00F,temp); */ + SiS_SetRegAND (SiS_Part1Port, 0x13, 0xEF); /* BDirectLCD=0 for lcd ?? */ + tempax = 0; + + if (modeflag & DoubleScanMode) + tempax |= 0x80; + if (modeflag & HalfDCLK) + tempax |= 0x40; + SiS_SetRegANDOR (SiS_Part1Port, 0x2C, ~0x0C0, tempax); + + } + + if (SiS_IF_DEF_LVDS == 0) { /* 301 */ + SiS_SetGroup1_301 (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension, RefreshRateTableIndex); + } else { /* LVDS */ + SiS_SetGroup1_LVDS (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + HwDeviceExtension, RefreshRateTableIndex); + } +} + +void +SiS_SetGroup1_301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + USHORT push1, push2; + USHORT tempax, tempbx, tempcx, temp; + USHORT resinfo, modeflag; + USHORT CRT1Index; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + CRT1Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index = CRT1Index & 0x3F; + } + + if (!(SiS_VBInfo & SetInSlaveMode)) { + return; + } + tempax = 0xFFFF; + if (!(SiS_VBInfo & SetCRT2ToTV)) { + tempax = SiS_GetVGAHT2 (); + } + if (modeflag & Charx8Dot) + tempcx = 0x08; + else + tempcx = 0x09; + if (tempax >= SiS_VGAHT) { + tempax = SiS_VGAHT; + } + if (modeflag & HalfDCLK) { + tempax = tempax >> 1; + } + tempax = (tempax / tempcx) - 5; + tempbx = tempax; + temp = 0xFF; /* set MAX HT */ + SiS_SetReg1 (SiS_Part1Port, 0x03, temp); + + tempax = SiS_VGAHDE; /* 0x04 Horizontal Display End */ + if (modeflag & HalfDCLK) + tempax = tempax >> 1; + tempax = (tempax / tempcx) - 1; + tempbx = tempbx | ((tempax & 0x00FF) << 8); + temp = tempax & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x04, temp); + + temp = (tempbx & 0xFF00) >> 8; + if (SiS_VBInfo & SetCRT2ToTV) { + temp = temp + 2; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (resinfo == 7) + temp = temp - 2; + } + } + SiS_SetReg1 (SiS_Part1Port, 0x05, temp); /* 0x05 Horizontal Display Start */ + SiS_SetReg1 (SiS_Part1Port, 0x06, 0x03); /* 0x06 Horizontal Blank end */ + /* 0x07 horizontal Retrace Start */ + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + temp = (tempbx & 0x00FF) - 1; + if (!(modeflag & HalfDCLK)) { + temp = temp - 6; + if (SiS_SetFlag & TVSimuMode) { + temp = temp - 4; + if (ModeNo > 0x13) + temp = temp - 10; + } + } + } else { + tempcx = tempbx & 0x00FF; + tempbx = (tempbx & 0xFF00) >> 8; + tempcx = (tempcx + tempbx) >> 1; + temp = (tempcx & 0x00FF) + 2; + if (SiS_VBInfo & SetCRT2ToTV) { + temp = temp - 1; + if (!(modeflag & HalfDCLK)) { + if ((modeflag & Charx8Dot)) { + temp = temp + 4; + if (SiS_VGAHDE >= 800) { + temp = temp - 6; + } + } + } + } else { + if (!(modeflag & HalfDCLK)) { + temp = temp - 4; + if (SiS_LCDResInfo != Panel1280x960) { + if (SiS_VGAHDE >= 800) { + temp = temp - 7; + if (SiS_ModeType == ModeEGA) { + if (SiS_VGAVDE == 1024) { + temp = + temp + 15; + if + (SiS_LCDResInfo + != + Panel1280x1024) + { + temp = + temp + + 7; + } + } + } + if (SiS_VGAHDE >= 1280) { + if (SiS_LCDResInfo != + Panel1280x960) { + if (SiS_LCDInfo + & + LCDNonExpanding) + { + temp = + temp + + + 28; + } + } + } + } + } + } + } + } + + SiS_SetReg1 (SiS_Part1Port, 0x07, temp); /* 0x07 Horizontal Retrace Start */ + SiS_SetReg1 (SiS_Part1Port, 0x08, 0); /* 0x08 Horizontal Retrace End */ + + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_SetFlag & TVSimuMode) { + if ((ModeNo == 0x06) || (ModeNo == 0x10) + || (ModeNo == 0x11) || (ModeNo == 0x13) + || (ModeNo == 0x0F)) { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x5b); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x03); + } + if ((ModeNo == 0x00) || (ModeNo == 0x01)) { + if (SiS_VBInfo & SetNTSCTV) { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x2A); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x61); + } else { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x2A); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x41); + SiS_SetReg1 (SiS_Part1Port, 0x0C, 0xF0); + } + } + if ((ModeNo == 0x02) || (ModeNo == 0x03) + || (ModeNo == 0x07)) { + if (SiS_VBInfo & SetNTSCTV) { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x54); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x00); + } else { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x55); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x0C, 0xF0); + } + } + if ((ModeNo == 0x04) || (ModeNo == 0x05) + || (ModeNo == 0x0D) || (ModeNo == 0x50)) { + if (SiS_VBInfo & SetNTSCTV) { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x30); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x03); + } else { + SiS_SetReg1 (SiS_Part1Port, 0x07, 0x2f); + SiS_SetReg1 (SiS_Part1Port, 0x08, 0x02); + } + } + } + } + + SiS_SetReg1 (SiS_Part1Port, 0x18, 0x03); /* 0x18 SR08 */ + SiS_SetRegANDOR (SiS_Part1Port, 0x19, 0xF0, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x09, 0xFF); /* 0x09 Set Max VT */ + + tempbx = SiS_VGAVT; + push1 = tempbx; + tempcx = 0x121; + tempbx = SiS_VGAVDE; /* 0x0E Virtical Display End */ + if (tempbx == 357) + tempbx = 350; + if (tempbx == 360) + tempbx = 350; + if (tempbx == 375) + tempbx = 350; + if (tempbx == 405) + tempbx = 400; + if (tempbx == 420) + tempbx = 400; + if (tempbx == 525) + tempbx = 480; + push2 = tempbx; + if (SiS_VBInfo & SetCRT2ToLCD) { + if (SiS_LCDResInfo == Panel1024x768) { + if (!(SiS_SetFlag & LCDVESATiming)) { + if (tempbx == 350) + tempbx = tempbx + 5; + if (tempbx == 480) + tempbx = tempbx + 5; + } + } + } + tempbx--; + temp = tempbx & 0x00FF; + tempbx--; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x10, temp); /* 0x10 vertical Blank Start */ + tempbx = push2; + tempbx--; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0E, temp); + if (tempbx & 0x0100) { + tempcx = tempcx | 0x0002; + } + tempax = 0x000B; + if (modeflag & DoubleScanMode) { + tempax = tempax | 0x08000; + } + if (tempbx & 0x0200) { + tempcx = tempcx | 0x0040; + } + + temp = (tempax & 0xFF00) >> 8; + SiS_SetReg1 (SiS_Part1Port, 0x0B, temp); + if (tempbx & 0x0400) { + tempcx = tempcx | 0x0600; + } + SiS_SetReg1 (SiS_Part1Port, 0x11, 0x00); /* 0x11 Vertival Blank End */ + + tempax = push1; + tempax = tempax - tempbx; /* 0x0C Vertical Retrace Start */ + tempax = tempax >> 2; + push1 = tempax; /* push ax */ + + if (resinfo != 0x09) { + tempax = tempax << 1; + tempbx = tempax + tempbx; + } + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + tempbx = tempbx - 10; + } else { + if (SiS_SetFlag & TVSimuMode) { + if (SiS_VBInfo & SetPALTV) { + tempbx = tempbx + 40; + } + } + } + tempax = push1; + tempax = tempax >> 2; + tempax++; + tempax = tempax + tempbx; + push1 = tempax; /* push ax */ + if ((SiS_VBInfo & SetPALTV)) { + if (tempbx <= 513) { + if (tempax >= 513) { + tempbx = 513; + } + } + } + temp = (tempbx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x0C, temp); + tempbx--; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x10, temp); + if (tempbx & 0x0100) { + tempcx = tempcx | 0x0008; + } + if (tempbx & 0x0200) { + SiS_SetRegANDOR (SiS_Part1Port, 0x0B, 0x0FF, 0x20); + } + tempbx++; + if (tempbx & 0x0100) { + tempcx = tempcx | 0x0004; + } + if (tempbx & 0x0200) { + tempcx = tempcx | 0x0080; + } + if (tempbx & 0x0400) { + tempcx = tempcx | 0x0C00; + } + + tempbx = push1; /* pop ax */ + temp = tempbx & 0x00FF; + temp = temp & 0x0F; + SiS_SetReg1 (SiS_Part1Port, 0x0D, temp); /* 0x0D vertical Retrace End */ + if (tempbx & 0x0010) { + tempcx = tempcx | 0x2000; + } + + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x0A, temp); /* 0x0A CR07 */ + temp = (tempcx & 0x0FF00) >> 8; + SiS_SetReg1 (SiS_Part1Port, 0x17, temp); /* 0x17 SR0A */ + tempax = modeflag; + temp = (tempax & 0xFF00) >> 8; + + temp = (temp >> 1) & 0x09; + SiS_SetReg1 (SiS_Part1Port, 0x16, temp); /* 0x16 SR01 */ + SiS_SetReg1 (SiS_Part1Port, 0x0F, 0); /* 0x0F CR14 */ + SiS_SetReg1 (SiS_Part1Port, 0x12, 0); /* 0x12 CR17 */ + if (SiS_LCDInfo & LCDRGB18Bit) + temp = 0x80; + else + temp = 0x00; + SiS_SetReg1 (SiS_Part1Port, 0x1A, temp); /* 0x1A SR0E */ + return; +} + +void +SiS_SetGroup1_LVDS (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + USHORT modeflag, resinfo; + USHORT push1, push2, tempax, tempbx, tempcx, temp, pushcx; + ULONG tempeax = 0, tempebx, tempecx, tempvcfact = 0; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + tempax = SiS_LCDHDES; + tempbx = SiS_HDE; + tempcx = SiS_HT; + tempcx = tempcx - tempbx; /* HT-HDE */ + if (SiS_LCDInfo & LCDNonExpanding) { + if (SiS_LCDResInfo == Panel800x600) + tempbx = 800; + if (SiS_LCDResInfo == Panel1024x768) + tempbx = 1024; + } + push1 = tempax; + tempax = tempax + tempbx; /* lcdhdee */ + tempbx = SiS_HT; + if (tempax >= tempbx) { + tempax = tempax - tempbx; + } + push2 = tempax; + /* push ax lcdhdee */ + tempcx = tempcx >> 2; /* temp */ + tempcx = tempcx + tempax; /* lcdhrs */ + if (tempcx >= tempbx) { + tempcx = tempcx - tempbx; + } + /* v ah,cl */ + tempax = tempcx; + tempax = tempax >> 3; /* BPLHRS */ + temp = tempax & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x14, temp); /* Part1_14h */ + temp = (tempax & 0x00FF) + 10; + temp = temp & 0x01F; + temp = temp | (((tempcx & 0x00ff) & 0x07) << 5); + SiS_SetReg1 (SiS_Part1Port, 0x15, temp); /* Part1_15h */ + tempbx = push2; /* lcdhdee */ + tempcx = push1; /* lcdhdes */ + temp = (tempcx & 0x00FF); + temp = temp & 0x07; /* BPLHDESKEW */ + SiS_SetReg1 (SiS_Part1Port, 0x1A, temp); /* Part1_1Ah */ + tempcx = tempcx >> 3; /* BPLHDES */ + temp = (tempcx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x16, temp); /* Part1_16h */ + if (tempbx & 0x07) + tempbx = tempbx + 8; + tempbx = tempbx >> 3; /* BPLHDEE */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x17, temp); /* Part1_17h */ + + tempcx = SiS_VGAVT; + tempbx = SiS_VGAVDE; + tempcx = tempcx - tempbx; /* GAVT-VGAVDE */ + tempbx = SiS_LCDVDES; /* VGAVDES */ + push1 = tempbx; /* push bx temppush1 */ + if (SiS_IF_DEF_TRUMPION == 0) { + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + tempax = SiS_VGAVDE; + } + } + if (SiS_VBInfo & SetCRT2ToLCD) { + if (SiS_LCDResInfo == Panel800x600) + tempax = 600; + if (SiS_LCDResInfo == Panel1024x768) + tempax = 768; + } + } else + tempax = SiS_VGAVDE; + tempbx = tempbx + tempax; + tempax = SiS_VT; /* VT */ + if (tempbx >= SiS_VT) { + tempbx = tempbx - tempax; + } + push2 = tempbx; /* push bx temppush2 */ + tempcx = tempcx >> 1; + tempbx = tempbx + tempcx; + tempbx++; /* BPLVRS */ + if (tempbx >= tempax) { + tempbx = tempbx - tempax; + } + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x18, temp); /* Part1_18h */ + tempcx = tempcx >> 3; + tempcx = tempcx + tempbx; + tempcx++; /* BPLVRE */ + temp = tempcx & 0x00FF; + temp = temp & 0x0F; + SiS_SetRegANDOR (SiS_Part1Port, 0x19, ~0x00F, temp); /* Part1_19h */ + temp = (tempbx & 0xFF00) >> 8; + temp = temp & 0x07; + temp = temp << 3; /* BPLDESKEW =0 */ + tempbx = SiS_VGAVDE; + if (tempbx != SiS_VDE) { + temp = temp | 0x40; + } + if (SiS_SetFlag & EnableLVDSDDA) { + temp = temp | 0x40; + } + if (SiS_LCDInfo & LCDRGB18Bit) { + temp = temp | 0x80; + } + SiS_SetRegANDOR (SiS_Part1Port, 0x1A, 0x07, temp); /* Part1_1Ah */ + + tempecx = SiS_VGAVT; + tempebx = SiS_VDE; + tempeax = SiS_VGAVDE; + tempecx = tempecx - tempeax; /* VGAVT-VGAVDE */ + tempeax = tempeax << 6; + temp = (USHORT) (tempeax % tempebx); + tempeax = tempeax / tempebx; + if (temp != 0) { + tempeax++; + } + tempebx = tempeax; /* BPLVCFACT */ + if (SiS_SetFlag & EnableLVDSDDA) { + tempebx = tempebx & 0x003F; + } + temp = (USHORT) (tempebx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x1E, temp); /* Part1_1Eh */ + + /*add for 301b different 301 */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + tempecx = SiS_VGAVT; + tempebx = SiS_VDE; + tempeax = SiS_VGAVDE; + tempecx = tempecx - tempeax; /* VGAVT-VGAVDE */ + tempeax = tempeax << 18; + temp = (USHORT) (tempeax % tempebx); + tempeax = tempeax / tempebx; + if (temp != 0) { + tempeax++; + } + tempebx = tempeax; /* BPLVCFACT */ + tempvcfact = tempeax; /*301b */ + temp = (USHORT) (tempebx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x37, temp); + temp = (USHORT) ((tempebx & 0x00FF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x36, temp); + temp = (USHORT) ((tempebx & 0x00030000) >> 16); + if (SiS_VDE == SiS_VGAVDE) { + temp = temp | 0x04; + } + + SiS_SetReg1 (SiS_Part1Port, 0x35, temp); + } + /*end for 301b */ + + tempbx = push2; /* p bx temppush2 BPLVDEE */ + tempcx = push1; /* pop cx temppush1 NPLVDES */ + push1 = (USHORT) (tempeax & 0xFFFF); + if (!(SiS_VBInfo & SetInSlaveMode)) { + if (SiS_LCDResInfo == Panel800x600) { + if (resinfo == 7) + tempcx++; + } else { + if (SiS_LCDResInfo == Panel1024x768) { + if (resinfo == 8) + tempcx++; + } + } + } + + temp = (tempbx & 0xFF00) >> 8; + temp = temp & 0x07; + temp = temp << 3; + temp = temp | (((tempcx & 0xFF00) >> 8) & 0x07); + SiS_SetReg1 (SiS_Part1Port, 0x1D, temp); /* Part1_1Dh */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x1C, temp); /* Part1_1Ch */ + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x1B, temp); /* Part1_1Bh */ + + tempecx = SiS_VGAHDE; + tempebx = SiS_HDE; + tempeax = tempecx; + tempeax = tempeax << 6; + tempeax = tempeax << 10; + tempeax = tempeax / tempebx; + if (tempebx == tempecx) { + tempeax = 65535; + } + tempecx = tempeax; + tempeax = SiS_VGAHDE; /*change VGAHT->VGAHDE */ + tempeax = tempeax << 6; + tempeax = tempeax << 10; + tempeax = tempeax / tempecx; + tempecx = tempecx << 16; + tempeax = tempeax - 1; + tempecx = tempecx | (tempeax & 0x00FFFF); + temp = (USHORT) (tempecx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x1F, temp); /* Part1_1Fh */ + + tempeax = SiS_VGAVDE; + tempeax = tempeax << 18; /*301b */ + tempeax = tempeax / tempvcfact; + tempbx = (USHORT) (tempeax & 0x0FFFF); + if (SiS_LCDResInfo == Panel1024x768) + tempbx--; + if (SiS_SetFlag & EnableLVDSDDA) { + tempbx = 1; + } + temp = ((tempbx & 0xFF00) >> 8) << 3; + temp = temp | (USHORT) (((tempecx & 0x0000FF00) >> 8) & 0x07); + SiS_SetReg1 (SiS_Part1Port, 0x20, temp); /* Part1_20h */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x21, temp); /* Part1_21h */ + tempecx = tempecx >> 16; /* BPLHCFACT */ + if (modeflag & HalfDCLK) { + tempecx = tempecx >> 1; + } + temp = (USHORT) ((tempecx & 0x0000FF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x22, temp); /* Part1_22h */ + temp = (USHORT) (tempecx & 0x000000FF); + SiS_SetReg1 (SiS_Part1Port, 0x23, temp); + /*add dstn new register */ + if (SiS_IF_DEF_DSTN) { + SiS_SetReg1 (SiS_Part1Port, 0x1E, 0x01); + SiS_SetReg1 (SiS_Part1Port, 0x25, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x26, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x27, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x28, 0x87); + SiS_SetReg1 (SiS_Part1Port, 0x29, 0x5A); + SiS_SetReg1 (SiS_Part1Port, 0x2A, 0x4B); + SiS_SetRegANDOR (SiS_Part1Port, 0x44, ~0x007, 0x03); + tempbx = SiS_HDE; /*Blps=lcdhdee(lcdhdes+HDE) +64 */ + tempbx = tempbx + 64; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x38, temp); + temp = ((tempbx & 0xFF00) >> 8) << 3; + SiS_SetRegANDOR (SiS_Part1Port, 0x35, ~0x078, temp); + tempbx = tempbx + 32; /*Blpe=lBlps+32 */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x39, temp); + SiS_SetReg1 (SiS_Part1Port, 0x3A, 0x00); /*Bflml=0 */ + SiS_SetRegANDOR (SiS_Part1Port, 0x3C, ~0x007, 0x00); + tempbx = SiS_VDE; + tempbx = tempbx / 2; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x3B, temp); + temp = ((tempbx & 0xFF00) >> 8) << 3; + SiS_SetRegANDOR (SiS_Part1Port, 0x3C, ~0x038, temp); + tempeax = SiS_HDE; /* BDxFIFOSTOP= (HDE*4)/128 */ + tempeax = tempeax * 4; + tempebx = 128; + temp = (USHORT) (tempeax % tempebx); + tempeax = tempeax / tempebx; + if (temp != 0) { + tempeax++; + } + temp = (USHORT) (tempeax & 0x0000003F); + SiS_SetRegANDOR (SiS_Part1Port, 0x45, ~0x0FF, temp); + SiS_SetReg1 (SiS_Part1Port, 0x3F, 0x00); /*BDxWadrst0 */ + SiS_SetReg1 (SiS_Part1Port, 0x3E, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x3D, 0x10); + SiS_SetRegANDOR (SiS_Part1Port, 0x3C, ~0x040, 0x00); + tempax = SiS_HDE; + tempax = tempax >> 4; /*BDxWadroff = HDE*4/8/8 */ + pushcx = tempax; + temp = tempax & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x43, temp); + temp = ((tempax & 0xFF00) >> 8) << 3; + SiS_SetRegANDOR (SiS_Part1Port, 0x44, ~0x0F8, temp); + tempax = SiS_VDE; /*BDxWadrst1 = BDxWadrst0+BDxWadroff*VDE */ + tempeax = (tempax * pushcx); + tempebx = 0x00100000 + tempeax; + temp = (USHORT) tempebx & 0x000000FF; + SiS_SetReg1 (SiS_Part1Port, 0x42, temp); + temp = (USHORT) ((tempebx & 0x0000FF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x41, temp); + temp = (USHORT) ((tempebx & 0x00FF0000) >> 16); + SiS_SetReg1 (SiS_Part1Port, 0x40, temp); + temp = (USHORT) ((tempebx & 0x01000000) >> 24); + temp = temp << 7; + SiS_SetRegANDOR (SiS_Part1Port, 0x3C, ~0x080, temp); + SiS_SetReg1 (SiS_Part1Port, 0x2F, 0x03); + SiS_SetReg1 (SiS_Part1Port, 0x03, 0x50); + SiS_SetReg1 (SiS_Part1Port, 0x04, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0x2F, 0x01); + SiS_SetReg1 (SiS_Part1Port, 0x13, 0x00); + SiS_SetReg1 (SiS_P3c4, 0x05, 0x86); + SiS_SetReg1 (SiS_P3c4, 0x1e, 0x62); + SiS_SetReg1 (SiS_Part1Port, 0x19, 0x38); + SiS_SetReg1 (SiS_Part1Port, 0x1e, 0x7d); + } + /*end add dstn */ + + return; +} + +/*301b*/ +void +SiS_SetGroup1_LCDA (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex) +{ + USHORT modeflag, resinfo; + USHORT push1, push2, tempax, tempbx, tempcx, temp; + ULONG tempeax = 0, tempebx, tempecx, tempvcfact; /*301b */ + SiS_SetRegOR (SiS_Part1Port, 0x2D, 0x20); + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + tempax = SiS_LCDHDES; + tempbx = SiS_HDE; + tempcx = SiS_HT; + + if (SiS_LCDInfo & LCDNonExpanding) { + if (SiS_LCDResInfo == Panel1280x1024) + tempbx = 1280; + if (SiS_LCDResInfo == Panel1024x768) + tempbx = 1024; + } + tempcx = tempcx - tempbx; /* HT-HDE */ + push1 = tempax; + tempax = tempax + tempbx; /* lcdhdee */ + tempbx = SiS_HT; + if (tempax >= tempbx) { + tempax = tempax - tempbx; + } + push2 = tempax; + /* push ax lcdhdee */ + tempcx = tempcx >> 2; /* temp */ + tempcx = tempcx + tempax; /* lcdhrs */ + if (tempcx >= tempbx) { + tempcx = tempcx - tempbx; + } + /* v ah,cl */ + tempax = tempcx; + tempax = tempax >> 3; /* BPLHRS */ + temp = tempax & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x14, temp); /* Part1_14h */ + temp = (tempax & 0x00FF) + 10; + temp = temp & 0x01F; + temp = temp | (((tempcx & 0x00ff) & 0x07) << 5); + SiS_SetReg1 (SiS_Part1Port, 0x15, temp); /* Part1_15h */ + tempbx = push2; /* lcdhdee */ + tempcx = push1; /* lcdhdes */ + temp = (tempcx & 0x00FF); + temp = temp & 0x07; /* BPLHDESKEW */ + SiS_SetReg1 (SiS_Part1Port, 0x1A, temp); /* Part1_1Ah */ + tempcx = tempcx >> 3; /* BPLHDES */ + temp = (tempcx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x16, temp); /* Part1_16h */ + if (tempbx & 0x07) + tempbx = tempbx + 8; + tempbx = tempbx >> 3; /* BPLHDEE */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x17, temp); /* Part1_17h */ + + tempcx = SiS_VGAVT; + tempbx = SiS_VGAVDE; + tempcx = tempcx - tempbx; /* GAVT-VGAVDE */ + tempbx = SiS_LCDVDES; /* VGAVDES */ + push1 = tempbx; /* push bx temppush1 */ + if (SiS_IF_DEF_TRUMPION == 0) { + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + tempax = SiS_VGAVDE; + } + } + + if (SiS_LCDResInfo == Panel1024x768) + tempax = 768; + if (SiS_LCDResInfo == Panel1280x1024) + tempax = 1024; + + } else + tempax = SiS_VGAVDE; + tempbx = tempbx + tempax; + tempax = SiS_VT; /* VT */ + if (tempbx >= SiS_VT) { + tempbx = tempbx - tempax; + } + push2 = tempbx; /* push bx temppush2 */ + tempcx = tempcx >> 1; + tempbx = tempbx + tempcx; + tempbx++; /* BPLVRS */ + if (tempbx >= tempax) { + tempbx = tempbx - tempax; + } + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x18, temp); /* Part1_18h */ + tempcx = tempcx >> 3; + tempcx = tempcx + tempbx; + tempcx++; /* BPLVRE */ + temp = tempcx & 0x00FF; + temp = temp & 0x0F; + SiS_SetRegANDOR (SiS_Part1Port, 0x19, ~0x00F, temp); /* Part1_19h */ + temp = (tempbx & 0xFF00) >> 8; + temp = temp & 0x07; + temp = temp << 3; /* BPLDESKEW =0 */ + tempbx = SiS_VGAVDE; + if (tempbx != SiS_VDE) { + temp = temp | 0x40; + } + if (SiS_SetFlag & EnableLVDSDDA) { + temp = temp | 0x40; + } + if (SiS_LCDInfo & LCDRGB18Bit) { + temp = temp | 0x80; + } + SiS_SetRegANDOR (SiS_Part1Port, 0x1A, 0x07, temp); /* Part1_1Ah */ + + tempbx = push2; /* p bx temppush2 BPLVDEE */ + tempcx = push1; /* pop cx temppush1 NPLVDES */ + push1 = (USHORT) (tempeax & 0xFFFF); + + if (!(SiS_VBInfo & SetInSlaveMode)) { + if (SiS_LCDResInfo == Panel800x600) { + if (resinfo == 7) + tempcx++; + } else { + if (SiS_LCDResInfo == Panel1024x768) { + if (resinfo == 8) + tempcx++; + } + } + } + + temp = (tempbx & 0xFF00) >> 8; + temp = temp & 0x07; + temp = temp << 3; + temp = temp | (((tempcx & 0xFF00) >> 8) & 0x07); + SiS_SetReg1 (SiS_Part1Port, 0x1D, temp); /* Part1_1Dh */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x1C, temp); /* Part1_1Ch */ + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x1B, temp); /* Part1_1Bh */ + + tempecx = SiS_VGAVT; + tempebx = SiS_VDE; + tempeax = SiS_VGAVDE; + tempecx = tempecx - tempeax; /* VGAVT-VGAVDE */ + tempeax = tempeax << 18; + temp = (USHORT) (tempeax % tempebx); + tempeax = tempeax / tempebx; + if (temp != 0) { + tempeax++; + } + tempebx = tempeax; /* BPLVCFACT */ + tempvcfact = tempeax; /*301b */ + temp = (USHORT) (tempebx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x37, temp); + temp = (USHORT) ((tempebx & 0x00FF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x36, temp); + temp = (USHORT) ((tempebx & 0x00030000) >> 16); + if (SiS_VDE == SiS_VGAVDE) { + temp = temp | 0x04; + } + + SiS_SetReg1 (SiS_Part1Port, 0x35, temp); + + tempecx = SiS_VGAHDE; + tempebx = SiS_HDE; + tempeax = tempecx; + tempeax = tempeax << 6; + tempeax = tempeax << 10; + tempeax = tempeax / tempebx; + if (tempebx == tempecx) { + tempeax = 65535; + } + tempecx = tempeax; + tempeax = SiS_VGAHDE; /*301b to change HT->HDE */ + tempeax = tempeax << 6; + tempeax = tempeax << 10; + tempeax = tempeax / tempecx; + tempecx = tempecx << 16; + tempeax = tempeax - 1; + tempecx = tempecx | (tempeax & 0x00FFFF); + temp = (USHORT) (tempecx & 0x00FF); + SiS_SetReg1 (SiS_Part1Port, 0x1F, temp); /* Part1_1Fh */ + + tempeax = SiS_VGAVDE; + tempeax = tempeax << 18; /*301b */ + tempeax = tempeax / tempvcfact; + tempbx = (USHORT) (tempeax & 0x0FFFF); + if (SiS_LCDResInfo == Panel1024x768) + tempbx--; + if (SiS_SetFlag & EnableLVDSDDA) { + tempbx = 1; + } + temp = ((tempbx & 0xFF00) >> 8) << 3; + temp = temp | (USHORT) (((tempecx & 0x0000FF00) >> 8) & 0x07); + SiS_SetReg1 (SiS_Part1Port, 0x20, temp); /* Part1_20h */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part1Port, 0x21, temp); /* Part1_21h */ + tempecx = tempecx >> 16; /* BPLHCFACT */ + + temp = (USHORT) ((tempecx & 0x0000FF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x22, temp); /* Part1_22h */ + temp = (USHORT) (tempecx & 0x000000FF); + SiS_SetReg1 (SiS_Part1Port, 0x23, temp); + return; +} + +/*end 301b*/ +void +SiS_SetTPData () +{ + return; +} + +void +SiS_SetCRT2Offset (USHORT SiS_Part1Port, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT offset; + UCHAR temp; + + if (SiS_VBInfo & SetInSlaveMode) { + return; + } + offset = + SiS_GetOffset (ROMAddr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + HwDeviceExtension); + temp = (UCHAR) (offset & 0xFF); + SiS_SetReg1 (SiS_Part1Port, 0x07, temp); + temp = (UCHAR) ((offset & 0xFF00) >> 8); + SiS_SetReg1 (SiS_Part1Port, 0x09, temp); + temp = (UCHAR) (((offset >> 3) & 0xFF) + 1); + SiS_SetReg1 (SiS_Part1Port, 0x03, temp); +} + +USHORT +SiS_GetOffset (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp, colordepth; + USHORT modeinfo, index, infoflag; + USHORT ColorDepth[] = { 0x01, 0x02, 0x04 }; + + modeinfo = SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo; + infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + if (HwDeviceExtension->jChipType < SIS_315H) { /* 300 series */ + index = (modeinfo >> 4) & 0xFF; + } else { /* 310 series */ + + index = (modeinfo >> 8) & 0xFF; + } + temp = SiS_ScreenOffset[index]; + if (infoflag & InterlaceMode) { + temp = temp << 1; + } + colordepth = SiS_GetColorDepth (ROMAddr, ModeNo, ModeIdIndex); + + if ((ModeNo >= 0x7C) && (ModeNo <= 0x7E)) { + temp = ModeNo - 0x7C; + colordepth = ColorDepth[temp]; + temp = 0x6B; + if (infoflag & InterlaceMode) { + temp = temp << 1; + } + return (temp * colordepth); + } else + return (temp * colordepth); +} + +USHORT +SiS_GetColorDepth (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT ColorDepth[6] = { 1, 2, 4, 4, 6, 8 }; + SHORT index; + USHORT modeflag; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + index = (modeflag & ModeInfoFlag) - ModeEGA; + if (index < 0) + index = 0; + return (ColorDepth[index]); +} + +void +SiS_SetCRT2Sync (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT RefreshRateTableIndex) +{ + USHORT tempah = 0, infoflag, flag; + + flag = 0; + infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; + if (SiS_IF_DEF_LVDS == 1) { + if (SiS_VBInfo & SetCRT2ToLCD) { + tempah = SiS_LCDInfo; + if (tempah & LCDSync) { + flag = 1; + } + } + } + if (flag != 1) + tempah = infoflag >> 8; + tempah = tempah & 0xC0; + tempah = tempah | 0x20; + if (!(SiS_LCDInfo & LCDRGB18Bit)) + tempah = tempah | 0x10; + if (SiS_IF_DEF_CH7005 == 1) + tempah = tempah | 0xC0; + + SiS_SetRegANDOR (SiS_Part1Port, 0x19, 0x3F, tempah); +} + +void +SiS_SetCRT2FIFO (USHORT SiS_Part1Port, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp, index; + USHORT modeidindex, refreshratetableindex; + USHORT VCLK, MCLK, colorth = 0, data, data2; + ULONG eax; + UCHAR LatencyFactor[] = { 97, 88, 86, 79, 77, 00, /*; 64 bit BQ=2 */ + 00, 87, 85, 78, 76, 54, /*; 64 bit BQ=1 */ + 97, 88, 86, 79, 77, 00, /*; 128 bit BQ=2 */ + 00, 79, 77, 70, 68, 48, /*; 128 bit BQ=1 */ + 80, 72, 69, 63, 61, 00, /*; 64 bit BQ=2 */ + 00, 70, 68, 61, 59, 37, /*; 64 bit BQ=1 */ + 86, 77, 75, 68, 66, 00, /*; 128 bit BQ=2 */ + 00, 68, 66, 59, 57, 37 + }; /*; 128 bit BQ=1 */ + + SiS_SearchModeID (ROMAddr, ModeNo, &modeidindex); + SiS_SetFlag = SiS_SetFlag & (~ProgrammingCRT2); + SiS_SelectCRT2Rate = 0; + refreshratetableindex = SiS_GetRatePtrCRT2 (ROMAddr, ModeNo, modeidindex); /* 11.GetRatePtr */ + if (ModeNo >= 0x13) { + index = SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK; + index = index & 0x3F; + VCLK = SiS_VCLKData[index].CLOCK; /* Get VCLK */ + index = SiS_GetReg1 (SiS_P3c4, 0x1A); + index = index & 07; + MCLK = SiS_MCLKData[index].CLOCK; /* Get MCLK */ + data2 = SiS_ModeType - 0x02; + switch (data2) { + case 0: + colorth = 1; + break; + case 1: + colorth = 1; + break; + case 2: + colorth = 2; + break; + case 3: + colorth = 2; + break; + case 4: + colorth = 3; + break; + case 5: + colorth = 4; + break; + } + data2 = (data2 * VCLK) / MCLK; /* bx */ + + temp = SiS_GetReg1 (SiS_P3c4, 0x14); + temp = ((temp & 0x00FF) >> 6) << 1; + if (temp == 0) + temp = 1; + temp = temp << 2; + + data2 = temp - data2; + if (data2 % (28 * 16)) { + data2 = data2 / (28 * 16); + data2++; + } else { + data2 = data2 / (28 * 16); + } + + index = 0; + temp = SiS_GetReg1 (SiS_P3c4, 0x14); + if (temp & 0x0080) + index = index + 12; + SiS_SetReg4 (0xcf8, 0x800000A0); + eax = SiS_GetReg3 (0xcfc); + temp = (USHORT) (eax >> 24); + if (!(temp & 0x01)) + index = index + 24; + + SiS_SetReg4 (0xcf8, 0x80000050); + eax = SiS_GetReg3 (0xcfc); + temp = (USHORT) (eax >> 24); + if (temp & 0x01) + index = index + 6; + temp = (temp & 0x0F) >> 1; + index = index + temp; + data = LatencyFactor[index]; + data = data + 15; + temp = SiS_GetReg1 (SiS_P3c4, 0x14); + if (!(temp & 0x80)) + data = data + 5; + data = data + data2; + + SiS_SetFlag = SiS_SetFlag | ProgrammingCRT2; + data = data * VCLK * colorth; + if (data % (MCLK << 4)) { + data = data / (MCLK << 4); + data++; + } else { + data = data / (MCLK << 4); + } + temp = 0x16; +/* Revision ID */ + temp = 0x13; +/* Revision ID */ + SiS_SetRegANDOR (SiS_Part1Port, 0x01, ~0x01F, temp); + SiS_SetRegANDOR (SiS_Part1Port, 0x02, ~0x01F, temp); + } +} + +void +SiS_SetCRT2FIFO2 (USHORT SiS_Part1Port, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ +#ifdef CONFIG_FB_SIS_315 + UCHAR CombCode[] = { 1, 1, 1, 4, 3, 1, 3, 4, 4, 1, 4, 4, 5, 1, 5, 4 }; + UCHAR CRT2ThLow[] = + { 39, 63, 55, 79, 78, 102, 90, 114, 55, 87, 84, 116, 103, 135, 119, + 151 }; +#endif + USHORT temp, temp1, temp2, temp3; + USHORT index; + USHORT CRT1ModeNo, CRT2ModeNo; + USHORT ModeIdIndex; + USHORT RefreshRateTableIndex; + + SiS_SetReg1 (SiS_Part1Port, 0x1, 0x3B); +/* CRT1ModeNo=(UCHAR)SiS_GetReg1(SiS_P3d4,0x34); *//* get CRT1 ModeNo */ + CRT1ModeNo = SiS_CRT1Mode; + /* CRT1ModeNo =ModeNo; */ + SiS_SearchModeID (ROMAddr, CRT1ModeNo, &ModeIdIndex); /* Get ModeID Table */ + SiS_SetFlag = SiS_SetFlag & (~ProgrammingCRT2); + + RefreshRateTableIndex = SiS_GetRatePtrCRT2 (ROMAddr, CRT1ModeNo, ModeIdIndex); /* Set REFIndex-> for crt1 refreshrate */ + index = + SiS_GetVCLK2Ptr (ROMAddr, CRT1ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + temp1 = SiS_VCLKData[index].CLOCK; /* Get VCLK */ + + temp2 = SiS_GetColorDepth (ROMAddr, CRT1ModeNo, ModeIdIndex); +#ifdef CONFIG_FB_SIS_315 + index = SiS_Get310DRAMType (ROMAddr); +#endif + temp3 = SiS_MCLKData[index].CLOCK; /* Get MCLK */ + + temp = SiS_GetReg1 (SiS_P3c4, 0x14); + if (temp & 0x02) + temp = 16; + else + temp = 8; + + temp = temp - temp1 * temp2 / temp3; /* 16-DRamBus - DCLK*BytePerPixel/MCLK */ + + if ((52 * 16 % temp) == 0) + temp = 52 * 16 / temp + 40; + else + temp = 52 * 16 / temp + 40 + 1; + + /* get DRAM latency */ + temp1 = (SiS_GetReg1 (SiS_P3c4, 0x17) >> 3) & 0x7; /* SR17[5:3] DRAM Queue depth */ + temp2 = (SiS_GetReg1 (SiS_P3c4, 0x17) >> 6) & 0x3; /* SR17[7:6] DRAM Grant length */ + +#ifdef CONFIG_FB_SIS_315 + if (SiS_Get310DRAMType (ROMAddr) < 2) { + for (temp3 = 0; temp3 < 16; temp3 += 2) { + if ((CombCode[temp3] == temp1) + && (CombCode[temp3 + 1] == temp2)) { + temp3 = CRT2ThLow[temp3 >> 1]; + } + } + } else { + for (temp3 = 0; temp3 < 16; temp3 += 2) { + if ((CombCode[temp3] == temp1) + && (CombCode[temp3 + 1] == temp2)) { + temp3 = CRT2ThLow[8 + (temp3 >> 1)]; + } + } + } +#endif + + temp += temp3; /* CRT1 Request Period */ + + CRT2ModeNo = ModeNo; /* get CRT2 ModeNo */ + SiS_SearchModeID (ROMAddr, CRT2ModeNo, &ModeIdIndex); /* Get ModeID Table */ + SiS_SetFlag = SiS_SetFlag | ProgrammingCRT2; + RefreshRateTableIndex = SiS_GetRatePtrCRT2 (ROMAddr, CRT1ModeNo, ModeIdIndex); /* Set REFIndex-> for crt1 refreshrate */ + index = + SiS_GetVCLK2Ptr (ROMAddr, CRT2ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + temp1 = SiS_VCLKData[index].CLOCK; /* Get VCLK */ + + temp2 = SiS_GetColorDepth (ROMAddr, CRT2ModeNo, ModeIdIndex); +#ifdef CONFIG_FB_SIS_315 + index = SiS_Get310DRAMType (ROMAddr); +#endif + temp3 = SiS_MCLKData[index].CLOCK; /* Get MCLK */ + + if ((temp * temp1 * temp2) % (16 * temp3) == 0) + temp = temp * temp1 * temp2 / (16 * temp3); /* CRT1 Request period * TCLK*BytePerPixel/(MCLK*16) */ + else + temp = temp * temp1 * temp2 / (16 * temp3) + 1; /* CRT1 Request period * TCLK*BytePerPixel/(MCLK*16) */ + + if (temp > 0x37) + temp = 0x37; + + SiS_SetRegANDOR (SiS_Part1Port, 0x02, ~0x3F, temp); + +} + +void +SiS_GetLVDSDesData (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + + USHORT modeflag; + USHORT PanelIndex, ResIndex; + SiS_LVDSDesStruct *PanelDesPtr = NULL; + if ((SiS_IF_DEF_LVDS == 0) + && ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { /*301b *//*for test */ + SiS_GetLVDSDesPtrA (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &PanelIndex, + &ResIndex); + switch (PanelIndex) { + case 0: + PanelDesPtr = LVDS1024x768Des_1; + break; + case 1: + PanelDesPtr = LVDS1280x1024Des_1; + break; + case 2: + PanelDesPtr = LVDS1280x960Des_1; + break; + case 3: + PanelDesPtr = LVDS1024x768Des_2; + break; + case 4: + PanelDesPtr = LVDS1280x1024Des_2; + break; + case 5: + PanelDesPtr = LVDS1280x960Des_2; + break; + } + } else { + SiS_GetLVDSDesPtr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &PanelIndex, + &ResIndex); + switch (PanelIndex) { + case 0: + PanelDesPtr = SiS_PanelType00_1; + break; + case 1: + PanelDesPtr = SiS_PanelType01_1; + break; + case 2: + PanelDesPtr = SiS_PanelType02_1; + break; + case 3: + PanelDesPtr = SiS_PanelType03_1; + break; + case 4: + PanelDesPtr = SiS_PanelType04_1; + break; + case 5: + PanelDesPtr = SiS_PanelType05_1; + break; + case 6: + PanelDesPtr = SiS_PanelType06_1; + break; + case 7: + PanelDesPtr = SiS_PanelType07_1; + break; + case 8: + PanelDesPtr = SiS_PanelType08_1; + break; + case 9: + PanelDesPtr = SiS_PanelType09_1; + break; + case 10: + PanelDesPtr = SiS_PanelType0a_1; + break; + case 11: + PanelDesPtr = SiS_PanelType0b_1; + break; + case 12: + PanelDesPtr = SiS_PanelType0c_1; + break; + case 13: + PanelDesPtr = SiS_PanelType0d_1; + break; + case 14: + PanelDesPtr = SiS_PanelType0e_1; + break; + case 15: + PanelDesPtr = SiS_PanelType0f_1; + break; + case 16: + PanelDesPtr = SiS_PanelType00_2; + break; + case 17: + PanelDesPtr = SiS_PanelType01_2; + break; + case 18: + PanelDesPtr = SiS_PanelType02_2; + break; + case 19: + PanelDesPtr = SiS_PanelType03_2; + break; + case 20: + PanelDesPtr = SiS_PanelType04_2; + break; + case 21: + PanelDesPtr = SiS_PanelType05_2; + break; + case 22: + PanelDesPtr = SiS_PanelType06_2; + break; + case 23: + PanelDesPtr = SiS_PanelType07_2; + break; + case 24: + PanelDesPtr = SiS_PanelType08_2; + break; + case 25: + PanelDesPtr = SiS_PanelType09_2; + break; + case 26: + PanelDesPtr = SiS_PanelType0a_2; + break; + case 27: + PanelDesPtr = SiS_PanelType0b_2; + break; + case 28: + PanelDesPtr = SiS_PanelType0c_2; + break; + case 29: + PanelDesPtr = SiS_PanelType0d_2; + break; + case 30: + PanelDesPtr = SiS_PanelType0e_2; + break; + case 31: + PanelDesPtr = SiS_PanelType0f_2; + break; + case 32: + PanelDesPtr = SiS_CHTVUNTSCDesData; + break; + case 33: + PanelDesPtr = SiS_CHTVONTSCDesData; + break; + case 34: + PanelDesPtr = SiS_CHTVUPALDesData; + break; + case 35: + PanelDesPtr = SiS_CHTVOPALDesData; + break; + } + } + SiS_LCDHDES = (PanelDesPtr + ResIndex)->LCDHDES; + SiS_LCDVDES = (PanelDesPtr + ResIndex)->LCDVDES; + if (SiS_LCDInfo & LCDNonExpanding) { + if (SiS_LCDResInfo >= Panel1024x768) { + if (ModeNo <= 0x13) { + modeflag = + SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + if (!(modeflag & HalfDCLK)) { + SiS_LCDHDES = 320; + } + } + } + } + return; + +} + +void +SiS_GetLVDSDesPtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * PanelIndex, + USHORT * ResIndex) +{ + USHORT tempbx, tempal; + + tempbx = 0; + if (SiS_IF_DEF_CH7005 == 1) { + if (!(SiS_VBInfo & SetCRT2ToLCD)) { + tempbx = 32; + if (SiS_VBInfo & SetPALTV) + tempbx = tempbx + 2; + if (SiS_VBInfo & SetCHTVOverScan) + tempbx = tempbx + 1; + } + } + if (SiS_VBInfo & SetCRT2ToLCD) { + tempbx = SiS_LCDTypeInfo; + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = tempbx + 16; + } + } + if (ModeNo <= 0x13) { + tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + tempal = tempal & 0x1F; + *PanelIndex = tempbx; + *ResIndex = tempal; +} + +/*301b*/ +void +SiS_GetLVDSDesPtrA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * PanelIndex, + USHORT * ResIndex) +{ + USHORT tempbx, tempal; + + tempbx = 0; + tempbx = SiS_LCDResInfo; + tempbx = tempbx - Panel1024x768; + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = tempbx + 3; + } + + if (ModeNo <= 0x13) { + tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + tempal = tempal & 0x1F; + *PanelIndex = tempbx; + *ResIndex = tempal; +} + +/*end 301b*/ + +void +SiS_SetCRT2ModeRegs (USHORT BaseAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT i, j; + USHORT tempcl, tempah; +/*301b*/ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_SetRegANDOR (SiS_Part1Port, 0x00, ~0x050, 0x40); + SiS_SetRegAND (SiS_Part1Port, 0x2E, 0xF7); + SiS_SetRegANDOR (SiS_Part1Port, 0x13, 0xFB, 0x04); + SiS_SetRegANDOR (SiS_Part1Port, 0x2c, 0xCF, 0x30); + SiS_SetRegANDOR (SiS_Part4Port, 0x21, 0x3F, 0xC0); + SiS_SetRegANDOR (SiS_Part4Port, 0x23, 0x7F, 0x00); + } + /*end 301b */ + else { + for (i = 0, j = 4; i < 3; i++, j++) + SiS_SetReg1 (SiS_Part1Port, j, 0); + + tempcl = SiS_ModeType; + if (HwDeviceExtension->jChipType < SIS_315H) { /* 300 series */ + if (ModeNo > 0x13) { + tempcl = tempcl - ModeVGA; + if ((tempcl > 0) || (tempcl == 0)) { + tempah = ((0x010 >> tempcl) | 0x080); + } + } else { + tempah = 0x080; + } + if (SiS_VBInfo & SetInSlaveMode) { + tempah = (tempah ^ 0x0A0); + } + } else { /* 310 series */ + + if (ModeNo > 0x13) { + tempcl = tempcl - ModeVGA; + if ((tempcl > 0) || (tempcl == 0)) { + tempah = (0x008 >> tempcl); + if (tempah == 0) + tempah = 1; + tempah |= 0x040; + } + } else { + tempah = 0x040; + } + + if (SiS_VBInfo & SetInSlaveMode) { + tempah = (tempah ^ 0x050); + } + + } + + if (SiS_VBInfo & CRT2DisplayFlag) { + tempah = 0; + } + SiS_SetReg1 (SiS_Part1Port, 0x00, tempah); + + if (SiS_IF_DEF_LVDS == 0) { /* ifdef 301 */ + tempah = 0x01; + if (!(SiS_VBInfo & SetInSlaveMode)) { + tempah = (tempah | 0x02); + } + if (!(SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempah = (tempah ^ 0x05); + if (!(SiS_VBInfo & SetCRT2ToLCD)) { + tempah = (tempah ^ 0x01); + } + } + + tempcl = tempah; /* 05/03/01 ynlai for TV display bug */ + + if (HwDeviceExtension->jChipType < SIS_315H) { /* 300 series */ + tempah = (tempah << 5) & 0xFF; + if (SiS_VBInfo & CRT2DisplayFlag) { + tempah = 0; + } + SiS_SetReg1 (SiS_Part1Port, 0x01, tempah); + + tempah = tempah >> 5; + } else { /* 310 series */ + + if (SiS_VBInfo & CRT2DisplayFlag) { + tempah = 0; + } + tempah = + (SiS_GetReg1 (SiS_Part1Port, 0x2E) & 0xF8) | + tempah; + SiS_SetReg1 (SiS_Part1Port, 0x2E, tempah); + tempah = tempcl; + } + + if ((SiS_ModeType == ModeVGA) + && (!(SiS_VBInfo & SetInSlaveMode))) { + tempah = tempah | 0x010; + } + + if (SiS_LCDResInfo == Panel1024x768) + tempah = tempah | 0x080; + + if ((SiS_LCDResInfo == Panel1280x1024) + || (SiS_LCDResInfo == Panel1280x960)) { + tempah = tempah | 0x080; + } + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_VBInfo & SetInSlaveMode) { + if ( + ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B))) { /*301b */ + if (SiS_SetFlag & TVSimuMode) + tempah = tempah | 0x020; + } else + tempah = tempah | 0x020; + } + } + SiS_SetRegANDOR (SiS_Part4Port, 0x0D, ~0x0BF, tempah); + tempah = 0; + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_VBInfo & SetInSlaveMode) { + if ( + ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B))) { /*301b */ + { + SiS_SetFlag = + SiS_SetFlag | + RPLLDIV2XO; + tempah = tempah | 0x40; + } + } else { + if (!(SiS_SetFlag & TVSimuMode)) { + if (! + (SiS_VBInfo & + SetCRT2ToHiVisionTV)) + { + SiS_SetFlag = + SiS_SetFlag + | + RPLLDIV2XO; + tempah = + tempah | + 0x40; + } + } + } + } else { + SiS_SetFlag = SiS_SetFlag | RPLLDIV2XO; + tempah = tempah | 0x40; + } + } + if (SiS_LCDResInfo == Panel1280x1024) + tempah = tempah | 0x80; + if (SiS_LCDResInfo == Panel1280x960) + tempah = tempah | 0x80; + SiS_SetReg1 (SiS_Part4Port, 0x0C, tempah); + } else { + /*LVDS*/ tempah = 0; + if (!(SiS_VBInfo & SetInSlaveMode)) { + tempah = tempah | 0x02; + } + SiS_SetRegANDOR (SiS_Part1Port, 0x2e, 0xF0, tempah); + } + } +/*301b*/ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (!(SiS_VBInfo & SetCRT2ToLCDA))) { + if (SiS_IsDualEdge (BaseAddr)) + SiS_SetRegANDOR (SiS_Part1Port, 0x13, 0xFB, 0x00); + else + SiS_SetRegANDOR (SiS_Part1Port, 0x13, 0xFF, 0x00); + if (SiS_IsDualEdge (BaseAddr)) + SiS_SetRegANDOR (SiS_Part1Port, 0x2c, 0xCF, 0x00); + else + SiS_SetRegANDOR (SiS_Part1Port, 0x2c, 0xFF, 0x00); + if (SiS_IsDualEdge (BaseAddr)) + SiS_SetRegANDOR (SiS_Part4Port, 0x21, 0x3F, 0x00); + else + SiS_SetRegANDOR (SiS_Part4Port, 0x21, 0xFF, 0x00); + + if (SiS_IsDualEdge (BaseAddr)) + SiS_SetRegANDOR (SiS_Part4Port, 0x23, 0xFF, 0x80); + else + SiS_SetRegANDOR (SiS_Part4Port, 0x23, 0xFF, 0x00); + } + +/*end 301b*/ +} +void +SiS_GetCRT2Data (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + if (SiS_IF_DEF_LVDS == 0) { /*301 */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetCRT2ToLCDA) + SiS_GetCRT2DataLVDS (ROMAddr, ModeNo, + ModeIdIndex, + RefreshRateTableIndex); + else + SiS_GetCRT2Data301 (ROMAddr, ModeNo, + ModeIdIndex, + RefreshRateTableIndex); + } else + SiS_GetCRT2Data301 (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + return; + } else { /*LVDS */ + SiS_GetCRT2DataLVDS (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + return; + } +} + +void +SiS_GetCRT2DataLVDS (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT tempax, tempbx; + USHORT CRT2Index, ResIndex; + SiS_LVDSDataStruct *LVDSData = NULL; + + SiS_GetCRT2ResInfo (ROMAddr, ModeNo, ModeIdIndex); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + SiS_GetCRT2PtrA (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &CRT2Index, &ResIndex); + switch (CRT2Index) { + case 0: + LVDSData = SiS_LVDS1024x768Data_1; + break; + case 1: + LVDSData = SiS_LVDS1280x1024Data_1; + break; + case 2: + LVDSData = SiS_LVDS1280x1024Data_1; + break; + /* case 2: LVDSData=SiS_LVDS1280x960Data_1; break; */ + case 3: + LVDSData = SiS_LVDS1024x768Data_2; + break; + case 4: + LVDSData = SiS_LVDS1280x1024Data_2; + break; + case 5: + LVDSData = SiS_LVDS1280x1024Data_2; + break; + /* case 5: LVDSData=SiS_LVDS1280x960Data_2; break; */ + } + } + + else { + SiS_GetCRT2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &CRT2Index, &ResIndex); + switch (CRT2Index) { + case 0: + LVDSData = SiS_LVDS800x600Data_1; + break; + case 1: + LVDSData = SiS_LVDS1024x768Data_1; + break; + case 2: + LVDSData = SiS_LVDS1280x1024Data_1; + break; + case 3: + LVDSData = SiS_LVDS800x600Data_2; + break; + case 4: + LVDSData = SiS_LVDS1024x768Data_2; + break; + case 5: + LVDSData = SiS_LVDS1280x1024Data_2; + break; + case 6: + LVDSData = SiS_LVDS640x480Data_1; + break; + case 7: + LVDSData = SiS_CHTVUNTSCData; + break; + case 8: + LVDSData = SiS_CHTVONTSCData; + break; + case 9: + LVDSData = SiS_CHTVUPALData; + break; + case 10: + LVDSData = SiS_CHTVOPALData; + break; + } + } + SiS_VGAHT = (LVDSData + ResIndex)->VGAHT; + SiS_VGAVT = (LVDSData + ResIndex)->VGAVT; + SiS_HT = (LVDSData + ResIndex)->LCDHT; + SiS_VT = (LVDSData + ResIndex)->LCDVT; +/*301b*/ + if ((SiS_IF_DEF_LVDS == 0) + && ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { /*for test */ + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (SiS_LCDResInfo == Panel1024x768) { + tempax = 1024; + tempbx = 768; + } else { + tempax = 1280; + tempbx = 1024; + } + SiS_HDE = tempax; + SiS_VDE = tempbx; + } + } else { + if (SiS_IF_DEF_TRUMPION == 0) { + if (SiS_VBInfo & SetCRT2ToLCD) { + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (SiS_LCDResInfo == Panel800x600) { + tempax = 800; + tempbx = 600; + } else if (SiS_LCDResInfo == + Panel1024x768) { + tempax = 1024; + tempbx = 768; + } else { + tempax = 1280; + tempbx = 1024; + } + SiS_HDE = tempax; + SiS_VDE = tempbx; + } + } + } + } + return; +} + +void +SiS_GetCRT2Data301 (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT tempax, tempbx, modeflag; + USHORT resinfo; + USHORT CRT2Index, ResIndex; + SiS_LCDDataStruct *LCDPtr = NULL; + SiS_TVDataStruct *TVPtr = NULL; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + SiS_NewFlickerMode = 0; + SiS_RVBHRS = 50; + SiS_RY1COE = 0; + SiS_RY2COE = 0; + SiS_RY3COE = 0; + SiS_RY4COE = 0; + + SiS_GetCRT2ResInfo (ROMAddr, ModeNo, ModeIdIndex); + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + SiS_GetRAMDAC2DATA (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex); + return; + } + + if (SiS_VBInfo & SetCRT2ToTV) { + SiS_GetCRT2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &CRT2Index, &ResIndex); + switch (CRT2Index) { + case 2: + TVPtr = SiS_ExtHiTVData; + break; + case 3: + TVPtr = SiS_ExtPALData; + break; + case 4: + TVPtr = SiS_ExtNTSCData; + break; + case 7: + TVPtr = SiS_St1HiTVData; + break; + case 8: + TVPtr = SiS_StPALData; + break; + case 9: + TVPtr = SiS_StNTSCData; + break; + case 12: + TVPtr = SiS_St2HiTVData; + break; + } + + SiS_RVBHCMAX = (TVPtr + ResIndex)->RVBHCMAX; + SiS_RVBHCFACT = (TVPtr + ResIndex)->RVBHCFACT; + SiS_VGAHT = (TVPtr + ResIndex)->VGAHT; + SiS_VGAVT = (TVPtr + ResIndex)->VGAVT; + SiS_HDE = (TVPtr + ResIndex)->TVHDE; + SiS_VDE = (TVPtr + ResIndex)->TVVDE; + SiS_RVBHRS = (TVPtr + ResIndex)->RVBHRS; + SiS_NewFlickerMode = (TVPtr + ResIndex)->FlickerMode; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (resinfo == 0x08) + SiS_NewFlickerMode = 0x40; + if (resinfo == 0x09) + SiS_NewFlickerMode = 0x40; + if (resinfo == 0x10) + SiS_NewFlickerMode = 0x40; + } + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (SiS_VGAVDE == 350) + SiS_SetFlag = SiS_SetFlag | TVSimuMode; + tempax = ExtHiTVHT; + tempbx = ExtHiTVVT; + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_SetFlag & TVSimuMode) { + tempax = StHiTVHT; + tempbx = StHiTVVT; + if (!(modeflag & Charx8Dot)) { + tempax = StHiTextTVHT; + tempbx = StHiTextTVVT; + } + } + } + } + if (!(SiS_VBInfo & SetCRT2ToHiVisionTV)) { + SiS_RY1COE = (TVPtr + ResIndex)->RY1COE; + SiS_RY2COE = (TVPtr + ResIndex)->RY2COE; + if (modeflag & HalfDCLK) { + SiS_RY1COE = 0x00; + SiS_RY2COE = 0xf4; + } + SiS_RY3COE = (TVPtr + ResIndex)->RY3COE; + SiS_RY4COE = (TVPtr + ResIndex)->RY4COE; + if (modeflag & HalfDCLK) { + SiS_RY3COE = 0x10; + SiS_RY4COE = 0x38; + } + if (!(SiS_VBInfo & SetPALTV)) { + tempax = NTSCHT; + tempbx = NTSCVT; + } else { + tempax = PALHT; + tempbx = PALVT; + } + } + SiS_HT = tempax; + SiS_VT = tempbx; + return; + } + + if (SiS_VBInfo & SetCRT2ToLCD) { + SiS_GetCRT2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &CRT2Index, &ResIndex); + switch (CRT2Index) { + case 0: + LCDPtr = SiS_ExtLCD1024x768Data; + break; + case 1: + LCDPtr = SiS_ExtLCD1280x1024Data; + break; + case 5: + LCDPtr = SiS_StLCD1024x768Data; + break; + case 6: + LCDPtr = SiS_StLCD1280x1024Data; + break; + case 10: + LCDPtr = SiS_St2LCD1024x768Data; + break; + case 11: + LCDPtr = SiS_St2LCD1280x1024Data; + break; + case 13: + LCDPtr = SiS_NoScaleData; + break; + case 14: + LCDPtr = SiS_LCD1280x960Data; + break; + } + + SiS_RVBHCMAX = (LCDPtr + ResIndex)->RVBHCMAX; + SiS_RVBHCFACT = (LCDPtr + ResIndex)->RVBHCFACT; + SiS_VGAHT = (LCDPtr + ResIndex)->VGAHT; + SiS_VGAVT = (LCDPtr + ResIndex)->VGAVT; + SiS_HT = (LCDPtr + ResIndex)->LCDHT; + SiS_VT = (LCDPtr + ResIndex)->LCDVT; + tempax = 1024; + if (SiS_SetFlag & LCDVESATiming) { + if (SiS_VGAVDE == 350) + tempbx = 560; + else if (SiS_VGAVDE == 400) + tempbx = 640; + else + tempbx = 768; + } else { + if (SiS_VGAVDE == 357) + tempbx = 527; + else if (SiS_VGAVDE == 420) + tempbx = 620; + else if (SiS_VGAVDE == 525) + tempbx = 775; + else if (SiS_VGAVDE == 600) + tempbx = 775; + else if (SiS_VGAVDE == 350) + tempbx = 560; + else if (SiS_VGAVDE == 400) + tempbx = 640; + else + tempbx = 768; + } + if (SiS_LCDResInfo == Panel1280x1024) { + tempax = 1280; + if (SiS_VGAVDE == 360) + tempbx = 768; + else if (SiS_VGAVDE == 375) + tempbx = 800; + else if (SiS_VGAVDE == 405) + tempbx = 864; + else + tempbx = 1024; + } + if (SiS_LCDResInfo == Panel1280x960) { + tempax = 1280; + if (SiS_VGAVDE == 350) + tempbx = 700; + else if (SiS_VGAVDE == 400) + tempbx = 800; + else if (SiS_VGAVDE == 1024) + tempbx = 960; + else + tempbx = 960; + } + if (SiS_LCDInfo & LCDNonExpanding) { + tempax = SiS_VGAHDE; + tempbx = SiS_VGAVDE; + } + SiS_HDE = tempax; + SiS_VDE = tempbx; + return; + } +} + +USHORT +SiS_GetResInfo (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT resindex; + + if (ModeNo <= 0x13) { + resindex = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; /* si+St_ResInfo */ + } else { + resindex = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; /* si+Ext_ResInfo */ + } + return (resindex); +} + +void +SiS_GetCRT2ResInfo (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT xres, yres, modeflag, resindex; + + resindex = SiS_GetResInfo (ROMAddr, ModeNo, ModeIdIndex); + if (ModeNo <= 0x13) { + xres = SiS_StResInfo[resindex].HTotal; + yres = SiS_StResInfo[resindex].VTotal; + } else { + xres = SiS_ModeResInfo[resindex].HTotal; /* xres->ax */ + yres = SiS_ModeResInfo[resindex].VTotal; /* yres->bx */ + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+St_ModeFlag */ + if (modeflag & HalfDCLK) { + xres = xres * 2; + } + if (modeflag & DoubleScanMode) { + yres = yres * 2; + } + } + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_LCDResInfo == Panel1280x1024) { + if (yres == 400) + yres = 405; + if (yres == 350) + yres = 360; + if (SiS_SetFlag & LCDVESATiming) { + if (yres == 360) + yres = 375; + } + } + if (SiS_LCDResInfo == Panel1024x768) { + if (!(SiS_SetFlag & LCDVESATiming)) { + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (yres == 350) + yres = 357; + if (yres == 400) + yres = 420; +/* if(!OldBios) */ + if (yres == 480) + yres = 525; + } + } + } + } else { + if (xres == 720) + xres = 640; + } + SiS_VGAHDE = xres; + SiS_HDE = xres; + SiS_VGAVDE = yres; + SiS_VDE = yres; +} + +void +SiS_GetCRT2Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * CRT2Index, + USHORT * ResIndex) +{ + USHORT tempbx, tempal; + USHORT Flag; + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToLCD) { /* LCD */ + tempbx = SiS_LCDResInfo; + tempbx = tempbx - Panel1024x768; + if (!(SiS_SetFlag & LCDVESATiming)) { + tempbx += 5; +/* GetRevisionID(); */ + tempbx += 5; + } + } else { + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { /* TV */ + if (SiS_VGAVDE > 480) + SiS_SetFlag = + SiS_SetFlag & (!TVSimuMode); + tempbx = 2; + if (SiS_VBInfo & SetInSlaveMode) { + if (!(SiS_SetFlag & TVSimuMode)) + tempbx = 10; + } + } else { + if (SiS_VBInfo & SetPALTV) { + tempbx = 3; + } else { + tempbx = 4; + } + if (SiS_SetFlag & TVSimuMode) { + tempbx = tempbx + 5; + } + } + } + if (ModeNo <= 0x13) { + tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = + SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + tempal = tempal & 0x3F; + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToTV)) { + /*look */ + if (tempal == 0x06) + tempal = 0x07; + + } + /*end 301b */ + if ((0x31 <= ModeNo) && (ModeNo <= 0x35)) + tempal = 6; + if (SiS_LCDInfo & LCDNonExpanding) + tempbx = 0x0D; + if (SiS_LCDResInfo == Panel1280x960) + tempbx = 0x0E; + *CRT2Index = tempbx; + *ResIndex = tempal; + } else { /* LVDS */ + Flag = 1; + tempbx = 0; + if (SiS_IF_DEF_CH7005 == 1) { + if (!(SiS_VBInfo & SetCRT2ToLCD)) { + Flag = 0; + tempbx = 7; + if (SiS_VBInfo & SetPALTV) + tempbx = tempbx + 2; + if (SiS_VBInfo & SetCHTVOverScan) + tempbx = tempbx + 1; + } + } + if (Flag == 1) { + tempbx = SiS_LCDResInfo - Panel800x600; + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = tempbx + 3; + } + } + if (ModeNo <= 0x13) { + tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = + SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + tempal = tempal & 0x1F; + *CRT2Index = tempbx; + *ResIndex = tempal; + } +} + +void +SiS_GetCRT2PtrA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * CRT2Index, + USHORT * ResIndex) +{ + USHORT tempbx, tempal; + + tempbx = SiS_LCDResInfo - Panel1024x768; + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = tempbx + 3; + } + if (ModeNo <= 0x13) { + tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + tempal = tempal & 0x1F; + *CRT2Index = tempbx; + *ResIndex = tempal; +} + +/*end 301b*/ + +USHORT +SiS_GetRatePtrCRT2 (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + SHORT LCDRefreshIndex[] = { 0x00, 0x00, 0x03, 0x01 }; + SHORT LCDARefreshIndex[] = { 0x00, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01 }; + USHORT RefreshRateTableIndex, i; + USHORT modeflag, index, temp; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + if (modeflag & HalfDCLK) + return (0); + } + } + if (ModeNo < 0x14) + return (0xFFFF); + index = SiS_GetReg1 (SiS_P3d4, 0x33); + index = index >> SiS_SelectCRT2Rate; + index = index & 0x0F; + if (SiS_LCDInfo & LCDNonExpanding) + index = 0; + if (index > 0) + index--; + + if (SiS_SetFlag & ProgrammingCRT2) { + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + index = 0; + } + } + if (SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if (SiS_IF_DEF_LVDS == 0) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) temp = + LCDARefreshIndex[SiS_LCDResInfo]; /*301b */ + else + temp = LCDRefreshIndex[SiS_LCDResInfo]; + if (index > temp) { + index = temp; + } + } else { + index = 0; + } + } + } + + RefreshRateTableIndex = SiS_EModeIDTable[ModeIdIndex].REFindex; + ModeNo = SiS_RefIndex[RefreshRateTableIndex].ModeID; + i = 0; + do { + if (SiS_RefIndex[RefreshRateTableIndex + i].ModeID != ModeNo) + break; + temp = SiS_RefIndex[RefreshRateTableIndex + i].Ext_InfoFlag; + temp = temp & ModeInfoFlag; + if (temp < SiS_ModeType) + break; + + i++; + index--; + } while (index != 0xFFFF); + + if (!(SiS_VBInfo & SetCRT2ToRAMDAC)) { + if (SiS_VBInfo & SetInSlaveMode) { + temp = + SiS_RefIndex[RefreshRateTableIndex + i - + 1].Ext_InfoFlag; + if (temp & InterlaceMode) { + i++; + } + } + } + + i--; + if ((SiS_SetFlag & ProgrammingCRT2)) { + temp = + SiS_AjustCRT2Rate (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &i); + } + return (RefreshRateTableIndex + i); /*return(0x01|(temp1<<1)); */ +} + +BOOLEAN +SiS_AjustCRT2Rate (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * i) +{ + USHORT tempax, tempbx, resinfo; + USHORT modeflag, infoflag; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ModeFlag */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + tempbx = SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID; + tempax = 0; + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempax = tempax | SupportRAMDAC2; + } + if (SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /*301b */ + tempax = tempax | SupportLCD; + if (SiS_LCDResInfo != Panel1280x1024) { + if (SiS_LCDResInfo != Panel1280x960) { + if (SiS_LCDInfo & LCDNonExpanding) { + if (resinfo >= 9) { + tempax = 0; + return (0); + } + } + } + } + } + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { /* for HiTV */ + tempax = tempax | SupportHiVisionTV; + if (SiS_VBInfo & SetInSlaveMode) { + if (resinfo == 4) + return (0); + if (resinfo == 3) { + if (SiS_SetFlag & TVSimuMode) + return (0); + } + if (resinfo > 7) + return (0); + } + } else { + if (SiS_VBInfo & + (SetCRT2ToAVIDEO | SetCRT2ToSVIDEO | + SetCRT2ToSCART)) { + tempax = tempax | SupportTV; + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { /*301b */ + + tempax = tempax | SupportTV1024; + + } + /*end 301b */ + + if (!(SiS_VBInfo & SetPALTV)) { + if (modeflag & NoSupportSimuTV) { + if (SiS_VBInfo & SetInSlaveMode) { + if (! + (SiS_VBInfo & + SetNotSimuMode)) { + return 0; + } + } + } + } + } + } + } else { /* for LVDS */ + if (SiS_IF_DEF_CH7005 == 1) { + if (SiS_VBInfo & SetCRT2ToTV) { + tempax = tempax | SupportCHTV; + } + } + if (SiS_VBInfo & SetCRT2ToLCD) { + tempax = tempax | SupportLCD; + if (resinfo > 0x08) + return (0); /*1024x768 */ + if (SiS_LCDResInfo < Panel1024x768) { + if (resinfo > 0x07) + return (0); /*800x600 */ + if (resinfo == 0x04) + return (0); /*512x384 */ + } + } + } + + for (; SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID == tempbx; + (*i)--) { + infoflag = + SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag; + if (infoflag & tempax) { + return (1); + } + if ((*i) == 0) + break; + } + + for ((*i) = 0;; (*i)++) { + infoflag = + SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag; + if (SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID != tempbx) { + return (0); + } + if (infoflag & tempax) { + return (1); + } + } + return (1); +} + +void +SiS_SaveCRT2Info (USHORT ModeNo) +{ + USHORT temp1, temp2; + + SiS_SetReg1 (SiS_P3d4, 0x34, ModeNo); /* reserve CR34 for CRT1 Mode No */ + temp1 = (SiS_VBInfo & SetInSlaveMode) >> 8; + temp2 = ~(SetInSlaveMode >> 8); + SiS_SetRegANDOR (SiS_P3d4, 0x31, temp2, temp1); +} + +void +SiS_GetVBInfo301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT tempax, tempbx, temp; + USHORT modeflag; + UCHAR OutputSelect = *pSiS_OutputSelect; + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + SiS_SetFlag = 0; + + SiS_ModeType = modeflag & ModeInfoFlag; + tempbx = 0; + if (SiS_BridgeIsOn (BaseAddr)) { + temp = SiS_GetReg1 (SiS_P3d4, 0x30); + tempbx = tempbx | temp; + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + tempax = temp << 8; + tempbx = tempbx | tempax; + temp = SetCHTVOverScan | SetInSlaveMode | DisableCRT2Display; /* ynlai */ + temp = 0xFFFF ^ temp; + tempbx = tempbx & temp; +#ifdef CONFIG_FB_SIS_315 + /*301b */ + if ((SiS_VBType & VB_SIS302B)) { + temp = SiS_GetReg1 (SiS_P3d4, 0x38); + if (temp == 0x03) + tempbx = tempbx | (SetCRT2ToLCDA); + } + /*end301b */ +#endif + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_IF_DEF_HiVision) + temp = 0x80FC; + else + temp = 0x807C; + } else { + if (SiS_IF_DEF_CH7005 == 1) { + temp = SetCRT2ToTV | SetCRT2ToLCD; + } else { + temp = SetCRT2ToLCD; + } + } + if (!(tempbx & temp)) { + tempax = tempax | DisableCRT2Display; + tempbx = 0; + } + + if (SiS_IF_DEF_LVDS == 0) { + if (tempbx & SetCRT2ToLCDA) { /*301b */ + tempbx = + tempbx & (0xFF00 | SwitchToCRT2 | + SetSimuScanMode); + } else if (tempbx & SetCRT2ToRAMDAC) { + tempbx = + tempbx & (0xFF00 | SetCRT2ToRAMDAC | + SwitchToCRT2 | SetSimuScanMode); + } else if ((tempbx & SetCRT2ToLCD) && (!(SiS_VBType & VB_NoLCD))) { /*301dlvds */ + tempbx = + tempbx & (0xFF00 | SetCRT2ToLCD | + SwitchToCRT2 | SetSimuScanMode); + } else if (tempbx & SetCRT2ToSCART) { + tempbx = + tempbx & (0xFF00 | SetCRT2ToSCART | + SwitchToCRT2 | SetSimuScanMode); + tempbx = tempbx | SetPALTV; + } else if (tempbx & SetCRT2ToHiVisionTV) { + tempbx = + tempbx & (0xFF00 | SetCRT2ToHiVisionTV | + SwitchToCRT2 | SetSimuScanMode); + /* ynlai begin */ + tempbx = tempbx | SetPALTV; + /* ynlai end */ + } + } else { + if (SiS_IF_DEF_CH7005 == 1) { + if (tempbx & SetCRT2ToTV) + tempbx = + tempbx & (0xFF00 | SetCRT2ToTV | + SwitchToCRT2 | + SetSimuScanMode); + } + if (tempbx & SetCRT2ToLCD) + tempbx = + tempbx & (0xFF00 | SetCRT2ToLCD | + SwitchToCRT2 | SetSimuScanMode); + } + if (tempax & DisableCRT2Display) { + if (!(tempbx & (SwitchToCRT2 | SetSimuScanMode))) { + tempbx = SetSimuScanMode | DisableCRT2Display; + } + } + if (!(tempbx & DriverMode)) { + tempbx = tempbx | SetSimuScanMode; + } + if (!(tempbx & SetSimuScanMode)) { + if (tempbx & SwitchToCRT2) { + if (!(modeflag & CRT2Mode)) { + tempbx = tempbx | SetSimuScanMode; + } + } else { + if (! + (SiS_BridgeIsEnable + (BaseAddr, HwDeviceExtension))) { + if (!(tempbx & DriverMode)) { + if (SiS_BridgeInSlave ()) { + tempbx = + tempbx | + SetInSlaveMode; + } + } + } + } + } + if (!(tempbx & DisableCRT2Display)) { + if (tempbx & DriverMode) { + if (tempbx & SetSimuScanMode) { + if (!(modeflag & CRT2Mode)) { + tempbx = + tempbx | SetInSlaveMode; + if (SiS_IF_DEF_LVDS == 0) { + if (tempbx & + SetCRT2ToTV) { + if (! + (tempbx & + SetNotSimuMode)) + SiS_SetFlag = + SiS_SetFlag + | + TVSimuMode; + } + } + } + } + } else { + tempbx = tempbx | SetInSlaveMode; + if (SiS_IF_DEF_LVDS == 0) { + if (tempbx & SetCRT2ToTV) { + if (!(tempbx & SetNotSimuMode)) + SiS_SetFlag = + SiS_SetFlag | + TVSimuMode; + } + } + } + } + if (SiS_IF_DEF_CH7005 == 1) { + temp = SiS_GetReg1 (SiS_P3d4, 0x35); + if (temp & TVOverScan) + tempbx = tempbx | SetCHTVOverScan; + } + } +#ifdef CONFIG_FB_SIS_300 + /*add PALMN */ + if (SiS_IF_DEF_LVDS == 0) { + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + if (!(OutputSelect & EnablePALMN)) + SiS_SetRegAND (SiS_P3d4, 0x35, 0x3F); + if (tempbx & SetCRT2ToTV) { + if (tempbx & SetPALTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x35); + temp = temp & 0xC0; + if (temp == 0x40) + tempbx = tempbx & (~SetPALTV); + } + } + } + } + /*end add */ +#endif +#ifdef CONFIG_FB_SIS_315 + /*add PALMN */ + if (SiS_IF_DEF_LVDS == 0) { + if (!(OutputSelect & EnablePALMN)) + SiS_SetRegAND (SiS_P3d4, 0x38, 0x3F); + if (tempbx & SetCRT2ToTV) { + if (tempbx & SetPALTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x38); + temp = temp & 0xC0; + if (temp == 0x40) + tempbx = tempbx & (~SetPALTV); + } + } + } + /*end add */ +#endif + SiS_VBInfo = tempbx; +} + +void +SiS_GetRAMDAC2DATA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT tempax, tempbx, temp; + USHORT temp1, temp2, modeflag = 0, tempcx; + + USHORT StandTableIndex, CRT1Index; + USHORT ResInfo, DisplayType; + SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr = NULL; + + SiS_RVBHCMAX = 1; + SiS_RVBHCFACT = 1; + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + StandTableIndex = SiS_GetModePtr (ROMAddr, ModeNo, ModeIdIndex); + tempax = SiS_StandTable[StandTableIndex].CRTC[0]; + tempbx = SiS_StandTable[StandTableIndex].CRTC[6]; + temp1 = SiS_StandTable[StandTableIndex].CRTC[7]; + } else { + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + /*add crt1ptr */ + temp = + SiS_GetLVDSCRT1Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &ResInfo, + &DisplayType); + if (temp == 0) { + return; + } + switch (DisplayType) { + case 0: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1; + break; + case 1: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1; + break; + case 2: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1; + break; + case 3: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H; + break; + case 4: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H; + break; + case 5: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H; + break; + case 6: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2; + break; + case 7: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2; + break; + case 8: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2; + break; + case 9: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H; + break; + case 10: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H; + break; + case 11: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H; + break; + case 12: + LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC; + break; + case 13: + LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC; + break; + case 14: + LVDSCRT1Ptr = SiS_CHTVCRT1UPAL; + break; + case 15: + LVDSCRT1Ptr = SiS_CHTVCRT1OPAL; + break; + } + temp1 = (LVDSCRT1Ptr + ResInfo)->CR[0]; + temp2 = (LVDSCRT1Ptr + ResInfo)->CR[14]; + tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8); + tempbx = (LVDSCRT1Ptr + ResInfo)->CR[6]; + tempcx = (LVDSCRT1Ptr + ResInfo)->CR[13] << 8; + tempcx = tempcx & 0x0100; + tempcx = tempcx << 2; + tempbx = tempbx | tempcx; + temp1 = (LVDSCRT1Ptr + ResInfo)->CR[7]; + } /*add 301b */ + else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + CRT1Index = + SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + CRT1Index = CRT1Index & 0x3F; + temp1 = (USHORT) SiS_CRT1Table[CRT1Index].CR[0]; + temp2 = (USHORT) SiS_CRT1Table[CRT1Index].CR[14]; + tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8); + tempbx = (USHORT) SiS_CRT1Table[CRT1Index].CR[6]; + tempcx = (USHORT) SiS_CRT1Table[CRT1Index].CR[13] << 8; + tempcx = tempcx & 0x0100; + tempcx = tempcx << 2; + tempbx = tempbx | tempcx; + temp1 = (USHORT) SiS_CRT1Table[CRT1Index].CR[7]; + } + } + if (temp1 & 0x01) + tempbx = tempbx | 0x0100; + if (temp1 & 0x20) + tempbx = tempbx | 0x0200; + tempax = tempax + 5; + if (modeflag & Charx8Dot) + tempax = tempax * 8; + else + tempax = tempax * 9; + + SiS_VGAHT = tempax; + SiS_HT = tempax; + tempbx++; + SiS_VGAVT = tempbx; + SiS_VT = tempbx; +} + +void +SiS_UnLockCRT2 (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr) +{ + if (HwDeviceExtension->jChipType >= SIS_315H) { + SiS_SetRegANDOR (SiS_Part1Port, 0x2f, 0xFF, 0x01); + } else { + SiS_SetRegANDOR (SiS_Part1Port, 0x24, 0xFF, 0x01); + } +} + +void +SiS_LockCRT2 (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr) +{ + if (HwDeviceExtension->jChipType >= SIS_315H) { + SiS_SetRegANDOR (SiS_Part1Port, 0x2F, 0xFE, 0x00); + } else { + SiS_SetRegANDOR (SiS_Part1Port, 0x24, 0xFE, 0x00); + } +} + +void +SiS_EnableCRT2 () +{ + SiS_SetRegANDOR (SiS_P3c4, 0x1E, 0xFF, 0x20); +} + +void +SiS_DisableBridge (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr) +{ + + USHORT temp1, tempah, temp; + SiS_SetRegANDOR (SiS_P3c4, 0x11, 0xF7, 0x08); +/*SetPanelDelay(1); */ + temp1 = 0x01; + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { /*301b */ + if ((SiS_IsVAMode (BaseAddr))) + temp1 = 0x00; /*no disable vb */ + } + + if (SiS_IF_DEF_LVDS == 0) { + if (!temp1) { /*301b */ + SiS_SetRegANDOR (SiS_Part2Port, 0x00, 0x0DF, 0x00); /* disable VB */ + SiS_DisplayOff (); + if (HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */ + SiS_SetRegOR (SiS_Part1Port, 0x00, 0x80); /* alan,BScreenOff */ + } + SiS_SetRegANDOR (SiS_P3c4, 0x32, 0xDF, 0x00); + + temp = SiS_GetReg1 (SiS_Part1Port, 0); + SiS_SetRegOR (SiS_Part1Port, 0x00, 0x10); /* alan,BScreenOff */ +/* + if(HwDeviceExtension->jChipType >= SIS_315H) + { + SiS_SetRegAND(SiS_Part1Port,0x2E,0x7F); + } + */ + SiS_SetRegANDOR (SiS_P3c4, 0x1E, 0xDF, 0x00); + SiS_SetReg1 (SiS_Part1Port, 0, temp); + } else { + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { /*301b */ + if (!(SiS_Is301B (BaseAddr))) { + SiS_SetRegAND (SiS_P3c4, 0x32, 0xDF); + if ((!(SiS_IsDualEdge (BaseAddr))) + && (!(SiS_IsVAMode (BaseAddr)))) + tempah = 0x7F; + else if ((!(SiS_IsDualEdge (BaseAddr))) + && (SiS_IsVAMode (BaseAddr))) + tempah = 0xBF; + else + tempah = 0x3F; + SiS_SetRegAND (SiS_Part4Port, 0x1F, + tempah); + } + } + } + } else { + if (SiS_IF_DEF_CH7005) { + SiS_SetCH7005 (0x090E); + } + SiS_DisplayOff (); + SiS_SetRegANDOR (SiS_P3c4, 0x32, 0xDF, 0x00); + SiS_SetRegANDOR (SiS_P3c4, 0x1E, 0xDF, 0x00); + SiS_UnLockCRT2 (HwDeviceExtension, BaseAddr); + SiS_SetRegANDOR (SiS_Part1Port, 0x01, 0xFF, 0x80); + SiS_SetRegANDOR (SiS_Part1Port, 0x02, 0xFF, 0x40); + } +/*SetPanelDelay(0); */ + SiS_SetRegANDOR (SiS_P3c4, 0x11, 0xFB, 0x04); +} + +void +SiS_EnableBridge (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr) +{ + USHORT temp, tempah; + + SiS_SetRegANDOR (SiS_P3c4, 0x11, 0xFB, 0x00); +/*SetPanelDelay(0); */ + if (SiS_IF_DEF_LVDS == 0) { + if ((!(SiS_IsVAMode (BaseAddr))) + && ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + SiS_SetRegANDOR (SiS_Part2Port, 0x00, 0x1F, 0x20); + } else { + temp = SiS_GetReg1 (SiS_P3c4, 0x32); + temp = temp & 0xDF; + if (SiS_BridgeInSlave ()) { + tempah = SiS_GetReg1 (SiS_P3d4, 0x30); + if (!(tempah & SetCRT2ToRAMDAC)) { + temp = temp | 0x20; + } + } + SiS_SetReg1 (SiS_P3c4, 0x32, temp); + SiS_SetRegANDOR (SiS_P3c4, 0x1E, 0xFF, 0x20); + if (HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */ + temp = SiS_GetReg1 (SiS_Part1Port, 0x2E); + if (!(temp & 0x80)) + SiS_SetRegOR (SiS_Part1Port, 0x2E, 0x80); /* by alan,BVBDOENABLE=1 */ + + } + SiS_SetRegANDOR (SiS_Part2Port, 0x00, 0x1F, 0x20); + + if (HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */ + temp = SiS_GetReg1 (SiS_Part1Port, 0x2E); + if (!(temp & 0x80)) + SiS_SetRegOR (SiS_Part1Port, 0x2E, 0x80); /* by alan,BVBDOENABLE=1 */ + } + + SiS_SetRegANDOR (SiS_Part2Port, 0x00, 0x1F, 0x20); + SiS_VBLongWait (); + SiS_DisplayOn (); + SiS_VBLongWait (); + } + /*add301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (!(SiS_Is301B (BaseAddr))) { + temp = SiS_GetReg1 (SiS_Part1Port, 0x2E); + if (!(temp & 0x80)) + SiS_SetRegOR (SiS_Part1Port, 0x2E, + 0x80); + if ((!(SiS_IsDualEdge (BaseAddr))) + && (!(SiS_IsVAMode (BaseAddr)))) + tempah = 0x80; + else if ((!(SiS_IsDualEdge (BaseAddr))) + && (SiS_IsVAMode (BaseAddr))) + tempah = 0x40; + else + tempah = 0xC0; + SiS_SetRegOR (SiS_Part4Port, 0x1F, tempah); + } + } + /*end 301b */ + } else { + /*LVDS*/ SiS_EnableCRT2 (); + SiS_DisplayOn (); + SiS_UnLockCRT2 (HwDeviceExtension, BaseAddr); + SiS_SetRegANDOR (SiS_Part1Port, 0x02, 0xBF, 0x00); + if (SiS_BridgeInSlave ()) { + SiS_SetRegANDOR (SiS_Part1Port, 0x01, 0x1F, 0x00); + } else { + SiS_SetRegANDOR (SiS_Part1Port, 0x01, 0x1F, 0x40); + } + if (SiS_IF_DEF_CH7005) { + SiS_SetCH7005 (0x0B0E); + } + } +/*SetPanelDelay(1); */ + SiS_SetRegANDOR (SiS_P3c4, 0x11, 0xF7, 0x00); +} + +void +SiS_SetPanelDelay (USHORT DelayTime) +{ + USHORT PanelID; + + PanelID = SiS_GetReg1 (SiS_P3d4, 0x36); + PanelID = PanelID >> 4; + + if (DelayTime == 0) + SiS_LCD_Wait_Time (SiS_PanelDelayTbl[PanelID].timer[0]); + else + SiS_LCD_Wait_Time (SiS_PanelDelayTbl[PanelID].timer[1]); +} + +void +SiS_LCD_Wait_Time (UCHAR DelayTime) +{ + USHORT i, j; + ULONG temp, flag; + + flag = 0; + for (i = 0; i < DelayTime; i++) { + for (j = 0; j < 66; j++) { + temp = SiS_GetReg3 (0x61); + temp = temp & 0x10; + if (temp == flag) + continue; + flag = temp; + } + } +} + +/*301b*/ + +BOOLEAN +SiS_Is301B (USHORT BaseAddr) +{ + USHORT flag; + flag = SiS_GetReg1 (SiS_Part4Port, 0x01); + if (flag > (0x0B0)) + return (0); /*301b */ + else + return (1); +} + +BOOLEAN +SiS_IsDualEdge (USHORT BaseAddr) +{ +#ifdef CONFIG_FB_SIS_315 + USHORT flag; + flag = SiS_GetReg1 (SiS_P3d4, 0x38); + if (flag & EnableDualEdge) + return (0); + else + return (1); +#endif + return (1); +} + +BOOLEAN +SiS_IsVAMode (USHORT BaseAddr) +{ + USHORT flag; + flag = SiS_GetReg1 (SiS_P3d4, 0x38); +#ifdef CONFIG_FB_SIS_315 + if ((flag & EnableDualEdge) && (flag & SetToLCDA)) + return (0); + else + return (1); +#endif + return (1); +} + +BOOLEAN +SiS_IsDisableCRT2 (USHORT BaseAddr) +{ + USHORT flag; + flag = SiS_GetReg1 (SiS_P3d4, 0x30); + if (flag & 0x20) + return (0); /*301b */ + else + return (1); +} + +/*end 301b*/ + +BOOLEAN +SiS_BridgeIsOn (USHORT BaseAddr) +{ + USHORT flag; + + if (SiS_IF_DEF_LVDS == 1) { + return (1); + } else { + flag = SiS_GetReg1 (SiS_Part4Port, 0x00); + if ((flag == 1) || (flag == 2)) + return (1); /*301b */ + else + return (0); + } +} + +BOOLEAN +SiS_BridgeIsEnable (USHORT BaseAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT flag; + + if (SiS_BridgeIsOn (BaseAddr) == 0) { + flag = SiS_GetReg1 (SiS_Part1Port, 0x0); + if (HwDeviceExtension->jChipType < SIS_315H) { /* 300 series */ + if (flag & 0x0a0) { + return 1; + } else { + return 0; + } + } else { /* 310 series */ + + if (flag & 0x050) { + return 1; + } else { + return 0; + } + + } + } + return 0; +} + +BOOLEAN +SiS_BridgeInSlave () +{ + USHORT flag1; + + flag1 = SiS_GetReg1 (SiS_P3d4, 0x31); + if (flag1 & (SetInSlaveMode >> 8)) { + return 1; + } else { + return 0; + } +} + +BOOLEAN +SiS_GetLCDResInfo301 (ULONG ROMAddr, USHORT SiS_P3d4, USHORT ModeNo, + USHORT ModeIdIndex) +{ + USHORT temp, modeflag, resinfo = 0; + + SiS_LCDResInfo = 0; + SiS_LCDTypeInfo = 0; + SiS_LCDInfo = 0; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ModeFlag */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; /*si+Ext_ResInfo */ + } + + if (!(SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) { + return 0; + } + if (!(SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2))) { + return 0; + } + temp = SiS_GetReg1 (SiS_P3d4, 0x36); + SiS_LCDTypeInfo = temp >> 4; + SiS_LCDResInfo = temp & 0x0F; + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_LCDResInfo < Panel1024x768) + SiS_LCDResInfo = Panel1024x768; + } else { + if (SiS_LCDResInfo < Panel800x600) + SiS_LCDResInfo = Panel800x600; + } + if (SiS_LCDResInfo > Panel640x480) + SiS_LCDResInfo = Panel1024x768; + + temp = SiS_GetReg1 (SiS_P3d4, 0x37); + SiS_LCDInfo = temp; + + if (SiS_IF_DEF_LVDS == 1) { + if (modeflag & HalfDCLK) { + if (SiS_IF_DEF_TRUMPION == 0) { + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (ModeNo > 0x13) { + if (SiS_LCDResInfo == + Panel1024x768) { + if (resinfo == 4) { /* 512x384 */ + SiS_SetFlag = + SiS_SetFlag + | + EnableLVDSDDA; + } + } else { + if (SiS_LCDResInfo == + Panel800x600) { + if (resinfo == 3) { /*400x300 */ + SiS_SetFlag + = + SiS_SetFlag + | + EnableLVDSDDA; + } + } + } + } + } else { + SiS_SetFlag = + SiS_SetFlag | EnableLVDSDDA; + } + } else { + SiS_SetFlag = SiS_SetFlag | EnableLVDSDDA; + } + } + } + + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_VBInfo & SetNotSimuMode) { + SiS_SetFlag = SiS_SetFlag | LCDVESATiming; + } + } else { + SiS_SetFlag = SiS_SetFlag | LCDVESATiming; + } + return 1; +} + +void +SiS_PresetScratchregister (USHORT SiS_P3d4, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + /*SiS_SetReg1(SiS_P3d4,0x30,0x21); */ + /*SiS_SetReg1(SiS_P3d4,0x31,0x41); */ + /*SiS_SetReg1(SiS_P3d4,0x32,0x28); */ + /*SiS_SetReg1(SiS_P3d4,0x33,0x22); */ + /*SiS_SetReg1(SiS_P3d4,0x35,0x43); */ + /*SiS_SetReg1(SiS_P3d4,0x36,0x01); */ + /*SiS_SetReg1(SiS_P3d4,0x37,0x00); */ +} + +void +SiS_LongWait () +{ + USHORT i; + + i = SiS_GetReg1 (SiS_P3c4, 0x1F); + if (!(i & 0xC0)) { + + for (i = 0; i < 0xFFFF; i++) { + if (!(SiS_GetReg2 (SiS_P3da) & 0x08)) + break; + } + for (i = 0; i < 0xFFFF; i++) { + if ((SiS_GetReg2 (SiS_P3da) & 0x08)) + break; + } + } +} + +void +SiS_VBLongWait () +{ + USHORT tempal, temp, i, j; + + if (!(SiS_VBInfo & SetCRT2ToTV)) { + temp = 0; + for (i = 0; i < 3; i++) { + for (j = 0; j < 100; j++) { + tempal = SiS_GetReg2 (SiS_P3da); + if (temp & 0x01) { /* VBWaitMode2 */ + if ((tempal & 0x08)) { + continue; + } + if (!(tempal & 0x08)) { + break; + } + } else { /* VBWaitMode1 */ + if (!(tempal & 0x08)) { + continue; + } + if ((tempal & 0x08)) { + break; + } + } + } + temp = temp ^ 0x01; + } + } else { + SiS_LongWait (); + } + return; +} + +BOOLEAN +SiS_WaitVBRetrace (USHORT BaseAddr) +{ + USHORT temp; + + return 0; + + temp = SiS_GetReg1 (SiS_Part1Port, 0x00); + if (!(temp & 0x80)) { + return 0; + } + + for (temp = 0; temp == 0;) { + temp = SiS_GetReg1 (SiS_Part1Port, 0x25); + temp = temp & 0x01; + } + for (; temp > 0;) { + temp = SiS_GetReg1 (SiS_Part1Port, 0x25); + temp = temp & 0x01; + } + return 1; +} + +void +SiS_SetRegANDOR (USHORT Port, USHORT Index, USHORT DataAND, USHORT DataOR) +{ + USHORT temp; + + temp = SiS_GetReg1 (Port, Index); /* SiS_Part1Port index 02 */ + temp = (temp & (DataAND)) | DataOR; + SiS_SetReg1 (Port, Index, temp); +} + +void +SiS_SetRegAND (USHORT Port, USHORT Index, USHORT DataAND) +{ + USHORT temp; + + temp = SiS_GetReg1 (Port, Index); /* SiS_Part1Port index 02 */ + temp = temp & DataAND; + SiS_SetReg1 (Port, Index, temp); +} + +void +SiS_SetRegOR (USHORT Port, USHORT Index, USHORT DataOR) +{ + USHORT temp; + + temp = SiS_GetReg1 (Port, Index); /* SiS_Part1Port index 02 */ + temp = temp | DataOR; + SiS_SetReg1 (Port, Index, temp); +} + +void +SiS_SetGroup2 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT i, j, tempax, tempbx, tempcx, temp, temp3; + USHORT push1, push2, temp1; + UCHAR *PhasePoint; + UCHAR *TimingPoint; + USHORT modeflag, resinfo, crt2crtc, resindex, xres; + ULONG longtemp, tempeax, tempebx, temp2, tempecx; + USHORT SiS_RY1COE = 0, SiS_RY2COE = 0, SiS_RY3COE = 0, SiS_RY4COE = + 0, SiS_RY5COE = 0, SiS_RY6COE = 0, SiS_RY7COE = 0; + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + crt2crtc = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + crt2crtc = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + tempcx = SiS_VBInfo; + tempax = (tempcx & 0x00FF) << 8; + tempbx = (tempcx & 0x00FF) | ((tempcx & 0x00FF) << 8); + tempbx = tempbx & 0x0410; + temp = (tempax & 0x0800) >> 8; + temp = temp >> 1; + temp = temp | (((tempbx & 0xFF00) >> 8) << 1); + temp = temp | ((tempbx & 0x00FF) >> 3); + temp = temp ^ 0x0C; + + PhasePoint = SiS_PALPhase; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { /* PALPhase */ + temp = temp ^ 0x01; + if (SiS_VBInfo & SetInSlaveMode) { + TimingPoint = SiS_HiTVSt2Timing; + if (SiS_SetFlag & TVSimuMode) { + if (modeflag & Charx8Dot) + TimingPoint = SiS_HiTVSt1Timing; + else + TimingPoint = SiS_HiTVTextTiming; + } + } else + TimingPoint = SiS_HiTVExtTiming; + } else { + if (SiS_VBInfo & SetPALTV) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) PhasePoint = SiS_PALPhase2; /* PALPhase */ + else + PhasePoint = SiS_PALPhase; + + TimingPoint = SiS_PALTiming; + } else { + temp = temp | 0x10; + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) PhasePoint = SiS_NTSCPhase2; /* PALPhase */ + else + PhasePoint = SiS_NTSCPhase; + + TimingPoint = SiS_NTSCTiming; + } + } + SiS_SetReg1 (SiS_Part2Port, 0x0, temp); + +#ifdef CONFIG_FB_SIS_300 + /*add PALMN */ + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x35); + temp1 = temp1 & 0x40; + if (temp1) + PhasePoint = SiS_PALMPhase; + temp1 = SiS_GetReg1 (SiS_P3d4, 0x35); + temp1 = temp1 & 0x80; + if (temp1) + PhasePoint = SiS_PALNPhase; + } + } + } +/*end add*/ +#endif +#ifdef CONFIG_FB_SIS_315 + /*add PALMN */ + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x38); + temp1 = temp1 & 0x40; + if (temp1) + PhasePoint = SiS_PALMPhase; + temp1 = SiS_GetReg1 (SiS_P3d4, 0x38); + temp1 = temp1 & 0x80; + if (temp1) + PhasePoint = SiS_PALNPhase; + } + } + /*end add */ +#endif + for (i = 0x31, j = 0; i <= 0x34; i++, j++) { + SiS_SetReg1 (SiS_Part2Port, i, PhasePoint[j]); + } + for (i = 0x01, j = 0; i <= 0x2D; i++, j++) { + SiS_SetReg1 (SiS_Part2Port, i, TimingPoint[j]); + } + for (i = 0x39; i <= 0x45; i++, j++) { + SiS_SetReg1 (SiS_Part2Port, i, TimingPoint[j]); /* di->temp2[j] */ + } + if (SiS_VBInfo & SetCRT2ToTV) { + SiS_SetRegANDOR (SiS_Part2Port, 0x3A, 0x1F, 0x00); + } + temp = SiS_NewFlickerMode; + SiS_SetRegANDOR (SiS_Part2Port, 0x0A, 0xFF, temp); + + SiS_SetReg1 (SiS_Part2Port, 0x35, 0x00); /*301b */ + SiS_SetReg1 (SiS_Part2Port, 0x36, 0x00); + SiS_SetReg1 (SiS_Part2Port, 0x37, 0x00); + SiS_SetReg1 (SiS_Part2Port, 0x38, SiS_RY1COE); + SiS_SetReg1 (SiS_Part2Port, 0x48, SiS_RY2COE); + SiS_SetReg1 (SiS_Part2Port, 0x49, SiS_RY3COE); + SiS_SetReg1 (SiS_Part2Port, 0x4a, SiS_RY4COE); +/*add to change 630+301b filter*/ + + resindex = SiS_GetResInfo (ROMAddr, ModeNo, ModeIdIndex); + if (ModeNo <= 0x13) { + xres = SiS_StResInfo[resindex].HTotal; + } else { + xres = SiS_ModeResInfo[resindex].HTotal; /* xres->ax */ + } + if (xres == 640) { + SiS_RY1COE = 0xFF; + SiS_RY2COE = 0x03; + SiS_RY3COE = 0x02; + SiS_RY4COE = 0xF6; + SiS_RY5COE = 0xFC; + SiS_RY6COE = 0x27; + SiS_RY7COE = 0x46; + } + if (xres == 800) { + SiS_RY1COE = 0x01; + SiS_RY2COE = 0x01; + SiS_RY3COE = 0xFC; + SiS_RY4COE = 0xF8; + SiS_RY5COE = 0x08; + SiS_RY6COE = 0x26; + SiS_RY7COE = 0x38; + } + if (xres == 1024) { + SiS_RY1COE = 0xFF; + SiS_RY2COE = 0xFF; + SiS_RY3COE = 0xFC; + SiS_RY4COE = 0x00; + SiS_RY5COE = 0x0F; + SiS_RY6COE = 0x22; + SiS_RY7COE = 0x28; + } + if (xres == 720) { + SiS_RY1COE = 0x01; + SiS_RY2COE = 0x02; + SiS_RY3COE = 0xFE; + SiS_RY4COE = 0xF7; + SiS_RY5COE = 0x03; + SiS_RY6COE = 0x27; + SiS_RY7COE = 0x3c; + } + SiS_SetReg1 (SiS_Part2Port, 0x35, SiS_RY1COE); /*301b */ + SiS_SetReg1 (SiS_Part2Port, 0x36, SiS_RY2COE); + SiS_SetReg1 (SiS_Part2Port, 0x37, SiS_RY3COE); + SiS_SetReg1 (SiS_Part2Port, 0x38, SiS_RY4COE); + SiS_SetReg1 (SiS_Part2Port, 0x48, SiS_RY5COE); + SiS_SetReg1 (SiS_Part2Port, 0x49, SiS_RY6COE); + SiS_SetReg1 (SiS_Part2Port, 0x4a, SiS_RY7COE); + +/*end add*/ + + if (SiS_VBInfo & SetCRT2ToHiVisionTV) + tempax = 950; + else { + if (SiS_VBInfo & SetPALTV) + tempax = 520; + else + tempax = 440; + } + if (SiS_VDE <= tempax) { + tempax = tempax - SiS_VDE; + tempax = tempax >> 2; + tempax = (tempax & 0x00FF) | ((tempax & 0x00FF) << 8); + push1 = tempax; + temp = (tempax & 0xFF00) >> 8; + temp = temp + (USHORT) TimingPoint[0]; + SiS_SetReg1 (SiS_Part2Port, 0x01, temp); + tempax = push1; + temp = (tempax & 0xFF00) >> 8; + temp = temp + TimingPoint[1]; + SiS_SetReg1 (SiS_Part2Port, 0x02, temp); + } + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToTV) && (SiS_VGAHDE == 1024)) { + if (SiS_VBInfo & SetPALTV) { + SiS_SetReg1 (SiS_Part2Port, 0x01, 0x19); + SiS_SetReg1 (SiS_Part2Port, 0x02, 0x52); + } else { + SiS_SetReg1 (SiS_Part2Port, 0x01, 0x0B); + SiS_SetReg1 (SiS_Part2Port, 0x02, 0x11); + } + } + + tempcx = SiS_HT - 1; + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + tempcx = tempcx - 1; + } + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x1B, temp); + temp = (tempcx & 0xFF00) >> 8; + SiS_SetRegANDOR (SiS_Part2Port, 0x1D, ~0x0F, temp); + + tempcx = SiS_HT >> 1; + push1 = tempcx; /* push cx */ + tempcx = tempcx + 7; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + tempcx = tempcx - 4; + } + temp = (tempcx & 0x00FF); + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x22, 0x0F, temp); + + tempbx = TimingPoint[j] | ((TimingPoint[j + 1]) << 8); + tempbx = tempbx + tempcx; + push2 = tempbx; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x24, temp); + temp = (tempbx & 0xFF00) >> 8; + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x25, 0x0F, temp); + + tempbx = push2; + tempbx = tempbx + 8; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + tempbx = tempbx - 4; + tempcx = tempbx; + } + temp = (tempbx & 0x00FF) << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x29, 0x0F, temp); + + j = j + 2; + tempcx = tempcx + (TimingPoint[j] | ((TimingPoint[j + 1]) << 8)); + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x27, temp); + temp = ((tempcx & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x28, 0x0F, temp); + + tempcx = tempcx + 8; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + tempcx = tempcx - 4; + } + temp = tempcx & 0xFF; + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x2A, 0x0F, temp); + + tempcx = push1; /* pop cx */ + j = j + 2; + temp = TimingPoint[j] | ((TimingPoint[j + 1]) << 8); + tempcx = tempcx - temp; + temp = tempcx & 0x00FF; + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x2D, 0x0F, temp); + + tempcx = tempcx - 11; + if (!(SiS_VBInfo & SetCRT2ToTV)) { + tempax = SiS_GetVGAHT2 (); + tempcx = tempax - 1; + } + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x2E, temp); + + tempbx = SiS_VDE; + if (SiS_VGAVDE == 360) + tempbx = 746; + if (SiS_VGAVDE == 375) + tempbx = 746; + if (SiS_VGAVDE == 405) + tempbx = 853; + if (SiS_VBInfo & SetCRT2ToTV) { + tempbx = tempbx >> 1; + } + tempbx = tempbx - 2; + temp = tempbx & 0x00FF; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (SiS_VBInfo & SetInSlaveMode) { + if (ModeNo == 0x2f) + temp = temp + 1; + } + } + SiS_SetReg1 (SiS_Part2Port, 0x2F, temp); + + temp = (tempcx & 0xFF00) >> 8; + temp = temp | (((tempbx & 0xFF00) >> 8) << 6); + if (!(SiS_VBInfo & SetCRT2ToHiVisionTV)) { + temp = temp | 0x10; + if (!(SiS_VBInfo & SetCRT2ToSVIDEO)) { + temp = temp | 0x20; + } + } + SiS_SetReg1 (SiS_Part2Port, 0x30, temp); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { /*tv gatingno */ + tempbx = SiS_VDE; + if (SiS_VBInfo & SetCRT2ToTV) { + tempbx = tempbx >> 1; + } + temp = (((tempbx - 3) & 0x0300) >> 8) << 5; + SiS_SetReg1 (SiS_Part2Port, 0x46, temp); + temp = (tempbx - 3) & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x47, temp); + } +/*end 301b*/ + + tempbx = tempbx & 0x00FF; + if (!(modeflag & HalfDCLK)) { + tempcx = SiS_VGAHDE; + if (tempcx >= SiS_HDE) { + tempbx = tempbx | 0x2000; + tempax = tempax & 0x00FF; + } + } + tempcx = 0x0101; + + if (SiS_VBInfo & (SetCRT2ToHiVisionTV | SetCRT2ToTV)) { /*301b */ + if (SiS_VGAHDE >= 1024) { + tempcx = 0x1920; + if (SiS_VGAHDE >= 1280) { + tempcx = 0x1420; + tempbx = tempbx & 0xDFFF; + } + } + } + if (!(tempbx & 0x2000)) { + if (modeflag & HalfDCLK) { + tempcx = (tempcx & 0xFF00) | ((tempcx & 0x00FF) << 1); + } + push1 = tempbx; + tempeax = SiS_VGAHDE; + tempebx = (tempcx & 0xFF00) >> 8; + longtemp = tempeax * tempebx; + tempecx = tempcx & 0x00FF; + longtemp = longtemp / tempecx; + /*301b */ + tempecx = 8 * 1024; + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + tempecx = tempecx * 8; + } + longtemp = longtemp * tempecx; + tempecx = SiS_HDE; + temp2 = longtemp % tempecx; + tempeax = longtemp / tempecx; + if (temp2 != 0) { + tempeax = tempeax + 1; + } + tempax = (USHORT) tempeax; + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + tempcx = ((tempax & 0xFF00) >> 5) >> 8; + } + /*end 301b */ + tempbx = push1; + tempbx = + (USHORT) (((tempeax & 0x0000FF00) & 0x1F00) | + (tempbx & 0x00FF)); + tempax = + (USHORT) (((tempeax & 0x000000FF) << 8) | + (tempax & 0x00FF)); + temp = (tempax & 0xFF00) >> 8; + } else { + temp = (tempax & 0x00FF) >> 8; + } + SiS_SetReg1 (SiS_Part2Port, 0x44, temp); + temp = (tempbx & 0xFF00) >> 8; + SiS_SetRegANDOR (SiS_Part2Port, 0x45, ~0x03F, temp); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + if ((tempcx & 0x00FF) == 0x01) + tempcx = 0x00; + SiS_SetRegANDOR (SiS_Part2Port, 0x46, ~0x007, tempcx); + SiS_SetRegOR (SiS_Part2Port, 0x46, 0x18); + if (SiS_VBInfo & SetPALTV) { + tempbx = 0x0364; + tempcx = 0x009c; + } else { + tempbx = 0x0346; + tempcx = 0x0078; + } + temp = (tempbx & 0x00FF); + SiS_SetReg1 (SiS_Part2Port, 0x4B, temp); + temp = (tempcx & 0x00FF); + SiS_SetReg1 (SiS_Part2Port, 0x4C, temp); + tempbx = (tempbx & 0x0300); + temp = (tempcx & 0xFF00) >> 8; + temp = (temp & 0x0003) << 2; + temp = temp | (tempbx >> 8); + SiS_SetReg1 (SiS_Part2Port, 0x4D, temp); + temp = SiS_GetReg1 (SiS_Part2Port, 0x43); + SiS_SetReg1 (SiS_Part2Port, 0x43, temp - 3); + } +/*end 301b*/ + +#ifdef CONFIG_FB_SIS_300 +/*add PALMN*/ + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x35); + temp1 = temp1 & 0x40; + if (temp1) { + SiS_SetRegANDOR (SiS_Part2Port, 0x00, + 0xEF, 0x00); + temp3 = + SiS_GetReg1 (SiS_Part2Port, 0x01); + temp3 = temp3 - 1; + SiS_SetReg1 (SiS_Part2Port, 0x01, + temp3); + } + } + } + } + /*end add */ +#endif + +#ifdef CONFIG_FB_SIS_315 +/*add PALMN*/ + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x38); + temp1 = temp1 & 0x40; + if (temp1) { + SiS_SetRegANDOR (SiS_Part2Port, 0x00, 0xEF, + 0x00); + temp3 = SiS_GetReg1 (SiS_Part2Port, 0x01); + temp3 = temp3 - 1; + SiS_SetReg1 (SiS_Part2Port, 0x01, temp3); + } + } + } + /*end add */ +#endif + + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + if (!(SiS_VBInfo & SetInSlaveMode)) { + SiS_SetReg1 (SiS_Part2Port, 0x0B, 0x00); + } + } + if (SiS_VBInfo & SetCRT2ToTV) { + return; + } + + tempbx = SiS_HDE - 1; /* RHACTE=HDE-1 */ + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x2C, temp); + temp = (tempbx & 0xFF00) >> 8; + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x2B, 0x0F, temp); + temp = 0x01; + if (SiS_LCDResInfo == Panel1280x1024) { + if (SiS_ModeType == ModeEGA) { + if (SiS_VGAHDE >= 1024) { + temp = 0x02; + if (SiS_SetFlag & LCDVESATiming) + temp = 0x01; + } + } + } + SiS_SetReg1 (SiS_Part2Port, 0x0B, temp); + + tempbx = SiS_VDE; /* RTVACTEO=(VDE-1)&0xFF */ + push1 = tempbx; + tempbx--; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part2Port, 0x03, temp); + temp = ((tempbx & 0xFF00) >> 8) & 0x07; + SiS_SetRegANDOR (SiS_Part2Port, 0x0C, ~0x07, temp); + + tempcx = SiS_VT - 1; + push2 = tempcx + 1; + temp = tempcx & 0x00FF; /* RVTVT=VT-1 */ + SiS_SetReg1 (SiS_Part2Port, 0x19, temp); + temp = (tempcx & 0xFF00) >> 8; + temp = temp << 5; + if (SiS_LCDInfo & LCDRGB18Bit) { + temp = temp | 0x10; + } + if (SiS_VBInfo & SetCRT2ToLCD) { + tempbx = (tempbx & 0xFF00) | (SiS_LCDInfo & 0x0FF); + if (tempbx & LCDSync) { + tempbx = tempbx & LCDSyncBit; + tempbx = + (tempbx & 0xFF00) | ((tempbx & 0x00FF) >> + LCDSyncShift); + temp = temp | (tempbx & 0x00FF); + } + } + SiS_SetReg1 (SiS_Part2Port, 0x1A, temp); + + tempcx++; + tempbx = 768; + if (SiS_LCDResInfo != Panel1024x768) { + tempbx = 1024; + if (SiS_LCDResInfo != Panel1280x1024) { + tempbx = 1200; /*301b */ + if (SiS_LCDResInfo != Panel1600x1200) { + if (tempbx != SiS_VDE) { + tempbx = 960; + } + } + } + } + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = SiS_VDE; + tempbx--; + tempcx--; + } + tempax = 1; + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (tempbx != SiS_VDE) { + tempax = tempbx; + if (tempax < SiS_VDE) { + tempax = 0; + tempcx = 0; + } else { + tempax = tempax - SiS_VDE; + } + tempax = tempax >> 1; + } + tempcx = tempcx - tempax; /* lcdvdes */ + tempbx = tempbx - tempax; /* lcdvdee */ + } else { + tempax = tempax >> 1; + tempcx = tempcx - tempax; /* lcdvdes */ + tempbx = tempbx - tempax; /* lcdvdee */ + } + + temp = tempcx & 0x00FF; /* RVEQ1EQ=lcdvdes */ + SiS_SetReg1 (SiS_Part2Port, 0x05, temp); + temp = tempbx & 0x00FF; /* RVEQ2EQ=lcdvdee */ + SiS_SetReg1 (SiS_Part2Port, 0x06, temp); + + temp = (tempbx & 0xFF00) >> 8; + temp = temp << 3; + temp = temp | ((tempcx & 0xFF00) >> 8); + SiS_SetReg1 (SiS_Part2Port, 0x02, temp); + + tempbx = push2; + tempax = push1; + tempcx = tempbx; + tempcx = tempcx - tempax; + tempcx = tempcx >> 4; + tempbx = tempbx + tempax; + tempbx = tempbx >> 1; + if (SiS_LCDInfo & LCDNonExpanding) { + tempbx = tempbx - 10; + } + temp = tempbx & 0x00FF; /* RTVACTEE=lcdvrs */ + SiS_SetReg1 (SiS_Part2Port, 0x04, temp); + + temp = (tempbx & 0xFF00) >> 8; + temp = temp << 4; + tempbx = tempbx + tempcx + 1; + temp = temp | (tempbx & 0x000F); + SiS_SetReg1 (SiS_Part2Port, 0x01, temp); + + if (SiS_LCDResInfo == Panel1024x768) { + if (!(SiS_SetFlag & LCDVESATiming)) { + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (ModeNo == 0x13) { + SiS_SetReg1 (SiS_Part2Port, 0x04, 0xB9); + SiS_SetReg1 (SiS_Part2Port, 0x05, 0xCC); + SiS_SetReg1 (SiS_Part2Port, 0x06, 0xA6); + } else { + temp = crt2crtc & 0x3F; + if (temp == 4) { + SiS_SetReg1 (SiS_Part2Port, + 0x01, 0x2B); + SiS_SetReg1 (SiS_Part2Port, + 0x02, 0x13); + SiS_SetReg1 (SiS_Part2Port, + 0x04, 0xE5); + SiS_SetReg1 (SiS_Part2Port, + 0x05, 0x08); + SiS_SetReg1 (SiS_Part2Port, + 0x06, 0xE2); + } + } + } + } + } + + SiS_SetRegANDOR (SiS_Part2Port, 0x09, 0xF0, 0x00); + SiS_SetRegANDOR (SiS_Part2Port, 0x0A, 0xF0, 0x00); + + tempcx = (SiS_HT - SiS_HDE) >> 2; /* (HT-HDE)>>2 */ + tempbx = (SiS_HDE + 7); /* lcdhdee */ + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + tempbx = tempbx + 2; + } + push1 = tempbx; + temp = tempbx & 0x00FF; /* RHEQPLE=lcdhdee */ + SiS_SetReg1 (SiS_Part2Port, 0x23, temp); + temp = (tempbx & 0xFF00) >> 8; + SiS_SetRegANDOR (SiS_Part2Port, 0x25, ~0x0F, temp); + /*301b */ + temp = 7; + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + temp = temp + 2; + } + SiS_SetReg1 (SiS_Part2Port, 0x1F, temp); /* RHBLKE=lcdhdes */ + SiS_SetRegANDOR (SiS_Part2Port, 0x20, 0x0F, 0x00); + + tempbx = tempbx + tempcx; + push2 = tempbx; + temp = tempbx & 0xFF; /* RHBURSTS=lcdhrs */ + if (SiS_LCDResInfo == Panel1280x1024) { + if (!(SiS_LCDInfo & LCDNonExpanding)) { + if (SiS_HDE == 1280) { + temp = 0x47; + } + } + } + SiS_SetReg1 (SiS_Part2Port, 0x1C, temp); + temp = (tempbx & 0xFF00) >> 8; + temp = temp << 4; + SiS_SetRegANDOR (SiS_Part2Port, 0x1D, ~0x0F0, temp); + + tempbx = push2; + tempcx = tempcx << 1; + tempbx = tempbx + tempcx; + temp = tempbx & 0x00FF; /* RHSYEXP2S=lcdhre */ + SiS_SetReg1 (SiS_Part2Port, 0x21, temp); + + SiS_SetRegANDOR (SiS_Part2Port, 0x17, 0xFB, 0x00); + SiS_SetRegANDOR (SiS_Part2Port, 0x18, 0xDF, 0x00); + + if (!(SiS_SetFlag & LCDVESATiming)) { + if (SiS_VGAVDE == 525) { + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { /*301b */ + temp = 0xC6; + } else + temp = 0xC4; + SiS_SetReg1 (SiS_Part2Port, 0x2f, temp); + SiS_SetReg1 (SiS_Part2Port, 0x30, 0xB3); + } + if (SiS_VGAVDE == 420) { + if ( + ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B))) { + temp = 0x4F; + } else + temp = 0x4E; + SiS_SetReg1 (SiS_Part2Port, 0x2f, temp); + } + } +} + +USHORT +SiS_GetVGAHT2 () +{ + ULONG tempax, tempbx; + + tempbx = ((SiS_VGAVT - SiS_VGAVDE) * SiS_RVBHCMAX) & 0xFFFF; + tempax = (SiS_VT - SiS_VDE) * SiS_RVBHCFACT; + tempax = (tempax * SiS_HT) / tempbx; + return ((USHORT) tempax); +} + +void +SiS_SetGroup3 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT i; + UCHAR *tempdi; + USHORT modeflag, temp, temp1; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + + SiS_SetReg1 (SiS_Part3Port, 0x00, 0x00); + if (SiS_VBInfo & SetPALTV) { + SiS_SetReg1 (SiS_Part3Port, 0x13, 0xFA); + SiS_SetReg1 (SiS_Part3Port, 0x14, 0xC8); + } else { + SiS_SetReg1 (SiS_Part3Port, 0x13, 0xF6); + SiS_SetReg1 (SiS_Part3Port, 0x14, 0xBF); + } +#ifdef CONFIG_FB_SIS_300 + /*add PALMN */ + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x35); + temp1 = temp1 & 0x40; + if (temp1) { + SiS_SetReg1 (SiS_Part3Port, 0x13, 0xFA); + SiS_SetReg1 (SiS_Part3Port, 0x14, 0xC8); + SiS_SetReg1 (SiS_Part3Port, 0x3D, 0xA8); + } + } + } + } + /*end add */ +#endif +#ifdef CONFIG_FB_SIS_315 +/*add PALMN*/ + if (SiS_VBInfo & SetCRT2ToTV) { + temp = SiS_GetReg1 (SiS_P3d4, 0x31); + temp = temp & 0x01; + if (temp) { + temp1 = SiS_GetReg1 (SiS_P3d4, 0x38); + temp1 = temp1 & 0x40; + if (temp1) { + SiS_SetReg1 (SiS_Part3Port, 0x13, 0xFA); + SiS_SetReg1 (SiS_Part3Port, 0x14, 0xC8); + SiS_SetReg1 (SiS_Part3Port, 0x3D, 0xA8); + } + } + } + /*end add */ +#endif + if (SiS_VBInfo & SetCRT2ToHiVisionTV) { + tempdi = SiS_HiTVGroup3Data; + if (SiS_SetFlag & TVSimuMode) { + tempdi = SiS_HiTVGroup3Simu; + if (!(modeflag & Charx8Dot)) { + tempdi = SiS_HiTVGroup3Text; + } + } + for (i = 0; i <= 0x3E; i++) { + SiS_SetReg1 (SiS_Part3Port, i, tempdi[i]); + } + } + return; +} + +void +SiS_SetGroup4 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT tempax, tempcx, tempbx, modeflag, temp, temp2, push1; + ULONG tempebx, tempeax, templong; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + temp = SiS_RVBHCFACT; + SiS_SetReg1 (SiS_Part4Port, 0x13, temp); + + tempbx = SiS_RVBHCMAX; + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part4Port, 0x14, temp); + temp2 = ((tempbx & 0xFF00) >> 8) << 7; + + tempcx = SiS_VGAHT - 1; + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part4Port, 0x16, temp); + temp = ((tempcx & 0xFF00) >> 8) << 3; + temp2 = temp | temp2; + + tempcx = SiS_VGAVT - 1; + if (!(SiS_VBInfo & SetCRT2ToTV)) { + tempcx = tempcx - 5; + } + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part4Port, 0x17, temp); + temp = temp2 | ((tempcx & 0xFF00) >> 8); + SiS_SetReg1 (SiS_Part4Port, 0x15, temp); + + tempcx = SiS_VBInfo; + tempbx = SiS_VGAHDE; + if (modeflag & HalfDCLK) { + tempbx = tempbx >> 1; + } + if (tempcx & SetCRT2ToHiVisionTV) { + temp = 0xA0; + if (tempbx != 1024) { + temp = 0xC0; + if (tempbx != 1280) + temp = 0; + } + } else if ((tempcx & SetCRT2ToTV) && (SiS_VGAHDE == 1024)) { /*301b */ + temp = 0xA0; + } else { + temp = 0x80; + if (SiS_VBInfo & SetCRT2ToLCD) { + temp = 0; + if (tempbx > 800) + temp = 0x60; + } + } + if (SiS_LCDResInfo != Panel1280x1024) + temp = temp | 0x0A; + SiS_SetRegANDOR (SiS_Part4Port, 0x0E, ~0xEF, temp); + + tempebx = SiS_VDE; + if (tempcx & SetCRT2ToHiVisionTV) { + /* if(!(tempax&0xE000)) tempbx=tempbx>>1; */ + if (!(temp & 0xE000)) + tempbx = tempbx >> 1; /* alan ???? */ + + } + + tempcx = SiS_RVBHRS; + temp = tempcx & 0x00FF; + SiS_SetReg1 (SiS_Part4Port, 0x18, temp); + + tempebx = tempebx; + tempeax = SiS_VGAVDE; + tempcx = tempcx | 0x04000; +/*tempeax=tempeax-tempebx; */ + if (tempeax <= tempebx) { + tempcx = ((tempcx & 0xFF00) ^ 0x4000) | (tempcx & 0x00ff); + tempeax = SiS_VGAVDE; + } + + else { + tempeax = tempeax - tempebx; + } + + push1 = tempcx; + templong = (tempeax * 256 * 1024) % tempebx; + tempeax = (tempeax * 256 * 1024) / tempebx; + tempebx = tempeax; + if (templong != 0) { + tempebx++; + } + tempcx = push1; + temp = (USHORT) (tempebx & 0x000000FF); + SiS_SetReg1 (SiS_Part4Port, 0x1B, temp); + temp = (USHORT) ((tempebx & 0x0000FF00) >> 8); + SiS_SetReg1 (SiS_Part4Port, 0x1A, temp); + tempbx = (USHORT) (tempebx >> 16); + temp = tempbx & 0x00FF; + temp = temp << 4; + temp = temp | ((tempcx & 0xFF00) >> 8); + SiS_SetReg1 (SiS_Part4Port, 0x19, temp); + /*301b */ + + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + temp = 0x0028; + SiS_SetReg1 (SiS_Part4Port, 0x1C, temp); + tempax = SiS_VGAHDE; + if (modeflag & HalfDCLK) { + tempax = tempax >> 1; + } + if (SiS_VBInfo & (SetCRT2ToLCD)) { + if (tempax > 800) + tempax = tempax - 800; + } + tempax = tempax - 1; + + if (SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToHiVisionTV)) { + if (SiS_VGAHDE > 800) { + if (SiS_VGAHDE == 1024) + tempax = (tempax * 25 / 32) - 1; + else + tempax = (tempax * 20 / 32) - 1; + } + } + temp = (tempax & 0xFF00) >> 8; + temp = ((temp & 0x0003) << 4); + SiS_SetReg1 (SiS_Part4Port, 0x1E, temp); + temp = (tempax & 0x00FF); + SiS_SetReg1 (SiS_Part4Port, 0x1D, temp); + + if (SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToHiVisionTV)) { + if (SiS_VGAHDE > 800) { + SiS_SetRegOR (SiS_Part4Port, 0x1E, 0x08); + } + } + temp = 0x0036; + if (SiS_VBInfo & SetCRT2ToTV) { + temp = temp | 0x0001; + } + SiS_SetRegANDOR (SiS_Part4Port, 0x1F, 0x00C0, temp); + tempbx = (SiS_HT / 2) - 2; + temp = ((tempbx & 0x0700) >> 8) << 3; + SiS_SetRegANDOR (SiS_Part4Port, 0x21, 0x00C0, temp); + temp = tempbx & 0x00FF; + SiS_SetReg1 (SiS_Part4Port, 0x22, temp); + } +/*end 301b*/ + SiS_SetCRT2VCLK (BaseAddr, ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); +} + +void +SiS_SetCRT2VCLK (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT vclkindex; + USHORT tempah, temp1; + + vclkindex = + SiS_GetVCLK2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B))) { + tempah = SiS_VBVCLKData[vclkindex].Part4_A; + SiS_SetReg1 (SiS_Part4Port, 0x0A, tempah); + tempah = SiS_VBVCLKData[vclkindex].Part4_B; + SiS_SetReg1 (SiS_Part4Port, 0x0B, tempah); + } else { + SiS_SetReg1 (SiS_Part4Port, 0x0A, 0x01); + tempah = SiS_VBVCLKData[vclkindex].Part4_B; + SiS_SetReg1 (SiS_Part4Port, 0x0B, tempah); + tempah = SiS_VBVCLKData[vclkindex].Part4_A; + SiS_SetReg1 (SiS_Part4Port, 0x0A, tempah); + + } + SiS_SetReg1 (SiS_Part4Port, 0x12, 0x00); + tempah = 0x08; + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + tempah = tempah | 0x020; + } + temp1 = SiS_GetReg1 (SiS_Part4Port, 0x12); + tempah = tempah | temp1; + SiS_SetReg1 (SiS_Part4Port, 0x12, tempah); +} + +USHORT +SiS_GetVCLK2Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT tempbx; +#ifdef CONFIG_FB_SIS_300 + USHORT LCDXlat1VCLK[4] = { VCLK65, VCLK65, VCLK65, VCLK65 }; + USHORT LCDXlat2VCLK[4] = { VCLK108_2, VCLK108_2, VCLK108_2, VCLK108_2 }; + USHORT LVDSXlat2VCLK[4] = { VCLK65, VCLK65, VCLK65, VCLK65 }; + USHORT LVDSXlat3VCLK[4] = { VCLK65, VCLK65, VCLK65, VCLK65 }; +#else /* SIS315H */ + USHORT LCDXlat1VCLK[4] = + { VCLK65 + 2, VCLK65 + 2, VCLK65 + 2, VCLK65 + 2 }; + USHORT LCDXlat2VCLK[4] = + { VCLK108_2 + 5, VCLK108_2 + 5, VCLK108_2 + 5, VCLK108_2 + 5 }; + USHORT LVDSXlat2VCLK[4] = + { VCLK65 + 2, VCLK65 + 2, VCLK65 + 2, VCLK65 + 2 }; + USHORT LVDSXlat3VCLK[4] = + { VCLK65 + 2, VCLK65 + 2, VCLK65 + 2, VCLK65 + 2 }; +#endif + USHORT LVDSXlat1VCLK[4] = { VCLK40, VCLK40, VCLK40, VCLK40 }; + USHORT CRT2Index, VCLKIndex; + USHORT modeflag, resinfo; + UCHAR *CHTVVCLKPtr = NULL; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + CRT2Index = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + CRT2Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + + if (SiS_IF_DEF_LVDS == 0) { + CRT2Index = CRT2Index >> 6; /* for LCD */ + if ((SiS_VBInfo & SetCRT2ToLCD) || (SiS_VBInfo & SetCRT2ToLCDA)) { /*301b */ + if (SiS_LCDResInfo != Panel1024x768) { + VCLKIndex = LCDXlat2VCLK[CRT2Index]; + } else { + VCLKIndex = LCDXlat1VCLK[CRT2Index]; + } + } else { /* for TV */ + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_IF_DEF_HiVision == 1) { + if (SiS_SetFlag & RPLLDIV2XO) { + VCLKIndex = HiTVVCLKDIV2; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } else { + VCLKIndex = HiTVVCLK; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } + if (SiS_SetFlag & TVSimuMode) { + if (modeflag & Charx8Dot) { + VCLKIndex = + HiTVSimuVCLK; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } else { + VCLKIndex = + HiTVTextVCLK; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } + } + } else { + if (SiS_VBInfo & SetCRT2ToTV) { + if (SiS_SetFlag & RPLLDIV2XO) { + VCLKIndex = TVVCLKDIV2; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } else { + VCLKIndex = TVVCLK; + if (HwDeviceExtension-> + jChipType >= SIS_315H) { /* 310 series */ +/* VCLKIndex += 11; for chip310 0x2E */ + VCLKIndex += 25; /* for chip315 */ + } + } + } + } + } else { /* for CRT2 */ + VCLKIndex = + (UCHAR) SiS_GetReg2 ((USHORT) (SiS_P3ca + 0x02)); /* Port 3cch */ + VCLKIndex = ((VCLKIndex >> 2) & 0x03); + if (ModeNo > 0x13) { + VCLKIndex = + SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; /* di+Ext_CRTVCLK */ + VCLKIndex = VCLKIndex & 0x3f; + } + } + } + } else { /* LVDS */ + if (ModeNo <= 0x13) + VCLKIndex = CRT2Index; + else + VCLKIndex = CRT2Index; + if (SiS_IF_DEF_CH7005 == 1) { + if (!(SiS_VBInfo & SetCRT2ToLCD)) { + VCLKIndex = VCLKIndex & 0x1f; + tempbx = 0; + if (SiS_VBInfo & SetPALTV) + tempbx = tempbx + 2; + if (SiS_VBInfo & SetCHTVOverScan) + tempbx = tempbx + 1; + switch (tempbx) { + case 0: + CHTVVCLKPtr = SiS_CHTVVCLKUNTSC; + break; + case 1: + CHTVVCLKPtr = SiS_CHTVVCLKONTSC; + break; + case 2: + CHTVVCLKPtr = SiS_CHTVVCLKUPAL; + break; + case 3: + CHTVVCLKPtr = SiS_CHTVVCLKOPAL; + break; + } + VCLKIndex = CHTVVCLKPtr[VCLKIndex]; + } + } else { + VCLKIndex = VCLKIndex >> 6; + if (SiS_LCDResInfo == Panel800x600) + VCLKIndex = LVDSXlat1VCLK[VCLKIndex]; + else if (SiS_LCDResInfo == Panel1024x768) + VCLKIndex = LVDSXlat2VCLK[VCLKIndex]; + else + VCLKIndex = LVDSXlat3VCLK[VCLKIndex]; + } + } +/*VCLKIndex=VCLKIndex&0x3F; */ + if (HwDeviceExtension->jChipType < SIS_315H) { /* for300 serial */ + VCLKIndex = VCLKIndex & 0x3F; + } + return (VCLKIndex); +} + +void +SiS_SetGroup5 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex) +{ + USHORT Pindex, Pdata; + + Pindex = SiS_Part5Port; + Pdata = SiS_Part5Port + 1; + if (SiS_ModeType == ModeVGA) { + if (! + (SiS_VBInfo & + (SetInSlaveMode | LoadDACFlag | CRT2DisplayFlag))) { + SiS_EnableCRT2 (); +/* LoadDAC2(ROMAddr,SiS_Part5Port,ModeNo,ModeIdIndex); */ + } + } + return; +} + +void +SiS_LoadDAC2 (ULONG ROMAddr, USHORT SiS_Part5Port, USHORT ModeNo, + USHORT ModeIdIndex) +{ + USHORT data, data2; + USHORT time, i, j, k; + USHORT m, n, o; + USHORT si, di, bx, dl; + USHORT al, ah, dh; + USHORT *table = 0; + USHORT Pindex, Pdata, modeflag; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + + Pindex = SiS_Part5Port; + Pdata = SiS_Part5Port + 1; + data = modeflag & DACInfoFlag; + time = 64; + if (data == 0x00) + table = SiS_MDA_DAC; + if (data == 0x08) + table = SiS_CGA_DAC; + if (data == 0x10) + table = SiS_EGA_DAC; + if (data == 0x18) { + time = 256; + table = SiS_VGA_DAC; + } + if (time == 256) + j = 16; + else + j = time; + + SiS_SetReg3 (Pindex, 0x00); + + for (i = 0; i < j; i++) { + data = table[i]; + for (k = 0; k < 3; k++) { + data2 = 0; + if (data & 0x01) + data2 = 0x2A; + if (data & 0x02) + data2 = data2 + 0x15; + SiS_SetReg3 (Pdata, data2); + data = data >> 2; + } + } + + if (time == 256) { + for (i = 16; i < 32; i++) { + data = table[i]; + for (k = 0; k < 3; k++) + SiS_SetReg3 (Pdata, data); + } + si = 32; + for (m = 0; m < 9; m++) { + di = si; + bx = si + 0x04; + dl = 0; + for (n = 0; n < 3; n++) { + for (o = 0; o < 5; o++) { + dh = table[si]; + ah = table[di]; + al = table[bx]; + si++; + SiS_WriteDAC2 (Pdata, dl, ah, al, dh); + } /* for 5 */ + si = si - 2; + for (o = 0; o < 3; o++) { + dh = table[bx]; + ah = table[di]; + al = table[si]; + si--; + SiS_WriteDAC2 (Pdata, dl, ah, al, dh); + } /* for 3 */ + dl++; + } /* for 3 */ + si = si + 5; + } /* for 9 */ + } +} + +void +SiS_WriteDAC2 (USHORT Pdata, USHORT dl, USHORT ah, USHORT al, USHORT dh) +{ + USHORT temp; + USHORT bh, bl; + + bh = ah; + bl = al; + if (dl != 0) { + temp = bh; + bh = dh; + dh = temp; + if (dl == 1) { + temp = bl; + bl = dh; + dh = temp; + } else { + temp = bl; + bl = bh; + bh = temp; + } + } + SiS_SetReg3 (Pdata, (USHORT) dh); + SiS_SetReg3 (Pdata, (USHORT) bh); + SiS_SetReg3 (Pdata, (USHORT) bl); +} + +void +SiS_SetCHTVReg (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT temp, tempbx, tempcl; +/* USHORT CRT2CRTC; */ + USHORT TVType, resindex; + SiS_CHTVRegDataStruct *CHTVRegData = NULL; + + if (ModeNo <= 0x13) { + tempcl = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + tempcl = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + TVType = 0; + if (SiS_VBInfo & SetPALTV) + TVType = TVType + 2; + if (SiS_VBInfo & SetCHTVOverScan) + TVType = TVType + 1; + switch (TVType) { + case 0: + CHTVRegData = SiS_CHTVReg_UNTSC; + break; + case 1: + CHTVRegData = SiS_CHTVReg_ONTSC; + break; + case 2: + CHTVRegData = SiS_CHTVReg_UPAL; + break; + case 3: + CHTVRegData = SiS_CHTVReg_OPAL; + break; + } + resindex = tempcl & 0x3F; + + if (SiS_VBInfo & SetPALTV) { + SiS_SetCH7005 (0x4304); + SiS_SetCH7005 (0x6909); + } else { + SiS_SetCH7005 (0x0304); + SiS_SetCH7005 (0x7109); + } + + temp = CHTVRegData[resindex].Reg[0]; + tempbx = ((temp & 0x00FF) << 8) | 0x00; + SiS_SetCH7005 (tempbx); + temp = CHTVRegData[resindex].Reg[1]; + tempbx = ((temp & 0x00FF) << 8) | 0x07; + SiS_SetCH7005 (tempbx); + temp = CHTVRegData[resindex].Reg[2]; + tempbx = ((temp & 0x00FF) << 8) | 0x08; + SiS_SetCH7005 (tempbx); + temp = CHTVRegData[resindex].Reg[3]; + tempbx = ((temp & 0x00FF) << 8) | 0x0A; + SiS_SetCH7005 (tempbx); + temp = CHTVRegData[resindex].Reg[4]; + tempbx = ((temp & 0x00FF) << 8) | 0x0B; + SiS_SetCH7005 (tempbx); + + SiS_SetCH7005 (0x2801); + SiS_SetCH7005 (0x3103); + SiS_SetCH7005 (0x003D); + SiS_SetCHTVRegANDOR (0x0010, 0x1F); + SiS_SetCHTVRegANDOR (0x0211, 0xF8); + SiS_SetCHTVRegANDOR (0x001C, 0xEF); + + if (!(SiS_VBInfo & SetPALTV)) { + /* tempcl=CRT2CRTC; */ + tempcl = tempcl & 0x3F; + if (SiS_VBInfo & SetCHTVOverScan) { + if (tempcl == 0x04) { /* 640x480 underscan */ + SiS_SetCHTVRegANDOR (0x0020, 0xEF); + SiS_SetCHTVRegANDOR (0x0121, 0xFE); + } else { + if (tempcl == 0x05) { /* 800x600 underscan */ + SiS_SetCHTVRegANDOR (0x0118, 0xF0); + SiS_SetCHTVRegANDOR (0x0C19, 0xF0); + SiS_SetCHTVRegANDOR (0x001A, 0xF0); + SiS_SetCHTVRegANDOR (0x001B, 0xF0); + SiS_SetCHTVRegANDOR (0x001C, 0xF0); + SiS_SetCHTVRegANDOR (0x001D, 0xF0); + SiS_SetCHTVRegANDOR (0x001E, 0xF0); + SiS_SetCHTVRegANDOR (0x001F, 0xF0); + SiS_SetCHTVRegANDOR (0x0120, 0xEF); + SiS_SetCHTVRegANDOR (0x0021, 0xFE); + } + } + } else { + if (tempcl == 0x04) { /* 640x480 overscan */ + SiS_SetCHTVRegANDOR (0x0020, 0xEF); + SiS_SetCHTVRegANDOR (0x0121, 0xFE); + } else { + if (tempcl == 0x05) { /* 800x600 overscan */ + SiS_SetCHTVRegANDOR (0x0118, 0xF0); + SiS_SetCHTVRegANDOR (0x0F19, 0xF0); + SiS_SetCHTVRegANDOR (0x011A, 0xF0); + SiS_SetCHTVRegANDOR (0x0C1B, 0xF0); + SiS_SetCHTVRegANDOR (0x071C, 0xF0); + SiS_SetCHTVRegANDOR (0x011D, 0xF0); + SiS_SetCHTVRegANDOR (0x0C1E, 0xF0); + SiS_SetCHTVRegANDOR (0x071F, 0xF0); + SiS_SetCHTVRegANDOR (0x0120, 0xEF); + SiS_SetCHTVRegANDOR (0x0021, 0xFE); + } + } + } + } +} + +void +SiS_SetCHTVRegANDOR (USHORT tempax, USHORT tempbh) +{ + USHORT tempal, tempah, tempbl; + + tempal = tempax & 0x00FF; + tempah = (tempax >> 8) & 0x00FF; + tempbl = SiS_GetCH7005 (tempal); + tempbl = (((tempbl & tempbh) | tempah) << 8 | tempal); + SiS_SetCH7005 (tempbl); +} + +void +SiS_SetCH7005 (USHORT tempbx) +{ + USHORT tempah, temp; + + SiS_DDC_Port = 0x3c4; + SiS_DDC_Index = 0x11; + SiS_DDC_DataShift = 0x00; + SiS_DDC_DeviceAddr = 0xEA; + + temp = 1; + for (; temp != 0;) { + SiS_SetSwitchDDC2 (); + SiS_SetStart (); + tempah = SiS_DDC_DeviceAddr; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + tempah = tempbx & 0x00FF; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + tempah = (tempbx & 0xFF00) >> 8; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + SiS_SetStop (); + } +} + +USHORT +SiS_GetCH7005 (USHORT tempbx) +{ + USHORT tempah, temp; + + SiS_DDC_Port = 0x3c4; + SiS_DDC_Index = 0x11; + SiS_DDC_DataShift = 0x00; + SiS_DDC_DeviceAddr = 0xEA; + SiS_DDC_ReadAddr = tempbx; + + for (;;) { + SiS_SetSwitchDDC2 (); + SiS_SetStart (); + tempah = SiS_DDC_DeviceAddr; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + tempah = SiS_DDC_ReadAddr; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + + SiS_SetStart (); + tempah = SiS_DDC_DeviceAddr; + tempah = tempah | 0x01; + temp = SiS_WriteDDC2Data (tempah); + if (temp) + continue; + tempah = SiS_ReadDDC2Data (tempah); + SiS_SetStop (); + return (tempah); + } +} + +void +SiS_SetSwitchDDC2 (void) +{ + USHORT i; + + SiS_SetSCLKHigh (); + for (i = 0; i < 1000; i++) { + SiS_GetReg1 (SiS_DDC_Port, 0x05); + } + SiS_SetSCLKLow (); + for (i = 0; i < 1000; i++) { + SiS_GetReg1 (SiS_DDC_Port, 0x05); + } +} + +void +SiS_SetStart (void) +{ + + SiS_SetSCLKLow (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x02); /* SetSDA(0x01); */ + SiS_SetSCLKHigh (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x00); /* SetSDA(0x00); */ + SiS_SetSCLKHigh (); +} + +void +SiS_SetStop (void) +{ + SiS_SetSCLKLow (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x00); /* SetSDA(0x00); */ + SiS_SetSCLKHigh (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x02); /* SetSDA(0x01); */ + SiS_SetSCLKHigh (); +} + +USHORT +SiS_WriteDDC2Data (USHORT tempax) +{ + USHORT i, flag, temp; + + flag = 0x80; + for (i = 0; i < 8; i++) { + SiS_SetSCLKLow (); + if (tempax & flag) { + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, + 0x02); + } else { + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, + 0x00); + } + SiS_SetSCLKHigh (); + flag = flag >> 1; + } + temp = SiS_CheckACK (); + return (temp); +} + +USHORT +SiS_ReadDDC2Data (USHORT tempax) +{ + USHORT i, temp, getdata; + + getdata = 0; + for (i = 0; i < 8; i++) { + getdata = getdata << 1; + SiS_SetSCLKLow (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x02); + SiS_SetSCLKHigh (); + temp = SiS_GetReg1 (SiS_DDC_Port, SiS_DDC_Index); + if (temp & 0x02) + getdata = getdata | 0x01; + } + return (getdata); +} + +void +SiS_SetSCLKLow (void) +{ + USHORT temp; + + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFE, 0x00); /* SetSCLKLow() */ + do { + temp = SiS_GetReg1 (SiS_DDC_Port, SiS_DDC_Index); + } while (temp & 0x01); + SiS_DDC2Delay (); +} + +void +SiS_SetSCLKHigh (void) +{ + USHORT temp; + + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFE, 0x01); /* SetSCLKHigh() */ + do { + temp = SiS_GetReg1 (SiS_DDC_Port, SiS_DDC_Index); + } while (!(temp & 0x01)); + SiS_DDC2Delay (); +} + +void +SiS_DDC2Delay (void) +{ + USHORT i; + + for (i = 0; i < DDC2DelayTime; i++) { + SiS_GetReg1 (SiS_P3c4, 0x05); + } +} + +USHORT +SiS_CheckACK (void) +{ + USHORT tempah; + + SiS_SetSCLKLow (); + SiS_SetRegANDOR (SiS_DDC_Port, SiS_DDC_Index, 0xFD, 0x02); + SiS_SetSCLKHigh (); + tempah = SiS_GetReg1 (SiS_DDC_Port, SiS_DDC_Index); + SiS_SetSCLKLow (); + if (tempah & 0x02) + return (1); + else + return (0); +} + +void +SiS_ModCRT1CRTC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT temp, tempah, i, modeflag, j; + USHORT ResInfo, DisplayType; + SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr = NULL; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + + temp = + SiS_GetLVDSCRT1Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &ResInfo, &DisplayType); + if (temp == 0) { + return; + } + + switch (DisplayType) { + case 0: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1; + break; + case 1: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1; + break; + case 2: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1; + break; + case 3: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H; + break; + case 4: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H; + break; + case 5: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H; + break; + case 6: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2; + break; + case 7: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2; + break; + case 8: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2; + break; + case 9: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H; + break; + case 10: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H; + break; + case 11: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H; + break; + case 12: + LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC; + break; + case 13: + LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC; + break; + case 14: + LVDSCRT1Ptr = SiS_CHTVCRT1UPAL; + break; + case 15: + LVDSCRT1Ptr = SiS_CHTVCRT1OPAL; + break; + } + + tempah = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x11); /*unlock cr0-7 */ + tempah = tempah & 0x7F; + SiS_SetReg1 (SiS_P3d4, 0x11, tempah); + tempah = (LVDSCRT1Ptr + ResInfo)->CR[0]; + SiS_SetReg1 (SiS_P3d4, 0x0, tempah); + for (i = 0x02, j = 1; i <= 0x05; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x06, j = 5; i <= 0x07; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x10, j = 7; i <= 0x11; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x15, j = 9; i <= 0x16; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + + for (i = 0x0A, j = 11; i <= 0x0C; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3c4, i, tempah); + } + + tempah = (LVDSCRT1Ptr + ResInfo)->CR[14]; + tempah = tempah & 0x0E0; + SiS_SetReg1 (SiS_P3c4, 0x0E, tempah); + + tempah = (LVDSCRT1Ptr + ResInfo)->CR[14]; + tempah = tempah & 0x01; + tempah = tempah << 5; + if (modeflag & DoubleScanMode) { + tempah = tempah | 0x080; + } + SiS_SetRegANDOR (SiS_P3d4, 0x09, ~0x020, tempah); + return; +} + +/*301b*/ +void +SiS_CHACRT1CRTC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex) +{ + USHORT temp, tempah, i, modeflag, j; + USHORT ResInfo, DisplayType; + SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr = NULL; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + } + + temp = + SiS_GetLVDSCRT1Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, &ResInfo, &DisplayType); + if (temp == 0) { + return; + } + + switch (DisplayType) { + case 0: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1; + break; + case 1: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1; + break; + case 2: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1; + break; + case 3: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H; + break; + case 4: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H; + break; + case 5: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H; + break; + case 6: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2; + break; + case 7: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2; + break; + case 8: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2; + break; + case 9: + LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H; + break; + case 10: + LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H; + break; + case 11: + LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H; + break; + case 12: + LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC; + break; + case 13: + LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC; + break; + case 14: + LVDSCRT1Ptr = SiS_CHTVCRT1UPAL; + break; + case 15: + LVDSCRT1Ptr = SiS_CHTVCRT1OPAL; + break; + } + + tempah = (UCHAR) SiS_GetReg1 (SiS_P3d4, 0x11); /*unlock cr0-7 */ + tempah = tempah & 0x7F; + SiS_SetReg1 (SiS_P3d4, 0x11, tempah); + tempah = (LVDSCRT1Ptr + ResInfo)->CR[0]; + SiS_SetReg1 (SiS_P3d4, 0x0, tempah); + for (i = 0x02, j = 1; i <= 0x05; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x06, j = 5; i <= 0x07; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x10, j = 7; i <= 0x11; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + for (i = 0x15, j = 9; i <= 0x16; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3d4, i, tempah); + } + + for (i = 0x0A, j = 11; i <= 0x0C; i++, j++) { + tempah = (LVDSCRT1Ptr + ResInfo)->CR[j]; + SiS_SetReg1 (SiS_P3c4, i, tempah); + } + + tempah = (LVDSCRT1Ptr + ResInfo)->CR[14]; + tempah = tempah & 0x0E0; + SiS_SetReg1 (SiS_P3c4, 0x0E, tempah); + + tempah = (LVDSCRT1Ptr + ResInfo)->CR[14]; + tempah = tempah & 0x01; + tempah = tempah << 5; + if (modeflag & DoubleScanMode) { + tempah = tempah | 0x080; + } + SiS_SetRegANDOR (SiS_P3d4, 0x09, ~0x020, tempah); + return; +} + +/*add for LCDA*/ + +BOOLEAN +SiS_GetLCDACRT1Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * ResInfo, + USHORT * DisplayType) +{ + USHORT tempbx = 0, modeflag = 0; + USHORT CRT2CRTC = 0; + /*301b */ + if (((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + && (SiS_VBInfo & SetCRT2ToLCDA)) { + tempbx = SiS_LCDResInfo; + tempbx -= Panel800x600; + if (SiS_LCDInfo & LCDNonExpanding) + tempbx += 6; + if (modeflag & HalfDCLK) + tempbx += +3; + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + CRT2CRTC = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + CRT2CRTC = + SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + } + *ResInfo = CRT2CRTC & 0x3F; + *DisplayType = tempbx; + return 1; +} + +/*end for 301b*/ + +BOOLEAN +SiS_GetLVDSCRT1Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * ResInfo, + USHORT * DisplayType) +{ + USHORT tempbx, modeflag = 0; + USHORT Flag, CRT2CRTC; + + if (ModeNo <= 0x13) { + modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */ + CRT2CRTC = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */ + CRT2CRTC = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + } + if (!(SiS_VBInfo & SetInSlaveMode)) { + return 0; + } + Flag = 1; + tempbx = 0; + if (SiS_IF_DEF_CH7005 == 1) { + if (!(SiS_VBInfo & SetCRT2ToLCD)) { + Flag = 0; + tempbx = 12; + if (SiS_VBInfo & SetPALTV) + tempbx += 2; + if (SiS_VBInfo & SetCHTVOverScan) + tempbx += 1; + } + } + if (Flag) { + tempbx = SiS_LCDResInfo; + tempbx -= Panel800x600; + if (SiS_LCDInfo & LCDNonExpanding) + tempbx += 6; + if (modeflag & HalfDCLK) + tempbx += +3; + } + + *ResInfo = CRT2CRTC & 0x3F; + *DisplayType = tempbx; + return 1; +} + +void +SiS_SetCRT2ECLK (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT tempah, tempal; + USHORT P3cc = SiS_P3c9 + 3; + USHORT vclkindex = 0; + + if (SiS_IF_DEF_TRUMPION == 0) { /*no trumpion */ + tempal = SiS_GetReg2 (P3cc); + tempal = tempal & 0x0C; + vclkindex = + SiS_GetVCLK2Ptr (ROMAddr, ModeNo, ModeIdIndex, + RefreshRateTableIndex, HwDeviceExtension); + } else { /*trumpion */ + SiS_SetFlag = SiS_SetFlag & (~ProgrammingCRT2); +/* tempal=*((UCHAR *)(ROMAddr+SiS_RefIndex+0x03)); &di+Ext_CRTVCLK */ + tempal = tempal & 0x03F; + if (tempal == 0x02) { /*31.5MHz */ +/* SiS_RefIndex=SiS_RefIndex-Ext2StructSize; */ + } +/* SiS_RefIndex=GetVCLKPtr(ROMAddr,ModeNo); */ + SiS_SetFlag = SiS_SetFlag | ProgrammingCRT2; + } + tempal = 0x02B; + if (!(SiS_VBInfo & SetInSlaveMode)) { + tempal = tempal + 3; + } + SiS_SetReg1 (SiS_P3c4, 0x05, 0x86); + tempah = SiS_VCLKData[vclkindex].SR2B; + SiS_SetReg1 (SiS_P3c4, tempal, tempah); + tempal++; + tempah = SiS_VCLKData[vclkindex].SR2C; + SiS_SetReg1 (SiS_P3c4, tempal, tempah); + tempal++; + SiS_SetReg1 (SiS_P3c4, tempal, 0x80); + return; +} + +void +SiS_SetDefCRT2ExtRegs (USHORT BaseAddr) +{ + USHORT temp; + + if (SiS_IF_DEF_LVDS == 0) { + SiS_SetReg1 (SiS_Part1Port, 0x02, 0x40); + SiS_SetReg1 (SiS_Part4Port, 0x10, 0x80); + temp = (UCHAR) SiS_GetReg1 (SiS_P3c4, 0x16); + temp = temp & 0xC3; + SiS_SetReg1 (SiS_P3d4, 0x35, temp); + } else { + SiS_SetReg1 (SiS_P3d4, 0x32, 0x02); + SiS_SetReg1 (SiS_Part1Port, 0x02, 0x00); + } +} + +#ifdef CONFIG_FB_SIS_315 +/* + for SIS310 O.E.M. +*/ +/* +--------------------------------------------------------- + LCDResInfo 1 : 800x600 + 2 : 1024x768 + 3 : 1280x1024 + 4 : 1280x960 + 5 : 640x480 + 6 : 1600x1200 + 7 : 1920x1440 + VESA + non-VESA + non-Expanding +--------------------------------------------------------- +*/ +USHORT +GetLCDPtrIndex (void) +{ + USHORT index; + + index = (SiS_LCDResInfo & 0x0F) - 1; + index *= 3; + if (SiS_LCDInfo & LCDNonExpanding) + index += 2; + else { + if (!(SiS_LCDInfo & LCDVESATiming)) + index++; + } + + return index; +} + +/* +--------------------------------------------------------- + GetTVPtrIndex() + return 0 : NTSC Enhanced/Standard + 1 : NTSC Standard TVSimuMode + 2 : PAL Enhanced/Standard + 3 : PAL Standard TVSimuMode + 4 : HiVision Enhanced/Standard + 5 : HiVision Standard TVSimuMode +--------------------------------------------------------- +*/ +USHORT +GetTVPtrIndex (void) +{ + USHORT index; + + index = 0; + if (SiS_VBInfo & SetPALTV) + index++; + if (SiS_VBInfo & SetCRT2ToHiVisionTV) /* Hivision TV use PAL */ + index++; + index *= 2; + + if ((SiS_VBInfo & SetInSlaveMode) && (SiS_SetFlag & TVSimuMode)) + index++; + + return index; +} + +void +SetDelayComp (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part1Port; + USHORT delay, index; + + if (SiS_VBInfo & SetCRT2ToRAMDAC) { + delay = SiS310_CRT2DelayCompensation1; + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + delay = SiS310_CRT2DelayCompensation2; + } else if (SiS_VBInfo & SetCRT2ToLCD) { + index = GetLCDPtrIndex (); + delay = SiS310_LCDDelayCompensation1[index]; + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + delay = SiS310_LCDDelayCompensation2[index]; + } else { + index = GetTVPtrIndex (); + delay = SiS310_TVDelayCompensation1[index]; + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) + delay = SiS310_TVDelayCompensation2[index]; + } + + Part1Port = BaseAddr + SIS_CRT2_PORT_04; + SiS_SetRegANDOR (Part1Port, 0x2D, ~0x0F, delay); /* index 2D D[3:0] */ + +} + +/* +*/ +void +SetAntiFlicker (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT Part2Port; + USHORT index, temp; + + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + temp = GetTVPtrIndex (); + temp = (temp >> 1); /* 0: NTSC, 1 :PAL, 2:HiTV */ + if (ModeNo <= 0x13) { + index = SiS_SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex; + } else { + index = SiS_EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex; + } + temp = SiS310_TVAntiFlick1[temp][index]; + temp <<= 4; + + SiS_SetRegANDOR (Part2Port, 0x0A, ~0x70, temp); /* index 0A D[6:4] */ + +} + +void +SetEdgeEnhance (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT Part2Port; + USHORT index, temp; + + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + temp = GetTVPtrIndex (); + temp = (temp >> 1); /* 0: NTSC, 1 :PAL, 2:HiTV */ + if (ModeNo <= 0x13) { + index = SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex; /* si+VB_StTVEdgeIndex */ + } else { + index = SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex; /* si+VB_ExtTVEdgeIndex */ + } + temp = SiS310_TVEdge1[temp][index]; + temp <<= 5; + + SiS_SetRegANDOR (Part2Port, 0x3A, ~0xE0, temp); /* index 0A D[7:5] */ + +} + +void +SetYFilter (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT Part2Port, temp1, temp2; + USHORT index, temp, i, index1; + UCHAR OutputSelect = *pSiS_OutputSelect; + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + temp = GetTVPtrIndex (); + temp >>= 1; /* 0: NTSC, 1 :PAL, 2:HiTV */ + + if (ModeNo <= 0x13) { + index = SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex; + } else { + index = SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex; + } + + if (SiS_VBInfo & SetCRT2ToHiVisionTV) /* Hivision TV use PAL */ + temp = 0; + + /*301b */ + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_TVYFilter2[temp][index][i - 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_TVYFilter2[temp][index][(i - 0x48) + + 0x04]); + } + } + /*end 301b */ + else { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_TVYFilter1[temp][index][i - 0x35]); + } + } +/*add PALMN*/ + if (OutputSelect & EnablePALMN) { + index1 = SiS_GetReg1 (SiS_P3d4, 0x31); + temp1 = index1 & 0x01; + index1 = SiS_GetReg1 (SiS_P3d4, 0x38); + temp2 = index1 & 0xC0; + if (temp1) { + if (temp2 == 0x40) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_PALMFilter2 + [index][i - 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_PALMFilter2 + [index][(i - 0x48) + + 0x04]); + } + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS310_PALMFilter + [index][i - 0x35]); + } + } + if (temp2 == 0x80) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_PALNFilter2 + [index][i - 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS310_PALNFilter2 + [index][(i - 0x48) + + 0x04]); + } + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS310_PALNFilter + [index][i - 0x35]); + } + } + } + } + /*end PALMN */ +} + +void +SetPhaseIncr (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index, temp, temp1, i; + + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + temp = GetTVPtrIndex (); + /* 0: NTSC Graphics, 1: NTSC Text, 2 :PAL Graphics, 3 :PAL Text, 4:HiTV Graphics 5:HiTV Text */ + index = temp % 2; + temp >>= 1; /* 0: NTSC, 1 :PAL, 2:HiTV */ + temp1 = SiS_GetReg1 (SiS_P3d4, 0x38); /*if PALMN Not Set */ + temp1 = temp1 & 0xC0; + if (!temp1) { + for (i = 0x31; i <= 0x34; i++) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) + SiS_SetReg1 (Part2Port, i, + SiS310_TVPhaseIncr2[temp] + [index][i - 0x31]); + else + SiS_SetReg1 (Part2Port, i, + SiS310_TVPhaseIncr1[temp][index][i + - + 0x31]); + } + } +} +void +SiS_OEM310Setting (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex) +{ + SetDelayComp (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo); + if (SiS_VBInfo & SetCRT2ToTV) { + SetAntiFlicker (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo, + ModeIdIndex); + SetPhaseIncr (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo); + SetYFilter (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo, + ModeIdIndex); + SetEdgeEnhance (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo, + ModeIdIndex); + } +} + +#endif + +#ifdef CONFIG_FB_SIS_300 +/* + for SIS300 O.E.M. +*/ + +USHORT +GetRevisionID (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ +#ifdef CONFIG_FB_SIS_300 + ULONG temp1, base; + USHORT temp2 = 0; + /* add to set SR14 */ + if ((HwDeviceExtension->jChipType == SIS_540) || + (HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + base = 0x80000008; + OutPortLong (base, 0xcf8); + temp1 = InPortLong (0xcfc); + temp1 = temp1 & 0x000000FF; + temp2 = (USHORT) (temp1); + return temp2; + } +#endif +} + +USHORT +GetOEMLCDPtr (PSIS_HW_DEVICE_INFO HwDeviceExtension) +{ + USHORT temp, tempbx = 0, tempax; + + if (SiS_IF_DEF_LVDS == 0) { + if (SiS_VBInfo & SetCRT2ToLCD) { /* LCD */ + tempax = SiS_LCDResInfo; + tempbx = SiS_LCDResInfo; + tempbx = tempbx - Panel1024x768; + if (!(SiS_SetFlag & LCDVESATiming)) { + tempbx += 4; + temp = GetRevisionID (HwDeviceExtension); + if ((HwDeviceExtension->jChipType == SIS_540) + && (temp < 1)) + tempbx += 4; + if ((HwDeviceExtension->jChipType == SIS_630) + && (temp < 3)) + tempbx += 4; + } + if ((tempax == Panel1024x768) + && (SiS_LCDInfo == LCDNonExpanding)) { + tempbx = tempbx + 3; + } + /*add OEMLCDPanelIDSupport */ + tempbx = SiS_LCDTypeInfo; + tempbx = tempbx << 1; + if (!(SiS_SetFlag & LCDVESATiming)) + tempbx = tempbx + 1; + } + } + tempbx *= 2; + return tempbx; +} + +USHORT +GetOEMTVPtr (void) +{ + USHORT index; + + index = 0; + if (!(SiS_VBInfo & SetInSlaveMode)) + index = index + 4; + + if (SiS_VBInfo & SetCRT2ToSCART) { + index = index + 2; + } else { + if (SiS_VBInfo & SetCRT2ToHiVisionTV) + index = index + 3; + else { + if (SiS_VBInfo & SetPALTV) + index = index + 1; + } + } + return index; +} + +void +SetOEMTVDelay (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part1Port; + USHORT index, temp, ModeIdIndex; + Part1Port = BaseAddr + SIS_CRT2_PORT_04; + ModeIdIndex = SiS_SearchVBModeID (ROMAddr, ModeNo); + temp = GetOEMTVPtr (); + index = SiS_VBModeIDTable[ModeIdIndex].VB_TVDelayIndex; + temp = SiS300_OEMTVDelay[temp][index]; + temp = temp & 0x3c; + SiS_SetRegANDOR (Part1Port, 0x13, ~0x3C, temp); /* index 0A D[6:4] */ +} + +void +SetOEMLCDDelay (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index, temp, ModeIdIndex; + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + ModeIdIndex = SiS_SearchVBModeID (ROMAddr, ModeNo); + temp = GetOEMLCDPtr (HwDeviceExtension); + index = SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex; + temp = SiS300_OEMLCDDelay1[temp][index]; + /*add OEMLCDPanelIDSupport */ + temp = SiS300_OEMLCDDelay2[temp][index]; + temp = temp & 0x3c; + SiS_SetRegANDOR (Part2Port, 0x13, ~0x3C, temp); /* index 0A D[6:4] */ +} + +/* +*/ +void +SetOEMAntiFlicker (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index, temp; + USHORT ModeIdIndex; + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + ModeIdIndex = SiS_SearchVBModeID (ROMAddr, ModeNo); + temp = GetOEMTVPtr (); + index = SiS_VBModeIDTable[ModeIdIndex].VB_TVFlickerIndex; + temp = SiS300_OEMTVFlicker[temp][index]; + temp = temp & 0x70; + SiS_SetRegANDOR (Part2Port, 0x0A, ~0x70, temp); /* index 0A D[6:4] */ + +} + +void +SetOEMPhaseIncr (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index, i, ModeIdIndex; + + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + // temp = GetTVPtrIndex(); + /* 0: NTSC Graphics, 1: NTSC Text, 2 :PAL Graphics, 3 :PAL Text, 4:HiTV Graphics 5:HiTV Text */ + // index = temp % 2; + // temp >>= 1; /* 0: NTSC, 1 :PAL, 2:HiTV */ + ModeIdIndex = SiS_SearchVBModeID (ROMAddr, ModeNo); + index = SiS_VBModeIDTable[ModeIdIndex].VB_TVPhaseIndex; + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_VBInfo & SetPALTV) { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_StPALPhase[index][i - + 0x31]); + } else { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_StNTSCPhase[index][i - + 0x31]); + } + if (SiS_VBInfo & SetCRT2ToSCART) { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_StSCARTPhase[index][i - + 0x31]); + } + } else { + if (SiS_VBInfo & SetPALTV) { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_ExtPALPhase[index][i - + 0x31]); + } else { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_ExtNTSCPhase[index][i - + 0x31]); + } + if (SiS_VBInfo & SetCRT2ToSCART) { + for (i = 0x31; i <= 0x34; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_ExtSCARTPhase[index][i - + 0x31]); + } + } +} + +void +SetOEMYFilter (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + USHORT Part2Port; + USHORT index, temp1, temp2, i, ModeIdIndex, index1; + Part2Port = BaseAddr + SIS_CRT2_PORT_10; + /*301b */ + ModeIdIndex = SiS_SearchVBModeID (ROMAddr, ModeNo); + index = SiS_VBModeIDTable[ModeIdIndex].VB_TVYFilterIndex; + if (SiS_VBInfo & SetInSlaveMode) { + if (SiS_VBInfo & SetPALTV) { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_StPALFilter[index][i - + 0x35]); + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_StNTSCFilter[index][i - + 0x35]); + } + } else { + if (SiS_VBInfo & SetPALTV) { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_ExtPALFilter[index][i - + 0x35]); + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_ExtNTSCFilter[index][i - + 0x35]); + } + } + + if ((SiS_VBType & VB_SIS301B) || (SiS_VBType & VB_SIS302B)) { + if (SiS_VBInfo & SetPALTV) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALFilter2[index][i - + 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALFilter2[index][(i - 0x48) + + 0x04]); + } + } else { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_NTSCFilter2[index][i - + 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_NTSCFilter2[index][ + (i - + 0x48) + + 0x04]); + } + } + } + +/*add PALMN*/ + if ((HwDeviceExtension->jChipType == SIS_630) || + (HwDeviceExtension->jChipType == SIS_730)) { + index1 = SiS_GetReg1 (SiS_P3d4, 0x31); + temp1 = index1 & 0x01; + index1 = SiS_GetReg1 (SiS_P3d4, 0x35); + temp2 = index1 & 0xC0; + if (temp1) { + if (temp2 == 0x40) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALMFilter2 + [index][i - 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALMFilter2 + [index][(i - 0x48) + + 0x04]); + } + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_PALMFilter + [index][i - 0x35]); + } + } + if (temp2 == 0x80) { + if ((SiS_VBType & VB_SIS301B) + || (SiS_VBType & VB_SIS302B)) { + for (i = 0x35; i <= 0x38; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALNFilter2 + [index][i - 0x35]); + } + for (i = 0x48; i <= 0x4A; i++) { + SiS_SetReg1 (Part2Port, i, + SiS300_PALNFilter2 + [index][(i - 0x48) + + 0x04]); + } + } else { + for (i = 0x35; i <= 0x38; i++) + SiS_SetReg1 (Part2Port, i, + SiS300_PALNFilter + [index][i - 0x35]); + } + } + } + } + /*end PALMN */ +} + +void +SiS_OEM300Setting (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo) +{ + if (SiS_VBInfo & SetCRT2ToLCD) { + SetOEMLCDDelay (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo); + } + if (SiS_VBInfo & SetCRT2ToTV) { + SetOEMTVDelay (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo); + SetOEMAntiFlicker (HwDeviceExtension, BaseAddr, ROMAddr, + ModeNo); + /* SetOEMPhaseIncr(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo); */ + SetOEMYFilter (HwDeviceExtension, BaseAddr, ROMAddr, ModeNo); + } +} +#endif diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/init301.h linux/drivers/video/sis/init301.h --- v2.4.14/linux/drivers/video/sis/init301.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/init301.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,223 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.h,v 1.4 2000/12/02 01:16:17 dawes Exp $ */ +#ifndef _INIT301_ +#define _INIT301_ + +#include "osdef.h" +#include "initdef.h" +#include "vgatypes.h" +#include "vstruct.h" + +#include <asm/io.h> +#include <linux/types.h> +#include <linux/sisfb.h> + +USHORT SiS_SetFlag; +USHORT SiS_RVBHCFACT, SiS_RVBHCMAX, SiS_RVBHRS; +USHORT SiS_VGAVT, SiS_VGAHT; +USHORT SiS_VT, SiS_HT; +USHORT SiS_VGAVDE, SiS_VGAHDE; +USHORT SiS_VDE, SiS_HDE; +USHORT SiS_NewFlickerMode, SiS_RY1COE, SiS_RY2COE, SiS_RY3COE, SiS_RY4COE; +USHORT SiS_LCDHDES, SiS_LCDVDES; +USHORT SiS_DDC_Port; +USHORT SiS_DDC_Index; +USHORT SiS_DDC_DataShift; +USHORT SiS_DDC_DeviceAddr; +USHORT SiS_DDC_Flag; +USHORT SiS_DDC_ReadAddr; +USHORT SiS_DDC_Buffer; + +extern USHORT SiS_CRT1Mode; +extern USHORT SiS_P3c4, SiS_P3d4; +/*extern USHORT SiS_P3c0,SiS_P3ce,SiS_P3c2;*/ +extern USHORT SiS_P3ca; +/*extern USHORT SiS_P3c6,SiS_P3c7,SiS_P3c8;*/ +extern USHORT SiS_P3c9; +extern USHORT SiS_P3da; +extern USHORT SiS_Part1Port, SiS_Part2Port; +extern USHORT SiS_Part3Port, SiS_Part4Port, SiS_Part5Port; +extern USHORT SiS_MDA_DAC[]; +extern USHORT SiS_CGA_DAC[]; +extern USHORT SiS_EGA_DAC[]; +extern USHORT SiS_VGA_DAC[]; +extern USHORT SiS_ModeType; +extern USHORT SiS_SelectCRT2Rate; +extern USHORT SiS_IF_DEF_LVDS; +extern USHORT SiS_IF_DEF_TRUMPION; +extern USHORT SiS_IF_DEF_CH7005; +extern USHORT SiS_IF_DEF_HiVision; +extern USHORT SiS_IF_DEF_DSTN; /*add for dstn */ +extern USHORT SiS_VBInfo; +extern USHORT SiS_VBType; /*301b */ +extern USHORT SiS_LCDResInfo; +extern USHORT SiS_LCDTypeInfo; +extern USHORT SiS_LCDInfo; +extern BOOLEAN SiS_SearchVBModeID (ULONG, USHORT); +extern BOOLEAN SiS_Is301B (USHORT BaseAddr); /*301b */ +extern BOOLEAN SiS_IsDisableCRT2 (USHORT BaseAddr); +extern BOOLEAN SiS_IsVAMode (USHORT BaseAddr); +extern BOOLEAN SiS_IsDualEdge (USHORT BaseAddr); +/*end 301b*/ + +void SiS_SetDefCRT2ExtRegs (USHORT BaseAddr); +USHORT SiS_GetRatePtrCRT2 (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +BOOLEAN SiS_AjustCRT2Rate (ULONG ROMAddr, USHORT ModeNo, USHORT MODEIdIndex, + USHORT RefreshRateTableIndex, USHORT * i); +void SiS_SaveCRT2Info (USHORT ModeNo); +void SiS_GetCRT2Data (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_GetCRT2DataLVDS (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_GetCRT2PtrA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * CRT2Index, USHORT * ResIndex); /*301b */ +void SiS_GetCRT2Data301 (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +USHORT SiS_GetResInfo (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_GetCRT2ResInfo (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_GetRAMDAC2DATA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_GetCRT2Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * CRT2Index, + USHORT * ResIndex); +void SiS_SetCRT2ModeRegs (USHORT BaseAddr, USHORT ModeNo, PSIS_HW_DEVICE_INFO); + +void SiS_GetLVDSDesData (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_SetCRT2Offset (USHORT Part1Port, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +USHORT SiS_GetOffset (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +USHORT SiS_GetColorDepth (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +USHORT SiS_GetVCLK (ULONG ROMAddr, USHORT ModeNo); +USHORT SiS_GetVCLKPtr (ULONG ROMAddr, USHORT ModeNo); +USHORT SiS_GetColorTh (ULONG ROMAddr); +USHORT SiS_GetMCLK (ULONG ROMAddr); +USHORT SiS_GetMCLKPtr (ULONG ROMAddr); +USHORT SiS_GetDRAMType (ULONG ROMAddr); +USHORT SiS_CalcDelayVB (void); +extern USHORT SiS_GetVCLK2Ptr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetCRT2Sync (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT RefreshRateTableIndex); +void SiS_SetRegANDOR (USHORT Port, USHORT Index, USHORT DataAND, USHORT DataOR); +void SiS_SetRegOR (USHORT Port, USHORT Index, USHORT DataOR); +void SiS_SetRegAND (USHORT Port, USHORT Index, USHORT DataAND); +USHORT SiS_GetVGAHT2 (void); +void SiS_SetGroup2 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetGroup3 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetGroup4 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetGroup5 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex); +void SiS_SetCRT2VCLK (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_EnableCRT2 (void); +void SiS_LoadDAC2 (ULONG ROMAddr, USHORT Part5Port, USHORT ModeNo, + USHORT ModeIdIndex); +void SiS_WriteDAC2 (USHORT Pdata, USHORT dl, USHORT ah, USHORT al, USHORT dh); +void SiS_GetVBInfo301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +BOOLEAN SiS_GetLCDResInfo (ULONG ROMAddr, USHORT P3d4, USHORT ModeNo, + USHORT ModeIdIndex); +BOOLEAN SiS_BridgeIsOn (USHORT BaseAddr); +BOOLEAN SiS_BridgeIsEnable (USHORT BaseAddr, PSIS_HW_DEVICE_INFO); +BOOLEAN SiS_BridgeInSlave (void); +/*void SiS_PresetScratchregister(USHORT P3d4);*/ +void SiS_PresetScratchregister (USHORT SiS_P3d4, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetTVSystem (VOID); +void SiS_LongWait (VOID); +USHORT SiS_GetQueueConfig (VOID); +void SiS_VBLongWait (VOID); +USHORT SiS_GetVCLKLen (ULONG ROMAddr); +BOOLEAN SiS_WaitVBRetrace (USHORT BaseAddr); +void SiS_SetCRT2ECLK (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_GetLVDSDesPtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * PanelIndex, + USHORT * ResIndex); +void SiS_GetLVDSDesPtrA (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, USHORT * PanelIndex, + USHORT * ResIndex); /*301b */ +void SiS_SetTPData (VOID); +void SiS_ModCRT1CRTC (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +extern BOOLEAN SiS_GetLVDSCRT1Ptr (ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + USHORT RefreshRateTableIndex, + USHORT * ResInfo, USHORT * DisplayType); +void SiS_SetCHTVReg (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_SetCHTVRegANDOR (USHORT tempax, USHORT tempbh); +void SiS_GetCHTVRegPtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RefreshRateTableIndex); +void SiS_SetCH7005 (USHORT tempax); +USHORT SiS_GetCH7005 (USHORT tempax); +void SiS_SetSwitchDDC2 (void); +void SiS_SetStart (void); +void SiS_SetStop (void); +void SiS_DDC2Delay (void); +void SiS_SetSCLKLow (void); +void SiS_SetSCLKHigh (void); +USHORT SiS_ReadDDC2Data (USHORT tempax); +USHORT SiS_WriteDDC2Data (USHORT tempax); +USHORT SiS_CheckACK (void); +void SiS_OEM310Setting (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_OEM300Setting (PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr, + ULONG ROMAddr, USHORT ModeNo); +USHORT GetRevisionID (PSIS_HW_DEVICE_INFO HwDeviceExtension); +extern void SiS_SetReg1 (USHORT, USHORT, USHORT); +extern void SiS_SetReg3 (USHORT, USHORT); +extern UCHAR SiS_GetReg1 (USHORT, USHORT); +extern UCHAR SiS_GetReg2 (USHORT); +extern BOOLEAN SiS_SearchModeID (ULONG ROMAddr, USHORT ModeNo, + USHORT * ModeIdIndex); +extern BOOLEAN SiS_GetRatePtr (ULONG, USHORT); +extern void SiS_SetReg4 (USHORT, ULONG); +extern ULONG SiS_GetReg3 (USHORT); +extern void SiS_DisplayOff (void); +extern void SiS_CRT2AutoThreshold (USHORT BaseAddr); +extern void SiS_DisplayOn (void); +extern UCHAR SiS_GetModePtr (ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex); +extern UCHAR SiS_Get310DRAMType (ULONG ROMAddr); + +BOOLEAN SiS_SetCRT2Group301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetGroup1 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex); +void SiS_SetGroup1_LVDS (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex); +void SiS_SetGroup1_LCDA (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT RefreshRateTableIndex); /*301b */ +void SiS_SetGroup1_301 (USHORT BaseAddr, ULONG ROMAddr, USHORT ModeNo, + USHORT ModeIdIndex, + PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT RefreshRateTableIndex); +void SiS_SetCRT2FIFO (USHORT Part1Port, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_SetCRT2FIFO2 (USHORT Part1Port, ULONG ROMAddr, USHORT ModeNo, + PSIS_HW_DEVICE_INFO HwDeviceExtension); +BOOLEAN SiS_GetLCDDDCInfo (PSIS_HW_DEVICE_INFO HwDeviceExtension); +void SiS_UnLockCRT2 (PSIS_HW_DEVICE_INFO, USHORT BaseAddr); +void SiS_LockCRT2 (PSIS_HW_DEVICE_INFO, USHORT BaseAddr); +void SiS_DisableBridge (PSIS_HW_DEVICE_INFO, USHORT BaseAddr); +void SiS_EnableBridge (PSIS_HW_DEVICE_INFO, USHORT BaseAddr); +void SiS_SetPanelDelay (USHORT DelayTime); +void SiS_LCD_Wait_Time (UCHAR DelayTime); + +#endif diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/initdef.h linux/drivers/video/sis/initdef.h --- v2.4.14/linux/drivers/video/sis/initdef.h Wed Nov 8 17:15:04 2000 +++ linux/drivers/video/sis/initdef.h Fri Nov 9 14:11:14 2001 @@ -1,138 +1,312 @@ -#include "sis.h" +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/initdef.h,v 1.4 2000/12/02 01:16:17 dawes Exp $ */ +#ifndef _INITDEF_ +#define _INITDEF_ -#define PRIMARY_VGA 1 //1: SiS is primary vga 0:SiS is secondary vga -#define ModeInfoFlag 0x07 -#define MemoryInfoFlag 0x1E0 -#define MemorySizeShift 0x05 -#define ModeText 0x00 -#define ModeCGA 0x01 -#define ModeEGA 0x02 -#define ModeVGA 0x03 -#define Mode15Bpp 0x04 -#define Mode16Bpp 0x05 -#define Mode24Bpp 0x06 -#define Mode32Bpp 0x07 -#define CRT1Len 17 -#define DoubleScanMode 0x8000 -#define ADR_CRT2PtrData 0x20E //address of CRT2PtrData in ROM image -#define offset_Zurac 0x210 -#define ADR_LVDSDesPtrData 0x212 -#define ADR_LVDSCRT1DataPtr 0x214 +#define SiS300 0x0300 +#define SiS540 0x5300 +#define SiS630 0x6300 +#define SiS730 0x6300 +#define VB_SIS301 0x0001 /*301b */ +#define VB_SIS301B 0x0002 +#define VB_SIS302B 0x0004 +#define VB_NoLCD 0x8000 + +/*end 301b*/ +#define CRT1Len 17 +#define LVDSCRT1Len 15 +#define CHTVRegDataLen 5 + +#define ModeInfoFlag 0x07 +#define IsTextMode 0x07 +#define ModeText 0x00 +#define ModeCGA 0x01 +#define ModeEGA 0x02 +#define ModeVGA 0x03 +#define Mode15Bpp 0x04 +#define Mode16Bpp 0x05 +#define Mode24Bpp 0x06 +#define Mode32Bpp 0x07 + +#define DACInfoFlag 0x18 +#define MemoryInfoFlag 0x1E0 +#define MemorySizeShift 0x05 -#define SoftDRAMType 0x80 //5/19/2000,Mars,for soft setting dram type -#define SoftSettingAddr 0x52 -#define ModeSettingAddr 0x53 - -#define InterlaceMode 0x80 -#define HalfDCLK 0x1000 -#define DACInfoFlag 0x18 -#define LineCompareOff 0x400 -#define ActivePAL 0x20 -#define ActivePALShift 5 - - -#define SelectCRT2Rate 0x4 -#define ProgrammingCRT2 0x1 -#define CRT2DisplayFlag 0x2000 -#define SetCRT2ToRAMDAC 0x0040 #define Charx8Dot 0x0200 -#define LCDDataLen 8 +#define LineCompareOff 0x0400 +#define CRT2Mode 0x0800 +#define HalfDCLK 0x1000 +#define NoSupportSimuTV 0x2000 +#define DoubleScanMode 0x8000 + +#define SupportAllCRT2 0x0078 +#define SupportTV 0x0008 +#define SupportHiVisionTV 0x0010 +#define SupportLCD 0x0020 +#define SupportRAMDAC2 0x0040 +#define NoSupportTV 0x0070 +#define NoSupportHiVisionTV 0x0060 +#define NoSupportLCD 0x0058 +#define SupportCHTV 0x0800 +#define SupportTV1024 0x0800 /*301b */ +#define InterlaceMode 0x0080 +#define SyncPP 0x0000 +#define SyncPN 0x4000 +#define SyncNP 0x8000 +#define SyncNN 0xc000 +#define ECLKindex0 0x0000 +#define ECLKindex1 0x0100 +#define ECLKindex2 0x0200 +#define ECLKindex3 0x0300 +#define ECLKindex4 0x0400 + +#define SetSimuScanMode 0x0001 +#define SwitchToCRT2 0x0002 +#define SetCRT2ToTV 0x009C +#define SetCRT2ToAVIDEO 0x0004 +#define SetCRT2ToSVIDEO 0x0008 +#define SetCRT2ToSCART 0x0010 #define SetCRT2ToLCD 0x0020 +#define SetCRT2ToRAMDAC 0x0040 #define SetCRT2ToHiVisionTV 0x0080 -#define HiTVDataLen 12 -#define TVDataLen 16 +#define SetNTSCTV 0x0000 #define SetPALTV 0x0100 #define SetInSlaveMode 0x0200 -#define SetCRT2ToTV 0x009C +#define SetNotSimuMode 0x0400 #define SetNotSimuTVMode 0x0400 -#define SetSimuScanMode 0x0001 +#define SetDispDevSwitch 0x0800 +#define LoadDACFlag 0x1000 +#define DisableCRT2Display 0x2000 #define DriverMode 0x4000 -#define CRT2Mode 0x0800 -//#define ReIndexEnhLCD 4 +#define HotKeySwitch 0x8000 +#define SetCHTVOverScan 0x8000 +#define SetCRT2ToLCDA 0x8000 /*301b */ +#define PanelRGB18Bit 0x0100 +#define PanelRGB24Bit 0x0000 + +#define TVOverScan 0x10 +#define TVOverScanShift 4 +#define ClearBufferFlag 0x20 +#define EnableDualEdge 0x01 /*301b */ +#define SetToLCDA 0x02 + +#define SetSCARTOutput 0x01 +#define BoardTVType 0x02 +#define EnablePALMN 0x40 +#define ProgrammingCRT2 0x01 +#define TVSimuMode 0x02 +#define RPLLDIV2XO 0x04 +#define LCDVESATiming 0x08 +#define EnableLVDSDDA 0x10 +#define SetDispDevSwitchFlag 0x20 +#define CheckWinDos 0x40 +#define SetJDOSMode 0x80 + +#define Panel800x600 0x01 +#define Panel1024x768 0x02 +#define Panel1280x1024 0x03 +#define Panel1280x960 0x04 +#define Panel640x480 0x05 +#define Panel1600x1200 0x06 /*301b */ +#define LCDRGB18Bit 0x01 +#define ExtChipType 0x0e +#define ExtChip301 0x02 +#define ExtChipLVDS 0x04 +#define ExtChipTrumpion 0x06 +#define ExtChipCH7005 0x08 +#define ExtChipMitacTV 0x0a +#define LCDNonExpanding 0x10 +#define LCDNonExpandingShift 4 +#define LCDSync 0x20 +#define LCDSyncBit 0xe0 +#define LCDSyncShift 6 + +#define DDC2DelayTime 300 + +#define CRT2DisplayFlag 0x2000 +#define LCDDataLen 8 +#define HiTVDataLen 12 +#define TVDataLen 16 +#define SetPALTV 0x0100 #define HalfDCLK 0x1000 -//#define HiVisionTVHT 2100 -//#define HiVisionTVVT 2100 #define NTSCHT 1716 #define NTSCVT 525 #define PALHT 1728 #define PALVT 625 +#define StHiTVHT 892 +#define StHiTVVT 1126 +#define StHiTextTVHT 1000 +#define StHiTextTVVT 1126 +#define ExtHiTVHT 2100 +#define ExtHiTVVT 1125 -#define VCLKStartFreq 25 -//Freq of first item in VCLKTable - +#define VCLKStartFreq 25 #define SoftDramType 0x80 +#define VCLK40 0x04 #define VCLK65 0x09 #define VCLK108_2 0x14 -//#define LCDIs1280x1024Panel 0x04 -//#define HiVisionVCLK 0x22 -#define TVSimuMode 0x02 -#define SetCRT2ToSVIDEO 0x08 -//#define LCDRGB18Bit 0x20 #define LCDRGB18Bit 0x01 -#define Panel1280x1024 0x03 -#define Panel1024x768 0x02 -#define Panel800x600 0x01 -#define RPLLDIV2XO 0x04 #define LoadDACFlag 0x1000 #define AfterLockCRT2 0x4000 -#define SupportRAMDAC2 0x0040 -#define SupportLCD 0x0020 -//#define Support1024x768LCD 0x0020 -//#define Support1280x1024LCD 0x0040 #define SetCRT2ToAVIDEO 0x0004 #define SetCRT2ToSCART 0x0010 -//#define NoSupportSimuTV 0x0100 -#define NoSupportSimuTV 0x2000 #define Ext2StructSize 5 -#define SupportTV 0x0008 -//#define TVVCLKDIV2 0x020 -//#define TVVCLK 0x021 + #define TVVCLKDIV2 0x021 #define TVVCLK 0x022 + +#define HiTVVCLKDIV2 0x023 +#define HiTVVCLK 0x024 +#define HiTVSimuVCLK 0x025 +#define HiTVTextVCLK 0x026 #define SwitchToCRT2 0x0002 #define LCDVESATiming 0x08 #define SetSCARTOutput 0x01 +#define AVIDEOSense 0x01 +#define SVIDEOSense 0x02 #define SCARTSense 0x04 +#define LCDSense 0x08 #define Monitor1Sense 0x20 #define Monitor2Sense 0x10 -#define SVIDEOSense 0x02 -#define AVIDEOSense 0x01 -#define LCDSense 0x08 +#define HiTVSense 0x40 #define BoardTVType 0x02 #define HotPlugFunction 0x08 #define StStructSize 0x06 -#define ExtChip301 0x02 -#define ExtChipLVDS 0x04 -#define ExtChipTrumpion 0x06 +#define SIS_CRT2_PORT_04 0x04 - 0x030 +#define SIS_CRT2_PORT_10 0x10 - 0x30 +#define SIS_CRT2_PORT_12 0x12 - 0x30 +#define SIS_CRT2_PORT_14 0x14 - 0x30 + #define LCDNonExpanding 0x10 -#define LCDNonExpandingShift 4 +#define ADR_CRT2PtrData 0x20E +#define offset_Zurac 0x210 +#define ADR_LVDSDesPtrData 0x212 +#define ADR_LVDSCRT1DataPtr 0x214 +#define ADR_CHTVVCLKPtr 0x216 +#define ADR_CHTVRegDataPtr 0x218 + #define LVDSDataLen 6 #define EnableLVDSDDA 0x10 -#define LCDSync 0x20 -#define SyncPP 0x0000 -#define LCDSyncBit 0xE0 #define LVDSDesDataLen 3 -#define LVDSCRT1Len 15 -#define ActiveNonExpanding 0x40 -#define ActiveNonExpandingShift 6 -#define ModeSwitchStatus 0x0F -#define SoftTVType 0x40 - -#define PanelType00 0x00 -#define PanelType01 0x08 -#define PanelType02 0x10 -#define PanelType03 0x18 -#define PanelType04 0x20 -#define PanelType05 0x28 -#define PanelType06 0x30 -#define PanelType07 0x38 -#define PanelType08 0x40 -#define PanelType09 0x48 -#define PanelType0A 0x50 -#define PanelType0B 0x58 -#define PanelType0C 0x60 -#define PanelType0D 0x68 -#define PanelType0E 0x70 -#define PanelType0F 0x78 +#define ActiveNonExpanding 0x40 +#define ActiveNonExpandingShift 6 +#define ActivePAL 0x20 +#define ActivePALShift 5 +#define ModeSwitchStatus 0x0F +#define SoftTVType 0x40 +#define SoftSettingAddr 0x52 +#define ModeSettingAddr 0x53 + +#define SelectCRT1Rate 0x4 + +#define _PanelType00 0x00 +#define _PanelType01 0x08 +#define _PanelType02 0x10 +#define _PanelType03 0x18 +#define _PanelType04 0x20 +#define _PanelType05 0x28 +#define _PanelType06 0x30 +#define _PanelType07 0x38 +#define _PanelType08 0x40 +#define _PanelType09 0x48 +#define _PanelType0A 0x50 +#define _PanelType0B 0x58 +#define _PanelType0C 0x60 +#define _PanelType0D 0x68 +#define _PanelType0E 0x70 +#define _PanelType0F 0x78 + +#define PRIMARY_VGA 0 /* 1: SiS is primary vga 0:SiS is secondary vga */ +#define BIOSIDCodeAddr 0x235 +#define OEMUtilIDCodeAddr 0x237 +#define VBModeIDTableAddr 0x239 +#define OEMTVPtrAddr 0x241 +#define PhaseTableAddr 0x243 +#define NTSCFilterTableAddr 0x245 +#define PALFilterTableAddr 0x247 +#define OEMLCDPtr_1Addr 0x249 +#define OEMLCDPtr_2Addr 0x24B +#define LCDHPosTable_1Addr 0x24D +#define LCDHPosTable_2Addr 0x24F +#define LCDVPosTable_1Addr 0x251 +#define LCDVPosTable_2Addr 0x253 +#define OEMLCDPIDTableAddr 0x255 + +#define VBModeStructSize 5 +#define PhaseTableSize 4 +#define FilterTableSize 4 +#define LCDHPosTableSize 7 +#define LCDVPosTableSize 5 +#define OEMLVDSPIDTableSize 4 +#define LVDSHPosTableSize 4 +#define LVDSVPosTableSize 6 + +#define VB_ModeID 0 +#define VB_TVTableIndex 1 +#define VB_LCDTableIndex 2 +#define VB_LCDHIndex 3 +#define VB_LCDVIndex 4 + +#define OEMLCDEnable 0x0001 +#define OEMLCDDelayEnable 0x0002 +#define OEMLCDPOSEnable 0x0004 +#define OEMTVEnable 0x0100 +#define OEMTVDelayEnable 0x0200 +#define OEMTVFlickerEnable 0x0400 +#define OEMTVPhaseEnable 0x0800 +#define OEMTVFilterEnable 0x1000 + +#define OEMLCDPanelIDSupport 0x0080 + +/* ============================================================= + for 310 +============================================================== */ +#define SoftDRAMType 0x80 +#define SoftSetting_OFFSET 0x52 +#define SR07_OFFSET 0x7C +#define SR15_OFFSET 0x7D +#define SR16_OFFSET 0x81 +#define SR17_OFFSET 0x85 +#define SR19_OFFSET 0x8D +#define SR1F_OFFSET 0x99 +#define SR21_OFFSET 0x9A +#define SR22_OFFSET 0x9B +#define SR23_OFFSET 0x9C +#define SR24_OFFSET 0x9D +#define SR25_OFFSET 0x9E +#define SR31_OFFSET 0x9F +#define SR32_OFFSET 0xA0 +#define SR33_OFFSET 0xA1 + +#define CR40_OFFSET 0xA2 +#define SR25_1_OFFSET 0xF6 +#define CR49_OFFSET 0xF7 + +#define VB310Data_1_2_Offset 0xB6 +#define VB310Data_4_D_Offset 0xB7 +#define VB310Data_4_E_Offset 0xB8 +#define VB310Data_4_10_Offset 0xBB + +#define RGBSenseDataOffset 0xBD +#define YCSenseDataOffset 0xBF +#define VideoSenseDataOffset 0xC1 +#define OutputSelectOffset 0xF3 + +#define ECLK_MCLK_DISTANCE 0x14 +#define VBIOSTablePointerStart 0x100 +#define StandTablePtrOffset VBIOSTablePointerStart+0x02 +#define EModeIDTablePtrOffset VBIOSTablePointerStart+0x04 +#define CRT1TablePtrOffset VBIOSTablePointerStart+0x06 +#define ScreenOffsetPtrOffset VBIOSTablePointerStart+0x08 +#define VCLKDataPtrOffset VBIOSTablePointerStart+0x0A +#define MCLKDataPtrOffset VBIOSTablePointerStart+0x0E +#define CRT2PtrDataPtrOffset VBIOSTablePointerStart+0x10 +#define TVAntiFlickPtrOffset VBIOSTablePointerStart+0x12 +#define TVDelayPtr1Offset VBIOSTablePointerStart+0x14 +#define TVPhaseIncrPtr1Offset VBIOSTablePointerStart+0x16 +#define TVYFilterPtr1Offset VBIOSTablePointerStart+0x18 +#define LCDDelayPtr1Offset VBIOSTablePointerStart+0x20 +#define TVEdgePtr1Offset VBIOSTablePointerStart+0x24 +#define CRT2Delay1Offset VBIOSTablePointerStart+0x28 +#endif diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/oem300.h linux/drivers/video/sis/oem300.h --- v2.4.14/linux/drivers/video/sis/oem300.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/oem300.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,397 @@ +UCHAR SiS300_TVEdge1[3][2] = { + {0x0, 0x4}, + {0x0, 0x4}, + {0x0, 0x0} +}; + +UCHAR SiS300_OEMTVDelay[8][4] = { + {0x08, 0x08, 0x08, 0x08}, + {0x08, 0x08, 0x08, 0x08}, + {0x08, 0x08, 0x08, 0x08}, + {0x2c, 0x2c, 0x2c, 0x2c}, + {0x08, 0x08, 0x08, 0x08}, + {0x08, 0x08, 0x08, 0x08}, + {0x08, 0x08, 0x08, 0x08}, + {0x20, 0x20, 0x20, 0x20} +}; + +UCHAR SiS300_OEMTVFlicker[8][4] = { + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00} +}; + +UCHAR SiS300_OEMLCDDelay1[12][4] = { + {0x2c, 0x2c, 0x2c, 0x2c}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x2c, 0x2c, 0x2c, 0x2c}, + {0x2c, 0x2c, 0x2c, 0x2c}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x24, 0x24, 0x24, 0x24}, + {0x24, 0x24, 0x24, 0x24}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x24, 0x24, 0x24, 0x24} +}; + +UCHAR SiS300_OEMLCDDelay2[32][4] = { + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20}, + {0x20, 0x20, 0x20, 0x20} +}; + +UCHAR SiS300_StNTSCPhase[6][4] = { + {0x21, 0xed, 0x00, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StPALPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StSCARTPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StHiTVPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtNTSCPhase[6][4] = { + {0x21, 0xed, 0x00, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0x21, 0xed, 0x8a, 0x08}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtPALPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtSCARTPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtHiTVPhase[6][4] = { + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0x2a, 0x05, 0xd3, 0x00}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StNTSCFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StPALFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StSCARTFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_StHiTVFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtNTSCFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtPALFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtSCARTFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_ExtHiTVFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x10, 0x32}, + {0xf3, 0x00, 0x1d, 0x20}, + {0x00, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xfc, 0xfb, 0x14, 0x2a}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_NTSCFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; + +UCHAR SiS300_PALFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; + +UCHAR SiS300_PALMFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_PALNFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS300_PALMFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; + +UCHAR SiS300_PALNFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/oem310.h linux/drivers/video/sis/oem310.h --- v2.4.14/linux/drivers/video/sis/oem310.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/oem310.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,204 @@ +UCHAR SiS310_CRT2DelayCompensation1 = 0x4; /* 301A */ + +UCHAR SiS310_LCDDelayCompensation1[] = { + 0x0, 0x0, 0x0, 0xb, 0xb, 0xb, 0x8, 0x8, + 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0 +}; + +UCHAR SiS310_TVDelayCompensation1[] = { 0x2, 0x2, 0x2, 0x2, 0x8, 0xb }; +UCHAR SiS310_CRT2DelayCompensation2 = 0xC; /* 301B */ +UCHAR SiS310_LCDDelayCompensation2[] = { + 0x0, 0x0, 0x0, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x8, 0x8, 0x8, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}; + +UCHAR SiS310_TVDelayCompensation2[] = { 0x3, 0x3, 0x3, 0x3, 0x8, 0xb }; + +UCHAR SiS310_TVAntiFlick1[3][2] = { + {0x4, 0x0}, + {0x4, 0x8}, + {0x0, 0x0} +}; + +UCHAR SiS310_TVEdge1[3][2] = { + {0x0, 0x4}, + {0x0, 0x4}, + {0x0, 0x0} +}; + +UCHAR SiS310_TVYFilter1[3][8][4] = { + { + {0x0, 0xf4, 0x10, 0x38}, + {0x0, 0xf4, 0x10, 0x38}, + {0xeb, 0x4, 0x25, 0x18}, + {0xf7, 0x6, 0x19, 0x14}, + {0x0, 0xf4, 0x10, 0x38}, + {0xeb, 0x4, 0x25, 0x18}, + {0xee, 0xc, 0x22, 0x8}, + {0xeb, 0x15, 0x25, 0xf6} + } + , + { + {0x0, 0xf4, 0x10, 0x38}, + {0x0, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf3, 0x0, 0x1d, 0x20}, + {0x0, 0xf4, 0x10, 0x38}, + {0xf1, 0xf7, 0x1f, 0x32}, + {0xf3, 0x0, 0x1d, 0x20}, + {0xfc, 0xfb, 0x14, 0x2a} + } + , + { + {0x0, 0x0, 0x0, 0x0}, + {0x0, 0xf4, 0x10, 0x38}, + {0x0, 0xf4, 0x10, 0x38}, + {0xeb, 0x4, 0x25, 0x18}, + {0xf7, 0x6, 0x19, 0x14}, + {0x0, 0xf4, 0x10, 0x38}, + {0xeb, 0x4, 0x25, 0x18}, + {0xee, 0xc, 0x22, 0x8} + } +}; + +/*301b*/ +UCHAR SiS310_TVYFilter2[3][9][7] = { + { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} + } + , + { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} + } + , + { + + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22}, + {0x0, 0x0, 0x0, 0xF4, 0xFF, 0x1C, 0x22} + } +}; +/*end 301b*/ +/*add PALMN*/ + +UCHAR SiS310_PALMFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS310_PALNFilter[17][4] = { + {0x00, 0xf4, 0x10, 0x38}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x10, 0x18}, + {0xf7, 0x06, 0x19, 0x14}, + {0x00, 0xf4, 0x10, 0x38}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x15, 0x25, 0xf6}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xeb, 0x04, 0x25, 0x18}, + {0xff, 0xff, 0xff, 0xff} +}; + +UCHAR SiS310_PALMFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; + +UCHAR SiS310_PALNFilter2[9][7] = { + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0xFF, 0x03, 0x02, 0xF6, 0xFC, 0x27, 0x46}, + {0x01, 0x02, 0xFE, 0xF7, 0x03, 0x27, 0x3C}, + {0x01, 0x01, 0xFC, 0xF8, 0x08, 0x26, 0x38}, + {0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x22, 0x28} +}; + +/*end PALMN*/ +UCHAR SiS310_TVPhaseIncr1[3][2][4] = { + { + {0x21, 0xed, 0x8a, 0x8}, + {0x21, 0xed, 0x8a, 0x8} + } + , + { + {0x2a, 0x5, 0xd3, 0x0}, + {0x2a, 0x5, 0xd3, 0x0} + } + , + { + {0x2a, 0x5, 0xd3, 0x0}, + {0x2a, 0x5, 0xd3, 0x0} + } +}; + +UCHAR SiS310_TVPhaseIncr2[3][2][4] = { + { + {0x21, 0xF0, 0x7b, 0xd6}, + {0x21, 0xF0, 0x7b, 0xd6} + } + , + { + {0x2a, 0x09, 0x86, 0xe9}, + {0x2a, 0x09, 0x86, 0xe9} + } + , + { + {0x2a, 0x5, 0xd3, 0x0}, + {0x2a, 0x5, 0xd3, 0x0} + } +}; diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/osdef.h linux/drivers/video/sis/osdef.h --- v2.4.14/linux/drivers/video/sis/osdef.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/osdef.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,37 @@ +#define LINUX_KERNEL + +#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize) +#define SiS_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length) + +/**********************************************************************/ + +#ifdef OutPortByte +#undef OutPortByte +#endif /* OutPortByte */ + +#ifdef OutPortWord +#undef OutPortWord +#endif /* OutPortWord */ + +#ifdef OutPortLong +#undef OutPortLong +#endif /* OutPortLong */ + +#ifdef InPortByte +#undef InPortByte +#endif /* InPortByte */ + +#ifdef InPortWord +#undef InPortWord +#endif /* InPortWord */ + +#ifdef InPortLong +#undef InPortLong +#endif /* InPortLong */ + +#define OutPortByte(p,v) outb((u8)(v),(u16)(p)) +#define OutPortWord(p,v) outw((u16)(v),(u16)(p)) +#define OutPortLong(p,v) outl((u32)(v),(u16)(p)) +#define InPortByte(p) inb((u16)(p)) +#define InPortWord(p) inw((u16)(p)) +#define InPortLong(p) inl((u16)(p)) diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/sis.h linux/drivers/video/sis/sis.h --- v2.4.14/linux/drivers/video/sis/sis.h Wed Nov 8 17:15:04 2000 +++ linux/drivers/video/sis/sis.h Wed Dec 31 16:00:00 1969 @@ -1,64 +0,0 @@ -#ifndef _SISFB_LOCAL -#define _SISFB_LOCAL -#include <linux/types.h> - -#undef NOBIOS -#undef CONFIG_FB_SIS_LINUXBIOS - -#ifdef NOBIOS -#undef CONFIG_FB_SIS_LINUXBIOS -#endif - -#define TRUE 1 -#define FALSE 0 -#define NO_ERROR 0 - -/* Data type conversion */ -#define UCHAR unsigned char -#define USHORT unsigned short -#define ULONG unsigned long -#define SHORT short -#define BOOLEAN int -#define VOID void - -#define IND_SIS_CRT2_PORT_04 0x04 - 0x30 -#define IND_SIS_CRT2_PORT_10 0x10 - 0x30 -#define IND_SIS_CRT2_PORT_12 0x12 - 0x30 -#define IND_SIS_CRT2_PORT_14 0x14 - 0x30 - -#define ClearALLBuffer(x) ClearBuffer(x) - -/* Data struct for setmode codes */ -typedef enum _CHIP_TYPE { - SIS_GENERIC = 0, - SIS_Glamour, //300 - SIS_Trojan, //630 - SIS_Spartan, //540 - SIS_730, - MAX_SIS_CHIP -} CHIP_TYPE; - -typedef enum _LCD_TYPE { - LCD1024 = 1, - LCD1280, - LCD2048, - LCD1920, - LCD1600, - LCD800, - LCD640 -} LCD_TYPE; - - -typedef struct _HW_DEVICE_EXTENSION -{ - unsigned long VirtualRomBase; - char *VirtualVideoMemoryAddress; - unsigned short IOAddress; - CHIP_TYPE jChipID; - int bIntegratedMMEnabled; - LCD_TYPE usLCDType; - u8 revision_id; - u8 uVBChipID; -} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION; - -#endif diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/sis_300.c linux/drivers/video/sis/sis_300.c --- v2.4.14/linux/drivers/video/sis/sis_300.c Sun Nov 12 20:40:42 2000 +++ linux/drivers/video/sis/sis_300.c Wed Dec 31 16:00:00 1969 @@ -1,1524 +0,0 @@ -/* Recently Update by v1.09.50 */ -#include <linux/config.h> -#include "sis_300.h" - -#if defined(ALLOC_PRAGMA) -#pragma alloc_text(PAGE,SiSSetMode) -#pragma alloc_text(PAGE,SiSInit300) -#endif - - -#ifdef NOBIOS -BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase; - ULONG FBAddr = (ULONG)HwDeviceExtension->VirtualVideoMemoryAddress; - USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; - UCHAR i,temp,AGP; - ULONG j,k,ulTemp; - UCHAR SR07,SR11,SR19,SR1A,SR1F,SR21,SR22,SR23,SR24,SR25,SR32; - UCHAR SR14; - ULONG Temp; - - if(ROMAddr==0) return (FALSE); - if(FBAddr==0) return (FALSE); - if(BaseAddr==0) return (FALSE); - if(HwDeviceExtension->jChipID >= SIS_Trojan) - if(!HwDeviceExtension->bIntegratedMMEnabled) return (FALSE); - - P3c4=BaseAddr+0x14; - P3d4=BaseAddr+0x24; - P3c0=BaseAddr+0x10; - P3ce=BaseAddr+0x1e; - P3c2=BaseAddr+0x12; - P3ca=BaseAddr+0x1a; - P3c6=BaseAddr+0x16; - P3c7=BaseAddr+0x17; - P3c8=BaseAddr+0x18; - P3c9=BaseAddr+0x19; - P3da=BaseAddr+0x2A; - Set_LVDS_TRUMPION(); - - SetReg1(P3c4,0x05,0x86); // 1.Openkey - SR14 = (UCHAR)GetReg1(P3c4,0x14); - SR19 = (UCHAR)GetReg1(P3c4,0x19); - SR1A = (UCHAR)GetReg1(P3c4,0x1A); - for(i=0x06;i< 0x20;i++) SetReg1(P3c4,i,0); // 2.Reset Extended register - for(i=0x21;i<=0x27;i++) SetReg1(P3c4,i,0); // Reset Extended register - for(i=0x31;i<=0x3D;i++) SetReg1(P3c4,i,0); - for(i=0x30;i<=0x37;i++) SetReg1(P3d4,i,0); - - if(HwDeviceExtension->jChipID >= SIS_Trojan) - temp=(UCHAR)SR1A; // 3.Set Define Extended register - else - { - temp=*((UCHAR *)(ROMAddr+SoftSettingAddr)); - if((temp&SoftDRAMType)==0){ - temp=(UCHAR)GetReg1(P3c4,0x3A); // 3.Set Define Extended register - } - } - RAMType=temp&0x07; - SetMemoryClock(ROMAddr); - for(k=0; k<5; k++) - { - for(j=0; j<0xffff; j++) - { - ulTemp = (ULONG)GetReg1(P3c4, 0x05); - } - } - Temp = (ULONG)GetReg1(P3c4, 0x3C); - Temp = Temp | 0x01; - SetReg1(P3c4, 0x3C, (USHORT)Temp); - for(k=0; k<5; k++) - { - for(j=0; j<0xffff; j++) - { - Temp = (ULONG)GetReg1(P3c4, 0x05); - } - } - Temp = (ULONG)GetReg1(P3c4, 0x3C); - Temp = Temp & 0xFE; - SetReg1(P3c4, 0x3C, (USHORT)Temp); - for(k=0; k<5; k++) - { - for(j=0; j<0xffff; j++) - { - Temp = (ULONG)GetReg1(P3c4, 0x05); - } - } - - SR07=*((UCHAR *)(ROMAddr+0xA4)); - SetReg1(P3c4,0x07,SR07); - if (HwDeviceExtension->jChipID == SIS_Glamour ) - { - for(i=0x15;i<=0x1C;i++) - { - temp=*((UCHAR *)(ROMAddr+0xA5+((i-0x15)*8)+RAMType)); - SetReg1(P3c4,i,temp); - } - } - - SR1F=*((UCHAR *)(ROMAddr+0xE5)); - SetReg1(P3c4,0x1F,SR1F); - - AGP=1; // Get AGP - temp=(UCHAR)GetReg1(P3c4,0x3A); - temp=temp&0x30; - if(temp==0x30) AGP=0; // PCI - - SR21=*((UCHAR *)(ROMAddr+0xE6)); - if(AGP==0) SR21=SR21&0xEF; // PCI - SetReg1(P3c4,0x21,SR21); - - SR22=*((UCHAR *)(ROMAddr+0xE7)); - if(AGP==1) SR22=SR22&0x20; // AGP - SetReg1(P3c4,0x22,SR22); - - SR23=*((UCHAR *)(ROMAddr+0xE8)); - SetReg1(P3c4,0x23,SR23); - - SR24=*((UCHAR *)(ROMAddr+0xE9)); - SetReg1(P3c4,0x24,SR24); - - SR25=*((UCHAR *)(ROMAddr+0xEA)); - SetReg1(P3c4,0x25,SR25); - - SR32=*((UCHAR *)(ROMAddr+0xEB)); - SetReg1(P3c4,0x32,SR32); - - SR11=0x0F; - SetReg1(P3c4,0x11,SR11); - - if(IF_DEF_LVDS==1){ //LVDS - temp=ExtChipLVDS; - }else if(IF_DEF_TRUMPION==1){ //Trumpion - temp=ExtChipTrumpion; - }else{ //301 - temp=ExtChip301; - } - SetReg1(P3d4,0x37,temp); - - //For SiS 630/540 Chip - //Restore SR14, SR19 and SR1A - SetReg1(P3c4,0x14,SR14); - SetReg1(P3c4,0x19,SR19); - SetReg1(P3c4,0x1A,SR1A); - - SetReg3(P3c6,0xff); // Reset register - ClearDAC(P3c8); // Reset register - DetectMonitor(HwDeviceExtension); //sense CRT1 - GetSenseStatus(HwDeviceExtension,BaseAddr,ROMAddr);//sense CRT2 - - return(TRUE); -} - -VOID Set_LVDS_TRUMPION(VOID) -{ - IF_DEF_LVDS=0; - IF_DEF_TRUMPION=0; -} - -VOID SetMemoryClock(ULONG ROMAddr) -{ - UCHAR data,i; - - MCLKData=*((USHORT *)(ROMAddr+0x20C)); // MCLKData Table - MCLKData=MCLKData+RAMType*5; - ECLKData=MCLKData+0x28; - - for(i=0x28;i<=0x2A;i++) { // Set MCLK - data=*((UCHAR *)(ROMAddr+MCLKData)); - SetReg1(P3c4,i,data); - MCLKData++; - } - - for(i=0x2E;i<=0x30;i++) { // Set ECLK - data=*((UCHAR *)(ROMAddr+ECLKData)); - SetReg1(P3c4,i,data); - ECLKData++; - } -} -#endif /* NOBIOS */ - -#ifdef CONFIG_FB_SIS_LINUXBIOS -BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - ULONG ROMAddr = 0; - USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; - UCHAR i,temp,AGP; - ULONG j,k,ulTemp; - UCHAR SR07,SR11,SR19,SR1A,SR1F,SR21,SR22,SR23,SR24,SR25,SR32; - UCHAR SR14; - ULONG Temp; - - if(BaseAddr==0) return (FALSE); - if(HwDeviceExtension->jChipID >= SIS_Trojan) - if(!HwDeviceExtension->bIntegratedMMEnabled) return (FALSE); - - P3c4=BaseAddr+0x14; - P3d4=BaseAddr+0x24; - P3c0=BaseAddr+0x10; - P3ce=BaseAddr+0x1e; - P3c2=BaseAddr+0x12; - P3ca=BaseAddr+0x1a; - P3c6=BaseAddr+0x16; - P3c7=BaseAddr+0x17; - P3c8=BaseAddr+0x18; - P3c9=BaseAddr+0x19; - P3da=BaseAddr+0x2A; - - SetReg1(P3c4,0x05,0x86); // 1.Openkey - - SR14 = (UCHAR)GetReg1(P3c4,0x14); - SR19 = (UCHAR)GetReg1(P3c4,0x19); - SR1A = (UCHAR)GetReg1(P3c4,0x1A); - - for(i=0x06;i< 0x20;i++) SetReg1(P3c4,i,0); // 2.Reset Extended register - for(i=0x21;i<=0x27;i++) SetReg1(P3c4,i,0); // Reset Extended register - for(i=0x31;i<=0x3D;i++) SetReg1(P3c4,i,0); - for(i=0x30;i<=0x37;i++) SetReg1(P3d4,i,0); - - temp=(UCHAR)SR1A; // 3.Set Define Extended register - - RAMType=temp&0x07; - SetMemoryClock(ROMAddr); - for(k=0; k<5; k++) - for(j=0; j<0xffff; j++) - ulTemp = (ULONG)GetReg1(P3c4, 0x05); - - Temp = (ULONG)GetReg1(P3c4, 0x3C); - Temp = Temp | 0x01; - SetReg1(P3c4, 0x3C, (USHORT)Temp); - - for(k=0; k<5; k++) - for(j=0; j<0xffff; j++) - Temp = (ULONG)GetReg1(P3c4, 0x05); - - Temp = (ULONG)GetReg1(P3c4, 0x3C); - Temp = Temp & 0xFE; - SetReg1(P3c4, 0x3C, (USHORT)Temp); - - for(k=0; k<5; k++) - for(j=0; j<0xffff; j++) - Temp = (ULONG)GetReg1(P3c4, 0x05); - - SR07=SRegsInit[0x07]; - SetReg1(P3c4,0x07,SR07); - - SR1F=SRegsInit[0x1F]; - SetReg1(P3c4,0x1F,SR1F); - - AGP=1; // Get AGP - temp=(UCHAR)GetReg1(P3c4,0x3A); - temp=temp&0x30; - if(temp==0x30) AGP=0; // PCI - - SR21=SRegsInit[0x21]; - if(AGP==0) SR21=SR21&0xEF; // PCI - SetReg1(P3c4,0x21,SR21); - - SR22=SRegsInit[0x22]; - if(AGP==1) SR22=SR22&0x20; // AGP - SetReg1(P3c4,0x22,SR22); - - SR23=SRegsInit[0x23]; - SetReg1(P3c4,0x23,SR23); - - SR24=SRegsInit[0x24]; - SetReg1(P3c4,0x24,SR24); - - SR25=SRegsInit[0x25]; - SetReg1(P3c4,0x25,SR25); - - SR32=SRegsInit[0x32]; - SetReg1(P3c4,0x32,SR32); - - SR11=0x0F; - SetReg1(P3c4,0x11,SR11); - - temp=ExtChip301; - SetReg1(P3d4,0x37,temp); - - SetReg1(P3c4,0x14,SR14); - SetReg1(P3c4,0x19,SR19); - SetReg1(P3c4,0x1A,SR1A); - - SetReg3(P3c6,0xff); // Reset register - ClearDAC(P3c8); // Reset register - DetectMonitor(HwDeviceExtension); //sense CRT1 - - return(TRUE); -} - -VOID SetMemoryClock(ULONG ROMAddr) -{ - UCHAR i; - USHORT idx; - - u8 MCLK[] = { - 0x5A, 0x64, 0x80, 0x66, 0x00, // SDRAM - 0xB3, 0x45, 0x80, 0x83, 0x00, // SGRAM - 0x37, 0x61, 0x80, 0x00, 0x01, // ESDRAM - 0x37, 0x22, 0x80, 0x33, 0x01, - 0x37, 0x61, 0x80, 0x00, 0x01, - 0x37, 0x61, 0x80, 0x00, 0x01, - 0x37, 0x61, 0x80, 0x00, 0x01, - 0x37, 0x61, 0x80, 0x00, 0x01 - }; - - u8 ECLK[] = { - 0x54, 0x43, 0x80, 0x00, 0x01, - 0x53, 0x43, 0x80, 0x00, 0x01, - 0x55, 0x43, 0x80, 0x00, 0x01, - 0x52, 0x43, 0x80, 0x00, 0x01, - 0x3f, 0x42, 0x80, 0x00, 0x01, - 0x54, 0x43, 0x80, 0x00, 0x01, - 0x54, 0x43, 0x80, 0x00, 0x01, - 0x54, 0x43, 0x80, 0x00, 0x01 - }; - - idx = RAMType * 5; - - for (i = 0x28; i <= 0x2A; i++) { // Set MCLK - SetReg1(P3c4, i, MCLK[idx]); - idx++; - } - - idx = RAMType * 5; - for (i = 0x2E; i <= 0x30; i++) { // Set ECLK - SetReg1(P3c4, i, ECLK[idx]); - idx++; - } - -} - -#endif /* CONFIG_FB_SIS_LINUXBIOS */ - -// ========================================= -// ======== SiS SetMode Function ========== -// ========================================= - -#ifdef CONFIG_FB_SIS_LINUXBIOS -BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, - USHORT ModeNo) -{ - ULONG i; - USHORT cr30flag,cr31flag; - ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase; - USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; - - P3c4=BaseAddr+0x14; - P3d4=BaseAddr+0x24; - P3c0=BaseAddr+0x10; - P3ce=BaseAddr+0x1e; - P3c2=BaseAddr+0x12; - P3ca=BaseAddr+0x1a; - P3c6=BaseAddr+0x16; - P3c7=BaseAddr+0x17; - P3c8=BaseAddr+0x18; - P3c9=BaseAddr+0x19; - P3da=BaseAddr+0x2A; - - cr30flag=(UCHAR)GetReg1(P3d4,0x30); - - if(((cr30flag&0x01)==1)||((cr30flag&0x02)==0)){ - SetReg1(P3d4,0x34,ModeNo); - //SetSeqRegs(ROMAddr); - { - UCHAR SRdata; - SRdata = SRegs[0x01] | 0x20; - SetReg1(P3c4, 0x01, SRdata); - - for (i = 02; i <= 04; i++) - SetReg1(P3c4, i, SRegs[i]); - } - - //SetMiscRegs(ROMAddr); - { - SetReg3(P3c2, 0x23); - } - - //SetCRTCRegs(ROMAddr); - { - UCHAR CRTCdata; - - CRTCdata = (UCHAR) GetReg1(P3d4, 0x11); - SetReg1(P3d4, 0x11, CRTCdata); - - for (i = 0; i <= 0x18; i++) - SetReg1(P3d4, i, CRegs[i]); - } - - //SetATTRegs(ROMAddr); - { - for (i = 0; i <= 0x13; i++) { - GetReg2(P3da); - SetReg3(P3c0, i); - SetReg3(P3c0, ARegs[i]); - } - GetReg2(P3da); - SetReg3(P3c0, 0x14); - SetReg3(P3c0, 0x00); - GetReg2(P3da); - SetReg3(P3c0, 0x20); - } - - //SetGRCRegs(ROMAddr); - { - for (i = 0; i <= 0x08; i++) - SetReg1(P3ce, i, GRegs[i]); - } - - //ClearExt1Regs(); - { - for (i = 0x0A; i <= 0x0E; i++) - SetReg1(P3c4, i, 0x00); - } - - - //SetSync(ROMAddr); - { - SetReg3(P3c2, MReg); - } - - //SetCRT1CRTC(ROMAddr); - { - UCHAR data; - - data = (UCHAR) GetReg1(P3d4, 0x11); - data = data & 0x7F; - SetReg1(P3d4, 0x11, data); - - for (i = 0; i <= 0x07; i++) - SetReg1(P3d4, i, CRegs[i]); - for (i = 0x10; i <= 0x12; i++) - SetReg1(P3d4, i, CRegs[i]); - for (i = 0x15; i <= 0x16; i++) - SetReg1(P3d4, i, CRegs[i]); - for (i = 0x0A; i <= 0x0C; i++) - SetReg1(P3c4, i, SRegs[i]); - - data = SRegs[0x0E] & 0xE0; - SetReg1(P3c4, 0x0E, data); - - SetReg1(P3d4, 0x09, CRegs[0x09]); - } - - //SetCRT1Offset(ROMAddr); - { - SetReg1(P3c4, 0x0E, SRegs[0x0E]); - SetReg1(P3c4, 0x10, SRegs[0x10]); - } - - //SetCRT1VCLK(HwDeviceExtension, ROMAddr); - { - SetReg1(P3c4, 0x31, 0); - - for (i = 0x2B; i <= 0x2C; i++) - SetReg1(P3c4, i, SRegs[i]); - SetReg1(P3c4, 0x2D, 0x80); - } - - //SetVCLKState(HwDeviceExtension, ROMAddr, ModeNo); - { - SetReg1(P3c4, 0x32, SRegs[0x32]); - SetReg1(P3c4, 0x07, SRegs[0x07]); - } - - //SetCRT1FIFO2(ROMAddr); - { - SetReg1(P3c4, 0x15, SRegs[0x15]); - - SetReg4(0xcf8, 0x80000050); - SetReg4(0xcfc, 0xc5041e04); - - SetReg1(P3c4, 0x08, SRegs[0x08]); - SetReg1(P3c4, 0x0F, SRegs[0x0F]); - SetReg1(P3c4, 0x3b, 0x00); - SetReg1(P3c4, 0x09, SRegs[0x09]); - } - - //SetCRT1ModeRegs(ROMAddr, ModeNo); - { - SetReg1(P3c4, 0x06, SRegs[0x06]); - SetReg1(P3c4, 0x01, SRegs[0x01]); - SetReg1(P3c4, 0x0F, SRegs[0x0F]); - SetReg1(P3c4, 0x21, SRegs[0x21]); - } - - if(HwDeviceExtension->jChipID >= SIS_Trojan) - { - //SetInterlace(ROMAddr,ModeNo); - SetReg1(P3d4, 0x19, CRegs[0x19]); - SetReg1(P3d4, 0x1A, CRegs[0x1A]); - } - - LoadDAC(ROMAddr); - - ClearBuffer(HwDeviceExtension); - } - - cr31flag=(UCHAR)GetReg1(P3d4,0x31); - DisplayOn(); // 16.DisplayOn - return(NO_ERROR); -} - -VOID LoadDAC(ULONG ROMAddr) -{ - USHORT data,data2; - USHORT time,i,j,k; - USHORT m,n,o; - USHORT si,di,bx,dl; - USHORT al,ah,dh; - USHORT *table=VGA_DAC; - - time=256; - table=VGA_DAC; - j=16; - - SetReg3(P3c6,0xFF); - SetReg3(P3c8,0x00); - - for(i=0;i<j;i++) { - data=table[i]; - for(k=0;k<3;k++) { - data2=0; - if(data&0x01) data2=0x2A; - if(data&0x02) data2=data2+0x15; - SetReg3(P3c9,data2); - data=data>>2; - } - } - - if(time==256) { - for(i=16;i<32;i++) { - data=table[i]; - for(k=0;k<3;k++) SetReg3(P3c9,data); - } - si=32; - for(m=0;m<9;m++) { - di=si; - bx=si+0x04; - dl=0; - for(n=0;n<3;n++) { - for(o=0;o<5;o++) { - dh=table[si]; - ah=table[di]; - al=table[bx]; - si++; - WriteDAC(dl,ah,al,dh); - } - si=si-2; - for(o=0;o<3;o++) { - dh=table[bx]; - ah=table[di]; - al=table[si]; - si--; - WriteDAC(dl,ah,al,dh); - } - dl++; - } - si=si+5; - } - } -} - -VOID WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh) -{ - USHORT temp; - USHORT bh,bl; - - bh=ah; - bl=al; - if(dl!=0) { - temp=bh; - bh=dh; - dh=temp; - if(dl==1) { - temp=bl; - bl=dh; - dh=temp; - } - else { - temp=bl; - bl=bh; - bh=temp; - } - } - SetReg3(P3c9,(USHORT)dh); - SetReg3(P3c9,(USHORT)bh); - SetReg3(P3c9,(USHORT)bl); -} - - -VOID DisplayOn() -{ - USHORT data; - - data=GetReg1(P3c4,0x01); - data=data&0xDF; - SetReg1(P3c4,0x01,data); -} - - -#else -BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, - USHORT ModeNo) -{ - ULONG temp; - USHORT cr30flag,cr31flag; - ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase; - USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress; - - P3c4=BaseAddr+0x14; - P3d4=BaseAddr+0x24; - P3c0=BaseAddr+0x10; - P3ce=BaseAddr+0x1e; - P3c2=BaseAddr+0x12; - P3ca=BaseAddr+0x1a; - P3c6=BaseAddr+0x16; - P3c7=BaseAddr+0x17; - P3c8=BaseAddr+0x18; - P3c9=BaseAddr+0x19; - P3da=BaseAddr+0x2A; - if(ModeNo&0x80){ - ModeNo=ModeNo&0x7F; - flag_clearbuffer=0; - }else{ - flag_clearbuffer=1; - } - - PresetScratchregister(P3d4,HwDeviceExtension); //add for CRT2 - - SetReg1(P3c4,0x05,0x86); // 1.Openkey - temp=SearchModeID(ROMAddr,ModeNo); // 2.Get ModeID Table - if(temp==0) return(0); - - SetTVSystem(HwDeviceExtension,ROMAddr); //add for CRT2 - GetLCDDDCInfo(HwDeviceExtension); //add for CRT2 - GetVBInfo(BaseAddr,ROMAddr); //add for CRT2 - GetLCDResInfo(ROMAddr,P3d4); //add for CRT2 - - temp=CheckMemorySize(ROMAddr); // 3.Check memory size - if(temp==0) return(0); - cr30flag=(UCHAR)GetReg1(P3d4,0x30); - if(((cr30flag&0x01)==1)||((cr30flag&0x02)==0)){ - // if cr30 d[0]=1 or d[1]=0 set crt1 - SetReg1(P3d4,0x34,ModeNo); - // set CR34->CRT1 ModeNofor CRT2 FIFO - GetModePtr(ROMAddr,ModeNo); // 4.GetModePtr - SetSeqRegs(ROMAddr); // 5.SetSeqRegs - SetMiscRegs(ROMAddr); // 6.SetMiscRegs - SetCRTCRegs(ROMAddr); // 7.SetCRTCRegs - SetATTRegs(ROMAddr); // 8.SetATTRegs - SetGRCRegs(ROMAddr); // 9.SetGRCRegs - ClearExt1Regs(); // 10.Clear Ext1Regs - temp=GetRatePtr(ROMAddr,ModeNo); // 11.GetRatePtr - if(temp) { - SetSync(ROMAddr); // 12.SetSync - SetCRT1CRTC(ROMAddr); // 13.SetCRT1CRTC - SetCRT1Offset(ROMAddr); // 14.SetCRT1Offset - SetCRT1VCLK(HwDeviceExtension, ROMAddr); // 15.SetCRT1VCLK - SetVCLKState(HwDeviceExtension, ROMAddr, ModeNo); - if(HwDeviceExtension->jChipID >= SIS_Trojan) - SetCRT1FIFO2(ROMAddr); - else - SetCRT1FIFO(ROMAddr); - } - SetCRT1ModeRegs(ROMAddr, ModeNo); - if(HwDeviceExtension->jChipID >= SIS_Trojan) - SetInterlace(ROMAddr,ModeNo); - LoadDAC(ROMAddr); - if(flag_clearbuffer) ClearBuffer(HwDeviceExtension); - } - - cr31flag=(UCHAR)GetReg1(P3d4,0x31); - if(((cr30flag&0x01)==1)||((cr30flag&0x03)==0x02) - ||(((cr30flag&0x03)==0x00)&&((cr31flag&0x20)==0x20))){ - //if CR30 d[0]=1 or d[1:0]=10, set CRT2 or cr30 cr31== 0x00 0x20 - SetCRT2Group(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension); //CRT2 - } - DisplayOn(); // 16.DisplayOn - return(NO_ERROR); -} - -BOOLEAN SearchModeID(ULONG ROMAddr, USHORT ModeNo) -{ - UCHAR ModeID; - USHORT usIDLength; - - ModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable - ModeID=*((UCHAR *)(ROMAddr+ModeIDOffset)); // Offset 0x20A - usIDLength = GetModeIDLength(ROMAddr, ModeNo); - while(ModeID!=0xff && ModeID!=ModeNo) { - ModeIDOffset=ModeIDOffset+usIDLength; - ModeID=*((UCHAR *)(ROMAddr+ModeIDOffset)); - } - if(ModeID==0xff) return(FALSE); - else return(TRUE); -} - -BOOLEAN CheckMemorySize(ULONG ROMAddr) -{ - USHORT memorysize; - USHORT modeflag; - USHORT temp; - - modeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - ModeType=modeflag&ModeInfoFlag; // Get mode type - - memorysize=modeflag&MemoryInfoFlag; - memorysize=memorysize>MemorySizeShift; - memorysize++; // Get memory size - - temp=GetReg1(P3c4,0x14); // Get DRAM Size - temp=temp&0x3F; - temp++; - - if(temp<memorysize) return(FALSE); - else return(TRUE); -} - -VOID GetModePtr(ULONG ROMAddr, USHORT ModeNo) -{ - UCHAR index; - - StandTable=*((USHORT *)(ROMAddr+0x202)); // Get First 0x202 - // StandTable Offset - if(ModeNo<=13) { - index=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+St_ModeFlag - } - else { - if(ModeType <= 0x02) index=0x1B; // 02 -> ModeEGA - else index=0x0F; - } - - StandTable=StandTable+64*index; // Get ModeNo StandTable - -} - -VOID SetSeqRegs(ULONG ROMAddr) -{ - UCHAR SRdata; - USHORT i; - - SetReg1(P3c4,0x00,0x03); // Set SR0 - StandTable=StandTable+0x05; - SRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get SR01 from file - if(IF_DEF_LVDS==1){ - if(VBInfo&SetCRT2ToLCD){ - if(VBInfo&SetInSlaveMode){ - if(LCDInfo&LCDNonExpanding){ - SRdata=SRdata|0x01; - } - } - } - } - - SRdata=SRdata|0x20; - SetReg1(P3c4,0x01,SRdata); // Set SR1 - for(i=02;i<=04;i++) { - StandTable++; - SRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get SR2,3,4 from file - SetReg1(P3c4,i,SRdata); // Set SR2 3 4 - } -} - -VOID SetMiscRegs(ULONG ROMAddr) -{ - UCHAR Miscdata; - - StandTable++; - Miscdata=*((UCHAR *)(ROMAddr+StandTable)); // Get Misc from file - SetReg3(P3c2,Miscdata); // Set Misc(3c2) -} - -VOID SetCRTCRegs(ULONG ROMAddr) -{ - UCHAR CRTCdata; - USHORT i; - - CRTCdata=(UCHAR)GetReg1(P3d4,0x11); - CRTCdata=CRTCdata&0x7f; - SetReg1(P3d4,0x11,CRTCdata); // Unlock CRTC - - for(i=0;i<=0x18;i++) { - StandTable++; - CRTCdata=*((UCHAR *)(ROMAddr+StandTable)); // Get CRTC from file - SetReg1(P3d4,i,CRTCdata); // Set CRTC(3d4) - } -} - -VOID SetATTRegs(ULONG ROMAddr) -{ - UCHAR ARdata; - USHORT i; - - for(i=0;i<=0x13;i++) { - StandTable++; - ARdata=*((UCHAR *)(ROMAddr+StandTable)); // Get AR for file - if(IF_DEF_LVDS==1){ //for LVDS - if(VBInfo&SetCRT2ToLCD){ - if(VBInfo&SetInSlaveMode){ - if(LCDInfo&LCDNonExpanding){ - if(i==0x13){ - ARdata=0; - } - } - } - } - } - GetReg2(P3da); // reset 3da - SetReg3(P3c0,i); // set index - SetReg3(P3c0,ARdata); // set data - } - if(IF_DEF_LVDS==1){ //for LVDS - if(VBInfo&SetCRT2ToLCD){ - if(VBInfo&SetInSlaveMode){ - if(LCDInfo&LCDNonExpanding){ - - } - } - } - } - GetReg2(P3da); // reset 3da - SetReg3(P3c0,0x14); // set index - SetReg3(P3c0,0x00); // set data - - GetReg2(P3da); // Enable Attribute - SetReg3(P3c0,0x20); -} - -VOID SetGRCRegs(ULONG ROMAddr) -{ - UCHAR GRdata; - USHORT i; - - for(i=0;i<=0x08;i++) { - StandTable++; - GRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get GR from file - SetReg1(P3ce,i,GRdata); // Set GR(3ce) - } - if(ModeType>ModeVGA){ - GRdata=(UCHAR)GetReg1(P3ce,0x05); - GRdata=GRdata&0xBF; - SetReg1(P3ce,0x05,GRdata); - } -} - -VOID ClearExt1Regs() -{ - USHORT i; - - for(i=0x0A;i<=0x0E;i++) SetReg1(P3c4,i,0x00); // Clear SR0A-SR0E -} - - -BOOLEAN GetRatePtr(ULONG ROMAddr, USHORT ModeNo) -{ - SHORT index; - USHORT temp; - USHORT ulRefIndexLength; - - if(ModeNo<0x14) return(FALSE); // Mode No <= 13h then return - - index=GetReg1(P3d4,0x33); // Get 3d4 CRTC33 - index=index&0x0F; // Frame rate index - if(index!=0) index--; - REFIndex=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point - - ulRefIndexLength = GetRefindexLength(ROMAddr, ModeNo); - do { - temp=*((USHORT *)(ROMAddr+REFIndex)); // di => REFIndex - if(temp==0xFFFF) break; - temp=temp&ModeInfoFlag; - if(temp<ModeType) break; - - REFIndex=REFIndex+ulRefIndexLength; // rate size - index--; - } while(index>=0); - - REFIndex=REFIndex-ulRefIndexLength; // rate size - return(TRUE); -} - -VOID SetSync(ULONG ROMAddr) -{ - USHORT sync; - USHORT temp; - - sync=*((USHORT *)(ROMAddr+REFIndex)); // di+0x00 - sync=sync&0xC0; - temp=0x2F; - temp=temp|sync; - SetReg3(P3c2,temp); // Set Misc(3c2) -} - -VOID SetCRT1CRTC(ULONG ROMAddr) -{ - UCHAR index; - UCHAR data; - USHORT i; - - index=*((UCHAR *)(ROMAddr+REFIndex+0x02)); // Get index - index=index&0x03F; - CRT1Table=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table - CRT1Table=CRT1Table+index*CRT1Len; - - data=(UCHAR)GetReg1(P3d4,0x11); - data=data&0x7F; - SetReg1(P3d4,0x11,data); // Unlock CRTC - - CRT1Table--; - for(i=0;i<=0x05;i++) { - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - SetReg1(P3d4,i,data); - } - for(i=0x06;i<=0x07;i++) { - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - SetReg1(P3d4,i,data); - } - for(i=0x10;i<=0x12;i++) { - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - SetReg1(P3d4,i,data); - } - for(i=0x15;i<=0x16;i++) { - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - SetReg1(P3d4,i,data); - } - for(i=0x0A;i<=0x0C;i++) { - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - SetReg1(P3c4,i,data); - } - - CRT1Table++; - data=*((UCHAR *)(ROMAddr+CRT1Table)); - data=data&0xE0; - SetReg1(P3c4,0x0E,data); - - data=(UCHAR)GetReg1(P3d4,0x09); - data=data&0xDF; - i=*((UCHAR *)(ROMAddr+CRT1Table)); - i=i&0x01; - i=i<<5; - data=data|i; - i=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); - i=i&DoubleScanMode; - if(i) data=data|0x80; - SetReg1(P3d4,0x09,data); - - if(ModeType>0x03) SetReg1(P3d4,0x14,0x4F); -} - -VOID SetCRT1Offset(ULONG ROMAddr) -{ - USHORT temp,ah,al; - USHORT temp2,i; - USHORT DisplayUnit; - - temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+Ext_ModeInfo - temp=temp>>4; // index - ScreenOffset=*((USHORT *)(ROMAddr+0x206)); // ScreenOffset - temp=*((UCHAR *)(ROMAddr+ScreenOffset+temp)); // data - - temp2=*((USHORT *)(ROMAddr+REFIndex+0x00)); - temp2=temp2&InterlaceMode; - if(temp2) temp=temp<<1; - temp2=ModeType-ModeEGA; - switch (temp2) { - case 0 : temp2=1; break; - case 1 : temp2=2; break; - case 2 : temp2=4; break; - case 3 : temp2=4; break; - case 4 : temp2=6; break; - case 5 : temp2=8; break; - } - temp=temp*temp2; - DisplayUnit=temp; - - temp2=temp; - temp=temp>>8; - temp=temp&0x0F; - i=GetReg1(P3c4,0x0E); - i=i&0xF0; - i=i|temp; - SetReg1(P3c4,0x0E,i); - - temp=(UCHAR)temp2; - temp=temp&0xFF; - SetReg1(P3d4,0x13,temp); - - temp2=*((USHORT *)(ROMAddr+REFIndex+0x00)); - temp2=temp2&InterlaceMode; - if(temp2) DisplayUnit>>=1; - - DisplayUnit=DisplayUnit<<5; - ah=(DisplayUnit&0xff00)>>8; - al=DisplayUnit&0x00ff; - if(al==0) ah=ah+1; - else ah=ah+2; - SetReg1(P3c4,0x10,ah); -} - - -VOID SetCRT1VCLK(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr) -{ - USHORT i; - UCHAR index,data; - - index=*((UCHAR *)(ROMAddr+REFIndex+0x03)); - index=index&0x03F; - CRT1VCLKLen=GetVCLKLen(ROMAddr); - data=index*CRT1VCLKLen; - VCLKData=*((USHORT *)(ROMAddr+0x208)); - VCLKData=VCLKData+data; - - SetReg1(P3c4,0x31,0); - for(i=0x2B;i<=0x2C;i++) { - data=*((UCHAR *)(ROMAddr+VCLKData)); - SetReg1(P3c4,i,data); - VCLKData++; - } - SetReg1(P3c4,0x2D,0x80); -} - - -VOID SetCRT1ModeRegs(ULONG ROMAddr, USHORT ModeNo) -{ - - USHORT data,data2,data3; - - if(ModeNo>0x13) data=*((USHORT *)(ROMAddr+REFIndex+0x00)); - else data=0; - - data2=0; - if(ModeNo>0x13) - if(ModeType>0x02) { - data2=data2|0x02; - data3=ModeType-ModeVGA; - data3=data3<<2; - data2=data2|data3; - } - - data=data&InterlaceMode; - if(data) data2=data2|0x20; - SetReg1(P3c4,0x06,data2); - - data=GetReg1(P3c4,0x01); - data=data&0xF7; - data2=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); - data2=data2&HalfDCLK; - if(data2) data=data|0x08; - SetReg1(P3c4,0x01,data); - - data=GetReg1(P3c4,0x0F); - data=data&0xF7; - data2=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); - data2=data2&LineCompareOff; - if(data2) data=data|0x08; - SetReg1(P3c4,0x0F,data); - - data=GetReg1(P3c4,0x21); - data=data&0x1F; - if(ModeType==0x00) data=data|0x60; // Text Mode - else if(ModeType<=0x02) data=data|0x00; // EGA Mode - else data=data|0xA0; // VGA Mode - SetReg1(P3c4,0x21,data); -} - -VOID SetVCLKState(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr, USHORT ModeNo) -{ - USHORT data,data2; - USHORT VCLK; - UCHAR index; - - index=*((UCHAR *)(ROMAddr+REFIndex+0x03)); - index=index&0x03F; - CRT1VCLKLen=GetVCLKLen(ROMAddr); - data=index*CRT1VCLKLen; - VCLKData=*((USHORT *)(ROMAddr+0x208)); - VCLKData=VCLKData+data+(CRT1VCLKLen-2); - VCLK=*((USHORT *)(ROMAddr+VCLKData)); - if(ModeNo<=0x13) VCLK=0; - - data=GetReg1(P3c4,0x07); - data=data&0x7B; - if(VCLK>=150) data=data|0x80; // VCLK > 150 - SetReg1(P3c4,0x07,data); - - data=GetReg1(P3c4,0x32); - data=data&0xD7; - if(VCLK>=150) data=data|0x08; // VCLK > 150 - SetReg1(P3c4,0x32,data); - - data2=0x03; - if(VCLK>135) data2=0x02; - if(VCLK>160) data2=0x01; - if(VCLK>260) data2=0x00; - data=GetReg1(P3c4,0x07); - data=data&0xFC; - data=data|data2; - SetReg1(P3c4,0x07,data); -} - -VOID LoadDAC(ULONG ROMAddr) -{ - USHORT data,data2; - USHORT time,i,j,k; - USHORT m,n,o; - USHORT si,di,bx,dl; - USHORT al,ah,dh; - USHORT *table=VGA_DAC; - - data=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); - data=data&DACInfoFlag; - time=64; - if(data==0x00) table=MDA_DAC; - if(data==0x08) table=CGA_DAC; - if(data==0x10) table=EGA_DAC; - if(data==0x18) { - time=256; - table=VGA_DAC; - } - if(time==256) j=16; - else j=time; - - SetReg3(P3c6,0xFF); - SetReg3(P3c8,0x00); - - for(i=0;i<j;i++) { - data=table[i]; - for(k=0;k<3;k++) { - data2=0; - if(data&0x01) data2=0x2A; - if(data&0x02) data2=data2+0x15; - SetReg3(P3c9,data2); - data=data>>2; - } - } - - if(time==256) { - for(i=16;i<32;i++) { - data=table[i]; - for(k=0;k<3;k++) SetReg3(P3c9,data); - } - si=32; - for(m=0;m<9;m++) { - di=si; - bx=si+0x04; - dl=0; - for(n=0;n<3;n++) { - for(o=0;o<5;o++) { - dh=table[si]; - ah=table[di]; - al=table[bx]; - si++; - WriteDAC(dl,ah,al,dh); - } - si=si-2; - for(o=0;o<3;o++) { - dh=table[bx]; - ah=table[di]; - al=table[si]; - si--; - WriteDAC(dl,ah,al,dh); - } - dl++; - } - si=si+5; - } - } -} - -VOID WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh) -{ - USHORT temp; - USHORT bh,bl; - - bh=ah; - bl=al; - if(dl!=0) { - temp=bh; - bh=dh; - dh=temp; - if(dl==1) { - temp=bl; - bl=dh; - dh=temp; - } - else { - temp=bl; - bl=bh; - bh=temp; - } - } - SetReg3(P3c9,(USHORT)dh); - SetReg3(P3c9,(USHORT)bh); - SetReg3(P3c9,(USHORT)bl); -} - - -VOID DisplayOn() -{ - USHORT data; - - data=GetReg1(P3c4,0x01); - data=data&0xDF; - SetReg1(P3c4,0x01,data); -} - -USHORT GetModeIDLength(ULONG ROMAddr, USHORT ModeNo) -{ - USHORT modeidlength; - USHORT usModeIDOffset; - USHORT PreviousWord,CurrentWord; - - modeidlength=0; - usModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable - // maybe = 2Exx or xx2E - CurrentWord=*((USHORT *)(ROMAddr+usModeIDOffset)); // Offset 0x20A - PreviousWord=*((USHORT *)(ROMAddr+usModeIDOffset-2)); // Offset 0x20A - while((CurrentWord!=0x2E07)||(PreviousWord!=0x0801)) { - modeidlength++; - usModeIDOffset=usModeIDOffset+1; // 10 <= ExtStructSize - CurrentWord=*((USHORT *)(ROMAddr+usModeIDOffset)); - PreviousWord=*((USHORT *)(ROMAddr+usModeIDOffset-2)); - } - modeidlength++; - return(modeidlength); -} - -USHORT GetRefindexLength(ULONG ROMAddr, USHORT ModeNo) -{ - UCHAR ModeID; - UCHAR temp; - USHORT refindexlength; - USHORT usModeIDOffset; - USHORT usREFIndex; - USHORT usIDLength; - - usModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable - ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); // Offset 0x20A - usIDLength = GetModeIDLength(ROMAddr, ModeNo); - while(ModeID!=0x40) { - usModeIDOffset=usModeIDOffset+usIDLength; // 10 <= ExtStructSize - ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); - } - - refindexlength=1; - usREFIndex=*((USHORT *)(ROMAddr+usModeIDOffset+0x04)); // si+Ext_point - usREFIndex++; - temp=*((UCHAR *)(ROMAddr+usREFIndex)); // di => REFIndex - while(temp!=0xFF) { - refindexlength++; - usREFIndex++; - temp=*((UCHAR *)(ROMAddr+usREFIndex)); // di => REFIndex - } - return(refindexlength); -} - -VOID SetInterlace(ULONG ROMAddr, USHORT ModeNo) -{ - ULONG Temp; - USHORT data,Temp2; - - Temp = (ULONG)GetReg1(P3d4, 0x01); - Temp++; - Temp=Temp*8; - - if(Temp==1024) data=0x0035; - else if(Temp==1280) data=0x0048; - else data=0x0000; - - Temp2=*((USHORT *)(ROMAddr+REFIndex+0x00)); - Temp2 &= InterlaceMode; - if(Temp2 == 0) data=0x0000; - - SetReg1(P3d4,0x19,data); - - Temp = (ULONG)GetReg1(P3d4, 0x1A); - Temp2= (USHORT)(Temp & 0xFC); - SetReg1(P3d4,0x1A,(USHORT)Temp); - - Temp = (ULONG)GetReg1(P3c4, 0x0f); - Temp2= (USHORT)Temp & 0xBF; - if(ModeNo==0x37) Temp2=Temp2|0x40; - SetReg1(P3d4,0x1A,(USHORT)Temp2); -} - -VOID SetCRT1FIFO(ULONG ROMAddr) -{ - USHORT colorth=0,index,data,VCLK,data2,MCLKOffset,MCLK; - USHORT ah,bl,A,B; - - index=*((UCHAR *)(ROMAddr+REFIndex+0x03)); - index=index&0x03F; - CRT1VCLKLen=GetVCLKLen(ROMAddr); - data=index*CRT1VCLKLen; - VCLKData=*((USHORT *)(ROMAddr+0x208)); - VCLKData=VCLKData+data+(CRT1VCLKLen-2); - VCLK=*((USHORT *)(ROMAddr+VCLKData)); // Get VCLK - - MCLKOffset=*((USHORT *)(ROMAddr+0x20C)); - index=GetReg1(P3c4,0x3A); - index=index&07; - MCLKOffset=MCLKOffset+index*5; - MCLK=*((UCHAR *)(ROMAddr+MCLKOffset+0x03)); // Get MCLK - - data2=ModeType-0x02; - switch (data2) { - case 0 : colorth=1; break; - case 1 : colorth=2; break; - case 2 : colorth=4; break; - case 3 : colorth=4; break; - case 4 : colorth=6; break; - case 5 : colorth=8; break; - } - - do{ - B=(CalcDelay(ROMAddr,0)*VCLK*colorth); - B=B/(16*MCLK); - B++; - - A=(CalcDelay(ROMAddr,1)*VCLK*colorth); - A=A/(16*MCLK); - A++; - - if(A<4) A=0; - else A=A-4; - - if(A>B) bl=A; - else bl=B; - - bl++; - if(bl>0x13) { - data=GetReg1(P3c4,0x16); - data=data>>6; - if(data!=0) { - data--; - data=data<<6; - data2=GetReg1(P3c4,0x16); - data2=(data2&0x3f)|data; - SetReg1(P3c4,0x16,data2); - } - else bl=0x13; - } - } while(bl>0x13); - - ah=bl; - ah=ah<<4; - ah=ah|0x0f; - SetReg1(P3c4,0x08,ah); - - data=bl; - data=data&0x10; - data=data<<1; - data2=GetReg1(P3c4,0x0F); - data2=data2&0x9f; - data2=data2|data; - SetReg1(P3c4,0x0F,data2); - - data=bl+3; - if(data>0x0f) data=0x0f; - SetReg1(P3c4,0x3b,0x00); - data2=GetReg1(P3c4,0x09); - data2=data2&0xF0; - data2=data2|data; - SetReg1(P3c4,0x09,data2); -} - -static USHORT CalcDelay(ULONG ROMAddr,USHORT key) -{ - USHORT data,data2,temp0,temp1; - UCHAR ThLowA[]={61,3,52,5,68,7,100,11, - 43,3,42,5,54,7, 78,11, - 34,3,37,5,47,7, 67,11}; - UCHAR ThLowB[]={81,4,72,6,88,8,120,12, - 55,4,54,6,66,8, 90,12, - 42,4,45,6,55,8, 75,12}; - UCHAR ThTiming[]= {1,2,2,3,0,1,1,2}; - - data=GetReg1(P3c4,0x16); - data=data>>6; - data2=GetReg1(P3c4,0x14); - data2=(data2>>4)&0x0C; - data=data|data2; - data=data<1; - if(key==0) { - temp0=(USHORT)ThLowA[data]; - temp1=(USHORT)ThLowA[data+1]; - } - else { - temp0=(USHORT)ThLowB[data]; - temp1=(USHORT)ThLowB[data+1]; - } - - data2=0; - data=GetReg1(P3c4,0x18); - if(data&0x02) data2=data2|0x01; - if(data&0x20) data2=data2|0x02; - if(data&0x40) data2=data2|0x04; - - data=temp1*ThTiming[data2]+temp0; - return(data); -} - -VOID SetCRT1FIFO2(ULONG ROMAddr) -{ - USHORT colorth=0,index,data,VCLK,data2,MCLKOffset,MCLK; - USHORT ah,bl,B; - ULONG eax; - - index=*((UCHAR *)(ROMAddr+REFIndex+0x03)); - index=index&0x03F; - CRT1VCLKLen=GetVCLKLen(ROMAddr); - data=index*CRT1VCLKLen; - VCLKData=*((USHORT *)(ROMAddr+0x208)); - VCLKData=VCLKData+data+(CRT1VCLKLen-2); - VCLK=*((USHORT *)(ROMAddr+VCLKData)); // Get VCLK - - MCLKOffset=*((USHORT *)(ROMAddr+0x20C)); - index=GetReg1(P3c4,0x1A); - index=index&07; - MCLKOffset=MCLKOffset+index*5; - MCLK=*((USHORT *)(ROMAddr+MCLKOffset+0x03)); // Get MCLK - - data2=ModeType-0x02; - switch (data2) { - case 0 : colorth=1; break; - case 1 : colorth=1; break; - case 2 : colorth=2; break; - case 3 : colorth=2; break; - case 4 : colorth=3; break; - case 5 : colorth=4; break; - } - - do{ - B=(CalcDelay2(ROMAddr,0)*VCLK*colorth); - if (B%(16*MCLK) == 0) - { - B=B/(16*MCLK); - bl=B+1; - } - else - { - B=B/(16*MCLK); - bl=B+2; - } - - if(bl>0x13) { - data=GetReg1(P3c4,0x15); - data=data&0xf0; - if(data!=0xb0) { - data=data+0x20; - if(data==0xa0) data=0x30; - - data2=GetReg1(P3c4,0x15); - data2=(data2&0x0f)|data; - SetReg1(P3c4,0x15,data2); - } - else bl=0x13; - } - } while(bl>0x13); - - data2=GetReg1(P3c4,0x15); - data2=(data2&0xf0)>>4; - data2=data2<<24; - - SetReg4(0xcf8,0x80000050); - eax=GetReg3(0xcfc); - eax=eax&0x0f0ffffff; - eax=eax|data2; - SetReg4(0xcfc,eax); - - ah=bl; - ah=ah<<4; - ah=ah|0x0f; - SetReg1(P3c4,0x08,ah); - - data=bl; - data=data&0x10; - data=data<<1; - data2=GetReg1(P3c4,0x0F); - data2=data2&0x9f; - data2=data2|data; - SetReg1(P3c4,0x0F,data2); - - data=bl+3; - if(data>0x0f) data=0x0f; - SetReg1(P3c4,0x3b,0x00); - data2=GetReg1(P3c4,0x09); - data2=data2&0xF0; - data2=data2|data; - SetReg1(P3c4,0x09,data2); -} - -USHORT CalcDelay2(ULONG ROMAddr,USHORT key) -{ - USHORT data,index; - UCHAR LatencyFactor[]={88,80,78,72,70,00, - 00,79,77,71,69,49, - 88,80,78,72,70,00, - 00,72,70,64,62,44}; - - index=0; - data=GetReg1(P3c4,0x14); - if(data&0x80) index=index+12; - - data=GetReg1(P3c4,0x15); - data=(data&0xf0)>>4; - if(data&0x01) index=index+6; - - data=data>>1; - index=index+data; - data=LatencyFactor[index]; - - return(data); -} - -#endif /* CONFIG_FB_SIS_LINUXBIOS */ diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/sis_300.h linux/drivers/video/sis/sis_300.h --- v2.4.14/linux/drivers/video/sis/sis_300.h Sun Nov 12 20:40:42 2000 +++ linux/drivers/video/sis/sis_300.h Wed Dec 31 16:00:00 1969 @@ -1,163 +0,0 @@ -#include <linux/config.h> -#include "initdef.h" - -USHORT DRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48}, - {0x0C,0x09,0x02,0x20,0x35},{0x0D,0x09,0x01,0x20,0x44}, - {0x0C,0x08,0x02,0x10,0x31},{0x0D,0x08,0x01,0x10,0x40}, - {0x0C,0x0A,0x01,0x20,0x34},{0x0C,0x09,0x01,0x08,0x32}, - {0x0B,0x08,0x02,0x08,0x21},{0x0C,0x08,0x01,0x08,0x30}, - {0x0A,0x08,0x02,0x04,0x11},{0x0B,0x0A,0x01,0x10,0x28}, - {0x09,0x08,0x02,0x02,0x01},{0x0B,0x09,0x01,0x08,0x24}, - {0x0B,0x08,0x01,0x04,0x20},{0x0A,0x08,0x01,0x02,0x10}, - {0x09,0x08,0x01,0x01,0x00}}; - -USHORT MDA_DAC[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15, - 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F}; - -USHORT CGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F}; - -USHORT EGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15, - 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35, - 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D, - 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D, - 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17, - 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37, - 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F}; - -USHORT VGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15, - 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F, - 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18, - 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F, - - 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F, - 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00, - 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18, - 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04, - 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10, - 0x0B,0x0C,0x0D,0x0F,0x10}; - -#ifdef CONFIG_FB_SIS_LINUXBIOS -unsigned char SRegsInit[] = { - 0x03, 0x00, 0x03, 0x00, 0x02, 0xa1, 0x00, 0x13, - 0x2f, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0f, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xa1, 0x76, 0xb2, 0xf6, 0x0d, 0x00, 0x00, 0x00, - 0x37, 0x61, 0x80, 0x1b, 0xe1, 0x01, 0x55, 0x43, - 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, - 0x8e, 0x40, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff -}; - -unsigned char SRegs[] = { - 0x03, 0x01, 0x0F, 0x00, 0x0E, 0xA1, 0x02, 0x13, - 0x3F, 0x86, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x0B, 0x0F, 0x00, 0x00, 0x4F, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x40, 0x00, - 0xA1, 0xB6, 0xB2, 0xF6, 0x0D, 0x00, 0xF8, 0xF0, - 0x37, 0x61, 0x80, 0x1B, 0xE1, 0x80, 0x55, 0x43, - 0x80, 0x00, 0x11, 0xFF, 0x00, 0x00, 0x00, 0xFF, - 0x8E, 0x40, 0x00, 0x00, 0x08, 0x00, 0xFF, 0xFF -}; - -unsigned char CRegs[] = { - 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe9, 0x0b, 0xdf, 0x50, 0x40, 0xe7, 0x04, 0xa3, - 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff -}; // clear CR11[7] - -unsigned char GRegs[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, 0x00 -}; - -unsigned char ARegs[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -unsigned char MReg = 0x6f; - -#endif - -USHORT P3c4,P3d4,P3c0,P3ce,P3c2,P3ca,P3c6,P3c7,P3c8,P3c9,P3da; -USHORT CRT1VCLKLen; //VCLKData table length of bytes of each entry -USHORT flag_clearbuffer; //0: no clear frame buffer 1:clear frame buffer -int RAMType; -int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,VCLKData,MCLKData, ECLKData; -int REFIndex,ModeType; -USHORT IF_DEF_LVDS,IF_DEF_TRUMPION; -USHORT VBInfo,LCDResInfo,LCDTypeInfo,LCDInfo; - -//int init300(int,int,int); -VOID SetMemoryClock(ULONG); -VOID SetDRAMSize(PHW_DEVICE_EXTENSION); -//extern "C" int ChkBUSWidth(int); - -//int setmode(int,int,int,int); -BOOLEAN SearchModeID(ULONG, USHORT); -BOOLEAN CheckMemorySize(ULONG); -VOID GetModePtr(ULONG, USHORT); -BOOLEAN GetRatePtr(ULONG, USHORT); -VOID SetSeqRegs(ULONG); -VOID SetMiscRegs(ULONG); -VOID SetCRTCRegs(ULONG); -VOID SetATTRegs(ULONG); -VOID SetGRCRegs(ULONG); -VOID ClearExt1Regs(VOID); -VOID SetSync(ULONG); -VOID SetCRT1CRTC(ULONG); -VOID SetCRT1Offset(ULONG); -VOID SetCRT1FIFO(ULONG); -VOID SetCRT1FIFO2(ULONG); -VOID SetCRT1VCLK(PHW_DEVICE_EXTENSION, ULONG); -VOID LoadDAC(ULONG); -VOID DisplayOn(VOID); -VOID SetCRT1ModeRegs(ULONG, USHORT); -VOID SetVCLKState(PHW_DEVICE_EXTENSION, ULONG, USHORT); -VOID WriteDAC(USHORT, USHORT, USHORT, USHORT); -VOID ClearBuffer(PHW_DEVICE_EXTENSION); -USHORT ChkBUSWidth(ULONG); -USHORT GetModeIDLength(ULONG, USHORT); -USHORT GetRefindexLength(ULONG, USHORT); -VOID SetInterlace(ULONG, USHORT); -USHORT CalcDelay2(ULONG ,USHORT); -void Set_LVDS_TRUMPION(VOID); -BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, - USHORT ModeNo); -#ifndef CONFIG_FB_SIS_LINUXBIOS -static USHORT CalcDelay(ULONG ,USHORT); -#endif - -extern BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -extern VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr); -extern VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension); -extern BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4); -extern VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr); -extern BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension); -extern BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr); -extern BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension); -extern USHORT GetVCLKLen(ULONG ROMAddr); -extern void SetReg1(u16 port, u16 index, u16 data); -extern void SetReg3(u16 port, u16 data); -extern void SetReg4(u16 port, unsigned long data); -extern u8 GetReg1(u16 port, u16 index); -extern u8 GetReg2(u16 port); -extern u32 GetReg3(u16 port); -extern void ClearDAC(u16 port); diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/sis_301.c linux/drivers/video/sis/sis_301.c --- v2.4.14/linux/drivers/video/sis/sis_301.c Sun Nov 12 20:40:42 2000 +++ linux/drivers/video/sis/sis_301.c Wed Dec 31 16:00:00 1969 @@ -1,2868 +0,0 @@ -/* Recently Update by v1.09.50 */ - -#include <linux/config.h> -#include "sis_301.h" - -#ifndef CONFIG_FB_SIS_LINUXBIOS - -BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - USHORT temp; - - SetFlag=SetFlag|ProgrammingCRT2; - SearchModeID(ROMAddr,ModeNo); - - temp=GetRatePtrCRT2(ROMAddr,ModeNo); - if(((temp&0x02)==0) && ((VBInfo&CRT2DisplayFlag)==0)) - return(FALSE); - SaveCRT2Info(ModeNo); - DisableBridge(BaseAddr); - UnLockCRT2(BaseAddr); - SetDefCRT2ExtRegs(BaseAddr); - SetCRT2ModeRegs(BaseAddr,ModeNo); - if(VBInfo&CRT2DisplayFlag){ - LockCRT2(BaseAddr); - return 0; - } - GetCRT2Data(ROMAddr,ModeNo); - if(IF_DEF_LVDS==1){ //LVDS - GetLVDSDesData(ROMAddr,ModeNo); - } - SetGroup1(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); - if(IF_DEF_LVDS==0){ - SetGroup2(BaseAddr,ROMAddr); - SetGroup3(BaseAddr); - SetGroup4(BaseAddr,ROMAddr,ModeNo); - SetGroup5(BaseAddr,ROMAddr); - }else{ //LVDS - if(IF_DEF_TRUMPION==0){ - ModCRT1CRTC(ROMAddr,ModeNo); - } - SetCRT2ECLK(ROMAddr,ModeNo); - } - - EnableCRT2(); - EnableBridge(BaseAddr); - SetLockRegs(); - LockCRT2(BaseAddr); - - return 1; -} - -VOID overwriteregs(ULONG ROMAddr,USHORT BaseAddr) -{ - int i; - USHORT Part1Port; //reg data is for 1024x768 16bit 85hz - int p1reg[0x29]={0x84,0x76,0x4B,0x21,0x00,0x00,0x00,0x00,0x1F,0x51, - 0x0C,0x10,0x44,0x90,0x1E,0xFF,0x00,0x34,0x13,0x10, - 0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x97,0x16, - 0xA3}; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - for(i=0;i<29;i++){ - SetReg1(Part1Port,(USHORT)i,(USHORT)p1reg[i]); - } -} - -VOID SetDefCRT2ExtRegs(USHORT BaseAddr) -{ - USHORT Part1Port,Part2Port,Part4Port; - USHORT temp; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; - Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - SetReg1(Part1Port,0x02,0x40); - SetReg1(Part4Port,0x10,0x80); - temp=(UCHAR)GetReg1(P3c4,0x16); - temp=temp&0xC3; - SetReg1(P3d4,0x35,temp); -} - -USHORT GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo) -{ //return bit0=>0:standard mode 1:extended mode - SHORT index; // bit1=>0:crt2 no support this mode - USHORT temp; // 1:crt2 support this mode - USHORT ulRefIndexLength; - USHORT temp1; - SHORT LCDRefreshIndex[4]={0x0,0x0,0x03,0x01}; - // LCDPanel:no lcd,800x600,1024x768,1280x1024 - if(ModeNo<0x14) return(0); // Mode No <= 13h then return - - index=GetReg1(P3d4,0x33); // Get 3d4 CRTC33 - index=index>>SelectCRT2Rate; //For CRT2,cl=SelectCRT2Rate=4, shr ah,cl - index=index&0x0F; // Frame rate index - if(index!=0) index--; - - if(IF_DEF_TRUMPION==1){ - if(VBInfo&SetSimuScanMode){ - index=0; - } - } - if(SetFlag&ProgrammingCRT2){ - if(VBInfo&SetCRT2ToLCD){ - if(IF_DEF_LVDS==0){ - temp=LCDResInfo; - temp1=LCDRefreshIndex[temp]; - if(index>temp1){ - index=temp1; - } - }else{ - index=0; - } - } - } - - REFIndex=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point - - ulRefIndexLength =Ext2StructSize; - do { - temp=*((USHORT *)(ROMAddr+REFIndex)); // di => REFIndex - if(temp==0xFFFF) break; - temp=temp&ModeInfoFlag; - if(temp<ModeType) break; - - REFIndex=REFIndex+ulRefIndexLength; // rate size - index--; - if(index<0){ - if(!(VBInfo&SetCRT2ToRAMDAC)){ - if(VBInfo&SetInSlaveMode){ - temp1=*((USHORT *)(ROMAddr+REFIndex+0-Ext2StructSize)); - if(temp1&InterlaceMode){ - index=0; - } - } - } - } - } while(index>=0); - - REFIndex=REFIndex-ulRefIndexLength; // rate size - - if((SetFlag&ProgrammingCRT2)){ - temp1=AjustCRT2Rate(ROMAddr); - }else{ - temp1=0; - } - - return(0x01|(temp1<<1)); -} - -BOOLEAN AjustCRT2Rate(ULONG ROMAddr) -{ - USHORT tempbx=0,tempax,temp; - USHORT tempextinfoflag; - tempax=0; - - if(IF_DEF_LVDS==0){ - if(VBInfo&SetCRT2ToRAMDAC){ - tempax=tempax|SupportRAMDAC2; - } - if(VBInfo&SetCRT2ToLCD){ - tempax=tempax|SupportLCD; - if(LCDResInfo!=Panel1280x1024){ - temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo - if(temp>=9){ - tempax=0; - } - } - } - if(VBInfo&(SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)){ - tempax=tempax|SupportTV; - if(!(VBInfo&SetPALTV)){ - tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag - if(tempextinfoflag&NoSupportSimuTV){ - if(VBInfo&SetInSlaveMode){ - if(!(VBInfo&SetNotSimuTVMode)){ - return 0; - } - } - } - } - } - tempbx=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point - }else{ //for LVDS - if(VBInfo&SetCRT2ToLCD){ - tempax=tempax|SupportLCD; - temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo - if(temp>0x08){ //1024x768 - return 0; - } - if(LCDResInfo<Panel1024x768){ - if(temp>0x07){ //800x600 - return 0; - } - if(temp==0x04){ //512x384 - return 0; - } - } - } - } - - for(;REFIndex>tempbx;REFIndex-=Ext2StructSize){ - tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag - if(tempextinfoflag&tempax){ - return 1; - } - } - for(REFIndex=tempbx;;REFIndex+=Ext2StructSize){ - tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag - if(tempextinfoflag==0x0FFFF){ - return 0; - } - if(tempextinfoflag&tempax){ - return 1; - } - } - return(FALSE); -} - -VOID SaveCRT2Info(USHORT ModeNo){ - USHORT temp1,temp2,temp3; - temp1=(VBInfo&SetInSlaveMode)>>8; - temp2=~(SetInSlaveMode>>8); - temp3=(UCHAR)GetReg1(P3d4,0x31); - temp3=((temp3&temp2)|temp1); - SetReg1(P3d4,0x31,(USHORT)temp3); - temp3=(UCHAR)GetReg1(P3d4,0x35); - temp3=temp3&0xF3; - SetReg1(P3d4,0x35,(USHORT)temp3); -} - -VOID DisableLockRegs(){ - UCHAR temp3; - temp3=(UCHAR)GetReg1(P3c4,0x32); - temp3=temp3&0xDF; - SetReg1(P3c4,0x32,(USHORT)temp3); -} - -VOID DisableCRT2(){ - UCHAR temp3; - temp3=(UCHAR)GetReg1(P3c4,0x1E); - temp3=temp3&0xDF; - SetReg1(P3c4,0x1E,(USHORT)temp3); -} - -void DisableBridge(USHORT BaseAddr) -{ - USHORT Part2Port,Part1Port; - Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - - if(IF_DEF_LVDS==0){ - SetRegANDOR(Part2Port,0x00,0xDF,0x00); //Set Part2 Index0 D[5]=0 - DisableLockRegs(); // SR 32 - DisableCRT2(); // SR 1E - }else{ - DisableLockRegs(); - DisableCRT2(); - if(IF_DEF_TRUMPION==0){ - UnLockCRT2(BaseAddr); - SetRegANDOR(Part1Port,0x02,0xFF,0x40); //set Part1Port ,index 2, D6=1, - } - } -} - -VOID GetCRT2Data(ULONG ROMAddr,USHORT ModeNo) -{ - if(IF_DEF_LVDS==0){ //301 - GetCRT2Data301(ROMAddr,ModeNo); - return; - }else{ //LVDS - GetCRT2DataLVDS(ROMAddr,ModeNo); - return; - } -} - -VOID GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT tempax,tempbx,OldREFIndex; - - OldREFIndex=(USHORT)REFIndex; //push di - GetResInfo(ROMAddr,ModeNo); - GetCRT2Ptr(ROMAddr,ModeNo); - - tempax=*((USHORT *)(ROMAddr+REFIndex)); - tempax=tempax&0x0FFF; - VGAHT=tempax; - - tempax=*((USHORT *)(ROMAddr+REFIndex+1)); - tempax=tempax>>4; - tempax=tempax&0x07FF; - VGAVT=tempax; - - tempax=*((USHORT *)(ROMAddr+REFIndex+3)); - tempax=tempax&0x0FFF; - tempbx=*((USHORT *)(ROMAddr+REFIndex+4)); - tempbx=tempbx>>4; - tempbx=tempbx&0x07FF; - - HT=tempax; - VT=tempbx; - - if(IF_DEF_TRUMPION==0){ - if(VBInfo&SetCRT2ToLCD){ - if(!(LCDInfo&LCDNonExpanding)){ - if(LCDResInfo==Panel800x600){ - tempax=800; - tempbx=600; - }else if(LCDResInfo==Panel1024x768){ - tempax=1024; - tempbx=768; - }else{ - tempax=1280; - tempbx=1024; - } - HDE=tempax; - VDE=tempbx; - } - } - } - REFIndex=OldREFIndex; //pop di - return; -} - -VOID GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT tempax,tempbx,modeflag1,OldREFIndex; - USHORT tempal,tempah,tempbl; - - OldREFIndex=(USHORT)REFIndex; //push di - RVBHRS=50;NewFlickerMode=0;RY1COE=0; - RY2COE=0;RY3COE=0;RY4COE=0; - - GetResInfo(ROMAddr,ModeNo); - if(VBInfo&SetCRT2ToRAMDAC){ - GetRAMDAC2DATA(ROMAddr,ModeNo); - REFIndex=OldREFIndex; //pop di - return; - } - GetCRT2Ptr(ROMAddr,ModeNo); - - tempal=*((UCHAR *)(ROMAddr+REFIndex)); - tempah=*((UCHAR *)(ROMAddr+REFIndex+4)); - tempax=tempal|(((tempah<<8)>>7)&0xFF00); - RVBHCMAX=tempax; - - tempal=*((UCHAR *)(ROMAddr+REFIndex+1)); - RVBHCFACT=tempal; - - tempax=*((USHORT *)(ROMAddr+REFIndex+2)); - VGAHT=(tempax&0x0FFF); - - tempax=*((USHORT *)(ROMAddr+REFIndex+3)); - VGAVT=((tempax>>4)&0x07FF); - - tempax=*((USHORT *)(ROMAddr+REFIndex+5)); - tempax=(tempax&0x0FFF); - tempbx=*((USHORT *)(ROMAddr+REFIndex+6)); - tempbx=((tempbx>>4)&0x07FF); - tempbl=tempbx&0x00FF; - - if(VBInfo&SetCRT2ToTV){ - tempax=*((USHORT *)(ROMAddr+REFIndex+5)); - tempax=(tempax&0x0FFF); - HDE=tempax; - tempax=*((USHORT *)(ROMAddr+REFIndex+6)); - tempax=((tempax>>4)&0x07FF); - VDE=tempax; - //skipp something about hivisiontv - tempax=*((USHORT *)(ROMAddr+REFIndex+8)); - tempbl=(tempax>>8); - tempax=tempax&0x0FFF; - modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(modeflag1&HalfDCLK){ - tempax=*((USHORT *)(ROMAddr+REFIndex+10)); - } - RVBHRS=tempax; - NewFlickerMode=(tempbl&0x080); - - tempax=*((USHORT *)(ROMAddr+REFIndex+12)); - RY1COE=(tempax&0x00FF); - RY2COE=((tempax&0xFF00)>>8); - tempax=*((USHORT *)(ROMAddr+REFIndex+14)); - RY3COE=(tempax&0x00FF); - RY4COE=((tempax&0xFF00)>>8); - if(!(VBInfo&SetPALTV)){ - tempax=NTSCHT; - tempbx=NTSCVT; - }else{ - tempax=PALHT; - tempbx=PALVT; - } - } - HT=tempax; - VT=tempbx; - if(!(VBInfo&SetCRT2ToLCD)){ - REFIndex=OldREFIndex; //pop di - return; - } - - tempax=1024; - if(VGAVDE==350){ //cx->VGAVDE - tempbx=560; - }else if(VGAVDE==400){ - tempbx=640; - }else{ - tempbx=768; - } - - if(LCDResInfo==Panel1280x1024){ - tempax=1280; - if(VGAVDE==360){ - tempbx=768; - }else if(VGAVDE==375){ - tempbx=800; - }else if(VGAVDE==405){ - tempbx=864; - }else{ - tempbx=1024; - } - } - - HDE=tempax; - VDE=tempbx; - REFIndex=OldREFIndex; //pop di - return; -} - -VOID GetResInfo(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT temp,xres,yres,modeflag1; - if(ModeNo<=0x13){ - temp=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x05)); // si+St_ResInfo - xres=StResInfo[temp][0]; - yres=StResInfo[temp][1]; - }else{ - temp=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); // si+Ext_ResInfo - xres=ModeResInfo[temp][0]; //xres->ax - yres=ModeResInfo[temp][1]; //yres->bx - modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(modeflag1&HalfDCLK){ xres=xres*2;} - if(modeflag1&DoubleScanMode){yres=yres*2;} - } - if(!(LCDResInfo==Panel1024x768)){ - if(yres==400) yres=405; - if(yres==350) yres=360; - if(SetFlag&LCDVESATiming){ - if(yres==360) yres=375; - } - } - VGAHDE=xres; - HDE=xres; - VGAVDE=yres; - VDE=yres; -} - -VOID GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT old_REFIndex,tempax; - - old_REFIndex=(USHORT)REFIndex; //push di - REFIndex=GetLVDSDesPtr(ROMAddr,ModeNo); - - tempax=*((USHORT *)(ROMAddr+REFIndex)); - tempax=tempax&0x0FFF; - LCDHDES=tempax; - - if(LCDInfo&LCDNonExpanding){ //hw walk-a-round - if(LCDResInfo>=Panel1024x768){ - if(ModeNo<=0x13){ - LCDHDES=320; - } - } - } - - tempax=*((USHORT *)(ROMAddr+REFIndex+1)); - tempax=tempax>>4; - tempax=tempax&0x07FF; - LCDVDES=tempax; - - REFIndex=old_REFIndex; //pop di - return; -} - - -VOID GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT tempax,tempbx,tempbh,modeflag1,t1=0,t2; - RVBHCMAX=1;RVBHCFACT=1; - if(ModeNo<=0x13){ - tempax=*((UCHAR *)(ROMAddr+REFIndex+10)); - tempbx=*((USHORT *)(ROMAddr+REFIndex+16)); - }else{ - t1=*((UCHAR *)(ROMAddr+REFIndex+0x2)); //Ext_CRT1CRTC=2 - t1=t1&0x03F; //[06/29/2000] fix bug for vbios >=v1.07.00 - t1=t1*CRT1Len; - REFIndex=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table - REFIndex=REFIndex+t1; - t1=*((UCHAR *)(ROMAddr+REFIndex+0)); - t2=*((UCHAR *)(ROMAddr+REFIndex+14)); - tempax=(t1&0xFF)|((t2&0x03)<<8); - tempbx=*((USHORT *)(ROMAddr+REFIndex+6)); - t1=*((UCHAR *)(ROMAddr+REFIndex+13)); - t1=(t1&0x01)<<2; - } - - tempbh=tempbx>>8; - tempbh=((tempbh&0x20)>>4)|(tempbh&0x01); - tempbh=tempbh|t1; - tempbx=(tempbx&0xFF)|(tempbh<<8); - tempax=tempax+5; - modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(modeflag1&Charx8Dot){ - tempax=tempax*8; - }else{ - tempax=tempax*9; - } - - VGAHT=tempax; - HT=tempax; - tempbx++; - VGAVT=tempbx; - VT=tempbx; - -} - -VOID GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT tempcl,tempbx,tempal,tempax,CRT2PtrData; - - if(IF_DEF_LVDS==0){ - if(VBInfo&SetCRT2ToLCD){ //LCD - tempbx=0; //default tempbx=0 -> ExtLCD1Data - tempcl=LCDDataLen; - if(LCDResInfo==Panel1024x768){ - tempbx=0; - }else if(LCDResInfo==Panel1280x1024){ - tempbx=1; - } - if(!(SetFlag&LCDVESATiming)) tempbx+=5; - }else if(VBInfo&SetPALTV){ - tempcl=TVDataLen; - tempbx=3; - }else{ - tempbx=4; - tempcl=TVDataLen; - } - if(SetFlag&TVSimuMode){ - tempbx=tempbx+4; - } - if(ModeNo<=0x13){ - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC - }else{ - tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC - } - tempal=tempal&0x1F; - - tempax=tempal*tempcl; - REFIndex=*((USHORT *)(ROMAddr+tempbx*2+0x20E)); - REFIndex+=tempax; - }else{ //for LVDS - - tempcl=LVDSDataLen; - tempbx=LCDResInfo-Panel800x600; - if(LCDInfo&LCDNonExpanding){ - tempbx=tempbx+3; - } - if(ModeNo<=0x13){ - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC - }else{ - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC - } - tempal=tempal&0x1F; - tempax=tempal*tempcl; - CRT2PtrData=*((USHORT *)(ROMAddr+ADR_CRT2PtrData)); //ADR_CRT2PtrData is defined in init.def - REFIndex=*((USHORT *)(ROMAddr+CRT2PtrData+tempbx*2)); - REFIndex+=tempax; - } -} - -VOID UnLockCRT2(USHORT BaseAddr) -{ - UCHAR temp3; - USHORT Part1Port; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - temp3=(UCHAR)GetReg1(Part1Port,0x24); - temp3=temp3|0x01; - SetReg1(Part1Port,0x24,(USHORT)temp3); -} - -VOID SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo) -{ - USHORT i,j; - USHORT tempah=0,temp3; - SHORT tempcl; - USHORT Part4Port; - USHORT Part1Port; - Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - for(i=0,j=4;i<3;i++,j++){ - SetReg1(Part1Port,j,0); - } - - tempcl=(USHORT)ModeType; - if(ModeNo>0x13){ - tempcl=tempcl-ModeVGA; - if(tempcl>=0){ - tempah=((0x010>>tempcl)|0x080); - } - }else{ - tempah=0x080; - } - - if(VBInfo&SetInSlaveMode){ - tempah=(tempah^0x0A0); - } - if(VBInfo&CRT2DisplayFlag){ - tempah=0; - } - SetReg1(Part1Port,0,tempah); - - if(IF_DEF_LVDS==0){ //301 - tempah=0x01; - if(!(VBInfo&SetInSlaveMode)){ - tempah=(tempah|0x02); - } - if(!(VBInfo&SetCRT2ToRAMDAC)){ - tempah=(tempah^0x05); - if(!(VBInfo&SetCRT2ToLCD)){ - tempah=(tempah^0x01); - } - } - tempah=(tempah<<5)&0xFF; - if(VBInfo&CRT2DisplayFlag){ - tempah=0; - } - SetReg1(Part1Port,0x01,tempah); - - tempah=tempah>>5; - if((ModeType==ModeVGA)&&(!(VBInfo&SetInSlaveMode))){ - tempah=tempah|0x010; - } - if(LCDResInfo!=Panel1024x768){ - tempah=tempah|0x080; - } - if(VBInfo&SetCRT2ToTV){ - if(VBInfo&SetInSlaveMode){ - tempah=tempah|0x020; - } - } - - temp3=(UCHAR)GetReg1(Part4Port,0x0D); - temp3=temp3&(~0x0BF); - temp3=temp3|tempah; - SetReg1(Part4Port,0x0D,(USHORT)temp3); - }else{ //LVDS - tempah=0; - if(!(VBInfo&SetInSlaveMode)){ - tempah=tempah|0x02; - } - tempah=(tempah<<5)&0x0FF; - if(VBInfo&CRT2DisplayFlag){ - tempah=0; - } - SetReg1(Part1Port,0x01,tempah); - } -} - -VOID SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - if(IF_DEF_LVDS==0){ //301 - SetGroup1_301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); - }else{ //LVDS - SetGroup1_LVDS(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension); - } -} -VOID SetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - USHORT temp1,temp2,tempcl,tempch,tempbh,tempal,tempah,tempax,tempbx; - USHORT tempcx,OldREFIndex,lcdhdee; - USHORT Part1Port; - USHORT temppush1,temppush2; - unsigned long int tempeax,tempebx,tempecx,templong; - - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - OldREFIndex=(USHORT)REFIndex; //push di - - SetCRT2Offset(Part1Port,ROMAddr); - SetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension); - SetCRT2Sync(BaseAddr,ROMAddr,ModeNo); - - temp1=(VGAHT-1)&0x0FF; //BTVGA2HT 0x08,0x09 - SetReg1(Part1Port,0x08,temp1); - temp1=(((VGAHT-1)&0xFF00)>>8)<<4; - SetRegANDOR(Part1Port,0x09,~0x0F0,temp1); - - - temp1=(VGAHDE+12)&0x0FF; //BTVGA2HDEE 0x0A,0x0C - SetReg1(Part1Port,0x0A,temp1); - - temp1=VGAHDE+12; //bx BTVGA@HRS 0x0B,0x0C - temp2=(VGAHT-VGAHDE)>>2; //cx - temp1=temp1+temp2; - temp2=(temp2<<1)+temp1; - tempcl=temp2&0x0FF; - // - SetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF)); - tempah=(temp1&0xFF00)>>8; - tempbh=((((VGAHDE+12)&0xFF00)>>8)<<4)&0x0FF; - tempah=tempah|tempbh; - SetReg1(Part1Port,0x0C,tempah); - SetReg1(Part1Port,0x0D,tempcl); //BTVGA2HRE 0x0D - tempcx=(VGAVT-1); - tempah=tempcx&0x0FF; - SetReg1(Part1Port,0x0E,tempah); //BTVGA2TV 0x0E,0x12 - tempbx=VGAVDE-1; - tempah=tempbx&0x0FF; - SetReg1(Part1Port,0x0F,tempah); //BTVGA2VDEE 0x0F,0x12 - tempah=((tempbx&0xFF00)<<3)>>8; - tempah=tempah|((tempcx&0xFF00)>>8); - SetReg1(Part1Port,0x12,tempah); - - tempbx=(VGAVT+VGAVDE)>>1; //BTVGA2VRS 0x10,0x11 - tempcx=((VGAVT-VGAVDE)>>4)+tempbx+1; //BTVGA2VRE 0x11 - // - tempah=tempbx&0x0FF; - SetReg1(Part1Port,0x10,tempah); - tempbh=(tempbx&0xFF00)>>8; - tempah=((tempbh<<4)&0x0FF)|(tempcx&0x0F); - SetReg1(Part1Port,0x11,tempah); - - SetRegANDOR(Part1Port,0x13,~0x03C,tempah); - - tempax=LCDHDES; - tempbx=HDE; - tempcx=HT; - tempcx=tempcx-tempbx; //HT-HDE - tempax=tempax+tempbx; //lcdhdee - tempbx=HT; - if(tempax>=tempbx){ - tempax=tempax-tempbx; - } - - lcdhdee=tempax; - tempcx=tempcx>>2; //temp - tempcx=tempcx+tempax; //lcdhrs - if(tempcx>=tempbx){ - tempcx=tempcx-tempbx; - } - - tempax=tempcx; - tempax=tempax>>3; //BPLHRS - tempah=tempax&0x0FF; - SetReg1(Part1Port,0x14,tempah); //Part1_14h - tempah=tempah+2; - tempah=tempah+0x01F; - tempcl=tempcx&0x0FF; - tempcl=tempcl&0x07; - tempcl=(tempcl<<5)&0xFF; //BPHLHSKEW - tempah=tempah|tempcl; - SetReg1(Part1Port,0x15,tempah); //Part1_15h - tempbx=lcdhdee; //lcdhdee - tempcx=LCDHDES; //lcdhdes - tempah=(tempcx&0xFF); - tempah=tempah&0x07; //BPLHDESKEW - SetReg1(Part1Port,0x1A,tempah); //Part1_1Ah - tempcx=tempcx>>3; //BPLHDES - tempah=(tempcx&0xFF); - SetReg1(Part1Port,0x16,tempah); //Part1_16h - tempbx=tempbx>>3; //BPLHDEE - tempah=tempbx&0xFF; - SetReg1(Part1Port,0x17,tempah); //Part1_17h - - tempcx=VGAVT; - tempbx=VGAVDE; - tempcx=tempcx-tempbx; //VGAVT-VGAVDE - tempbx=LCDVDES; //VGAVDES - temppush1=tempbx; //push bx temppush1 - if(IF_DEF_TRUMPION==0){ - if(LCDResInfo==Panel800x600){ - tempax=600; - }else{ - tempax=768; - } - }else{ - tempax=VGAVDE; - } - tempbx=tempbx+tempax; - tempax=VT; //VT - if(tempbx>=VT){ - tempbx=tempbx-tempax; - } - temppush2=tempbx; //push bx temppush2 - tempcx=tempcx>>1; - tempbx=tempbx+tempcx; - tempbx++; //BPLVRS - if(tempbx>=tempax){ - tempbx=tempbx-tempax; - } - tempah=tempbx&0xFF; - SetReg1(Part1Port,0x18,tempah); //Part1_18h - tempcx=tempcx>>3; - tempcx=tempcx+tempbx; - tempcx++; //BPLVRE - tempah=tempcx&0xFF; - tempah=tempah&0x0F; - tempah=tempah|0x030; - SetRegANDOR(Part1Port,0x19,~0x03F,tempah); //Part1_19h - tempbh=(tempbx&0xFF00)>>8; - tempbh=tempbh&0x07; - tempah=tempbh; - tempah=(tempah<<3)&0xFF; //BPLDESKEW =0 - tempbx=VGAVDE; - if(tempbx!=VDE){ - tempah=tempah|0x40; - } - SetRegANDOR(Part1Port,0x1A,0x07,tempah); //Part1_1Ah - tempecx=VGAVT; - tempebx=VDE; - tempeax=VGAVDE; - tempecx=tempecx-tempeax; //VGAVT-VGAVDE - tempeax=tempeax*64; - templong=tempeax/tempebx; - if(templong*tempebx<tempeax){ - templong++; - } - tempebx=templong; //BPLVCFACT - if(SetFlag&EnableLVDSDDA){ - tempebx=tempebx&0x03F; - } - tempah=(USHORT)(tempebx&0x0FF); - SetReg1(Part1Port,0x1E,tempah); //Part1_1Eh - tempbx=temppush2; //pop bx temppush2 BPLVDEE - tempcx=temppush1; //pop cx temppush1 NPLVDES - tempbh=(tempbx&0xFF00)>>8; - tempah=tempah&0x07; - tempah=tempbh; - tempah=tempah<<3; - tempch=(tempcx&0xFF00)>>8; - tempch=tempah&0x07; - tempah=tempah|tempch; - SetReg1(Part1Port,0x1D,tempah); //Part1_1Dh - tempah=tempbx&0xFF; - SetReg1(Part1Port,0x1C,tempah); //Part1_1Ch - tempah=tempcx&0xFF; - SetReg1(Part1Port,0x1B,tempah); //Part1_1Bh - - tempecx=VGAHDE; - tempebx=HDE; - tempeax=tempecx; - tempeax=tempeax<<6; - tempeax=tempeax<<10; - tempeax=tempeax/tempebx; - if(tempebx==tempecx){ - tempeax=65535; - } - tempecx=tempeax; - tempeax=VGAHT; - tempeax=tempeax<<6; - tempeax=tempeax<<10; - tempeax=tempeax/tempecx; - tempecx=tempecx<<16; - tempeax=tempeax-1; - tempax=(USHORT)(tempeax&0x00FFFF); - tempcx=tempax; - tempah=tempcx&0x0FF; - SetReg1(Part1Port,0x1F,tempah); //Part1_1Fh - tempbx=VDE; - tempbx--; //BENPLACCEND - if(SetFlag&EnableLVDSDDA){ - tempbx=1; - } - tempah=(tempbx&0xFF00)>>8; - tempah=(tempah<<3)&0xFF; - tempch=(tempcx&0xFF00)>>8; - tempch=tempch&0x07; - tempah=tempah|tempch; - SetReg1(Part1Port,0x20,tempah); //Part1_20h - tempah=tempbx&0xFF; - SetReg1(Part1Port,0x21,tempah); //Part1_21h - tempecx=tempecx>>16; //BPLHCFACT - temp1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(temp1&HalfDCLK){ - tempecx=tempecx>>1; - } - tempcx=(USHORT)(tempecx&0x0FFFF); - tempah=(tempcx&0xFF00)>>8; - SetReg1(Part1Port,0x22,tempah); //Part1_22h - tempah=tempcx&0x0FF; - SetReg1(Part1Port,0x23,tempah); //Part1_23h - if(IF_DEF_TRUMPION==1){ - tempal=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x05)); // si+St_ResInfo - if(ModeNo>0x13){ - SetFlag=SetFlag|ProgrammingCRT2; - GetRatePtrCRT2(ROMAddr,ModeNo); - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC - tempal=tempal&0x1F; - } - tempah=0x80; - tempal=tempal*tempah; - REFIndex= offset_Zurac; //offset Zurac need added in rompost.asm - REFIndex=REFIndex+tempal; - SetTPData(); //this function not implemented yet - SetTPData(); - SetTPData(); - SetTPData(); - SetTPData(); - SetTPData(); - SetTPData(); - SetTPData(); - SetTPData(); - } - - REFIndex=OldREFIndex; //pop di - return; -} - -VOID SetTPData(VOID) -{ - return; -} - -VOID SetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - USHORT temp1,temp2,tempcl,tempch,tempbl,tempbh,tempal,tempah,tempax,tempbx; - USHORT tempcx,OldREFIndex; - USHORT Part1Port; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - OldREFIndex=(USHORT)REFIndex; //push di - - SetCRT2Offset(Part1Port,ROMAddr); - SetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension); - SetCRT2Sync(BaseAddr,ROMAddr,ModeNo); - - GetCRT1Ptr(ROMAddr); - - temp1=(VGAHT-1)&0x0FF; //BTVGA2HT 0x08,0x09 - SetReg1(Part1Port,0x08,temp1); - temp1=(((VGAHT-1)&0xFF00)>>8)<<4; - SetRegANDOR(Part1Port,0x09,~0x0F0,temp1); - - temp1=(VGAHDE+12)&0x0FF; //BTVGA2HDEE 0x0A,0x0C - SetReg1(Part1Port,0x0A,temp1); - - temp1=VGAHDE+12; //bx BTVGA@HRS 0x0B,0x0C - temp2=(VGAHT-VGAHDE)>>2; //cx - temp1=temp1+temp2; - temp2=(temp2<<1)+temp1; - tempcl=temp2&0x0FF; - if(VBInfo&SetCRT2ToRAMDAC){ - tempbl=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+4 - tempbh=*((UCHAR *)(ROMAddr+REFIndex+14)); //di+14 - temp1=((tempbh>>6)<<8)|tempbl; //temp1->bx - temp1=(temp1-1)<<3; - tempcl=*((UCHAR *)(ROMAddr+REFIndex+5)); //di+5 - tempch=*((UCHAR *)(ROMAddr+REFIndex+15)); //di+15 - tempcl=tempcl&0x01F; - tempch=(tempch&0x04)<<(6-2); - tempcl=((tempcl|tempch)-1)<<3; - } - SetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF)); - tempah=(temp1&0xFF00)>>8; - tempbh=((((VGAHDE+12)&0xFF00)>>8)<<4)&0x0FF; - tempah=tempah|tempbh; - SetReg1(Part1Port,0x0C,tempah); - SetReg1(Part1Port,0x0D,tempcl); //BTVGA2HRE 0x0D - tempcx=(VGAVT-1); - tempah=tempcx&0x0FF; - SetReg1(Part1Port,0x0E,tempah); //BTVGA2TV 0x0E,0x12 - tempbx=VGAVDE-1; - tempah=tempbx&0x0FF; - SetReg1(Part1Port,0x0F,tempah); //BTVGA2VDEE 0x0F,0x12 - tempah=((tempbx&0xFF00)<<3)>>8; - tempah=tempah|((tempcx&0xFF00)>>8); - SetReg1(Part1Port,0x12,tempah); - - tempbx=(VGAVT+VGAVDE)>>1; //BTVGA2VRS 0x10,0x11 - tempcx=((VGAVT-VGAVDE)>>4)+tempbx+1; //BTVGA2VRE 0x11 - if(VBInfo&SetCRT2ToRAMDAC){ - tempbx=*((UCHAR *)(ROMAddr+REFIndex+8)); //di+8 - temp1=*((UCHAR *)(ROMAddr+REFIndex+7)); //di+7 - if(temp1&0x04){ - tempbx=tempbx|0x0100; - } - if(temp1&0x080){ - tempbx=tempbx|0x0200; - } - temp1=*((UCHAR *)(ROMAddr+REFIndex+13)); //di+13 - if(temp1&0x08){ - tempbx=tempbx|0x0400; - } - tempcl= *((UCHAR *)(ROMAddr+REFIndex+9)); //di+9 - tempcx=(tempcx&0xFF00)|(tempcl&0x00FF); - } - tempah=tempbx&0x0FF; - SetReg1(Part1Port,0x10,tempah); - tempbh=(tempbx&0xFF00)>>8; - tempah=((tempbh<<4)&0x0FF)|(tempcx&0x0F); - SetReg1(Part1Port,0x11,tempah); - - if(HwDeviceExtension->jChipID == SIS_Glamour) - { - tempah=0x10; - if((LCDResInfo!=Panel1024x768)&&(LCDResInfo==Panel1280x1024)){ - tempah=0x20; - } - }else{ - tempah=0x20; - } - if(VBInfo&SetCRT2ToTV){ - tempah=0x08; - } - - SetRegANDOR(Part1Port,0x13,~0x03C,tempah); - - if(!(VBInfo&SetInSlaveMode)){ - REFIndex=OldREFIndex; - return; - } - if(VBInfo&SetCRT2ToTV){ - tempax=0xFFFF; - }else{ - tempax=GetVGAHT2(); - } - tempcl=0x08; //Reg 0x03 Horozontal Total - temp1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(!(temp1&Charx8Dot)){ //temp1->St_ModeFlag - tempcl=0x09; - } - if(tempax>=VGAHT){ - tempax=VGAHT; - } - if(temp1&HalfDCLK){ - tempax=tempax>>1; - } - tempax=(tempax/tempcl)-5; - tempbl=tempax; - tempah=0xFF; //set MAX HT - SetReg1(Part1Port,0x03,tempah); - - tempax=VGAHDE; //0x04 Horizontal Display End - if(temp1&HalfDCLK){ - tempax=tempax>>1; - } - tempax=(tempax/tempcl)-1; - tempbh=tempax; - SetReg1(Part1Port,0x04,tempax); - - tempah=tempbh; - if(VBInfo&SetCRT2ToTV){ - tempah=tempah+2; - } - SetReg1(Part1Port,0x05,tempah); //0x05 Horizontal Display Start - SetReg1(Part1Port,0x06,0x03); //0x06 Horizontal Blank end - //0x07 horizontal Retrace Start - tempcx=(tempbl+tempbh)>>1; - tempah=(tempcx&0xFF)+2; - - if(VBInfo&SetCRT2ToTV){ - tempah=tempah-1; - if(!(temp1&HalfDCLK)){ - if((temp1&Charx8Dot)){ - tempah=tempah+4; - if(VGAHDE>=800){ - tempah=tempah-6; - } - } - } - }else{ - if(!(temp1&HalfDCLK)){ - tempah=tempah-4; - if(VGAHDE>=800){ - tempah=tempah-7; - if(ModeType==ModeEGA){ - if(VGAVDE==1024){ - tempah=tempah+15; - if(LCDResInfo!=Panel1280x1024){ - tempah=tempah+7; - } - } - } - if(VGAHDE>=1280){ - tempah=tempah+28; - } - } - } - } - - SetReg1(Part1Port,0x07,tempah);//0x07 Horizontal Retrace Start - - SetReg1(Part1Port,0x08,0); //0x08 Horizontal Retrace End - SetReg1(Part1Port,0x18,0x03); //0x18 SR08 - SetReg1(Part1Port,0x19,0); //0x19 SR0C - SetReg1(Part1Port,0x09,0xFF); //0x09 Set Max VT - - tempcx=0x121; - tempcl=0x21; - tempch=0x01; - tempbx=VGAVDE; //0x0E Virtical Display End - if(tempbx==360) tempbx=350; - if(tempbx==375) tempbx=350; - if(tempbx==405) tempbx=400; - tempbx--; - tempah=tempbx&0x0FF; - SetReg1(Part1Port,0x0E,tempah); - SetReg1(Part1Port,0x10,tempah);//0x10 vertical Blank Start - tempbh=(tempbx&0xFF00)>>8; - if(tempbh&0x01){ - tempcl=tempcl|0x0A; - } - tempah=0;tempal=0x0B; - if(temp1&DoubleScanMode){ - tempah=tempah|0x080; - } - if(tempbh&0x02){ - tempcl=tempcl|0x040; - tempah=tempah|0x020; - } - SetReg1(Part1Port,0x0B,tempah); - if(tempbh&0x04){ - tempch=tempch|0x06; - } - - SetReg1(Part1Port,0x11,0); //0x11 Vertival Blank End - - tempax=VGAVT-tempbx; //0x0C Vertical Retrace Start - tempax=tempax>>2; - temp2=tempax; //push ax - tempax=tempax<<1; - tempbx=tempax+tempbx; - if((SetFlag&TVSimuMode)&&(VBInfo&SetPALTV)&&(VGAHDE==800)){ - tempbx=tempbx+40; - } - tempah=(tempbx&0x0FF); - SetReg1(Part1Port,0x0C,tempah); - tempbh=(tempbx&0xFF00)>>8; - if(tempbh&0x01){ - tempcl=tempcl|0x04; - } - if(tempbh&0x02){ - tempcl=tempcl|0x080; - } - if(tempbh&0x04){ - tempch=tempch|0x08; - } - - tempax=temp2; //pop ax - tempax=(tempax>>2)+1; - tempbx=tempbx+tempax; - tempah=(tempbx&0x0FF)&0x0F; - SetReg1(Part1Port,0x0D,tempah); //0x0D vertical Retrace End - tempbl=tempbx&0x0FF; - if(tempbl&0x10){ - tempch=tempch|0x020; - } - - tempah=tempcl; - SetReg1(Part1Port,0x0A,tempah); //0x0A CR07 - tempah=tempch; - SetReg1(Part1Port,0x17,tempah); //0x17 SR0A - tempax=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - tempah=(tempax&0xFF00)>>8; - tempah=(tempah>>1)&0x09; - SetReg1(Part1Port,0x16,tempah); //0x16 SR01 - SetReg1(Part1Port,0x0F,0); //0x0F CR14 - SetReg1(Part1Port,0x12,0); //0x12 CR17 - SetReg1(Part1Port,0x1A,0); //0x1A SR0E - - REFIndex=OldREFIndex; //pop di -} - -VOID SetCRT2Offset(USHORT Part1Port,ULONG ROMAddr) -{ - USHORT offset; - if(VBInfo&SetInSlaveMode){ - return; - } - offset=GetOffset(ROMAddr); - SetReg1(Part1Port,0x07,(USHORT)(offset&0xFF)); - SetReg1(Part1Port,0x09,(USHORT)((offset&0xFF00)>>8)); - SetReg1(Part1Port,0x03,(USHORT)(((offset>>3)&0xFF)+1)); -} - -USHORT GetOffset(ULONG ROMAddr) -{ - USHORT tempal,temp1,colordepth; - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+Ext_ModeInfo - tempal=(tempal>>4)&0xFF; - ScreenOffset=*((USHORT *)(ROMAddr+0x206)); // Get ScreeOffset table - tempal=*((UCHAR *)(ROMAddr+ScreenOffset+tempal)); // get ScreenOffset - tempal=tempal&0xFF; - temp1=*((UCHAR *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag - if(temp1&InterlaceMode){ - tempal=tempal<<1; - } - colordepth=GetColorDepth(ROMAddr); - return(tempal*colordepth); -} - -USHORT GetColorDepth(ULONG ROMAddr) -{ - USHORT ColorDepth[6]={1,2,4,4,6,8}; - USHORT temp; - int temp1; - temp=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - temp1=(temp&ModeInfoFlag)-ModeEGA; - if(temp1<0) temp1=0; - return(ColorDepth[temp1]); -} - -VOID SetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - USHORT temp,temp1,temp2,temp3,flag; - USHORT vclk2ptr,latencyindex; - USHORT oldREFIndex,CRT1ModeNo,oldModeIDOffset; - long int longtemp; - - USHORT LatencyFactor[48]={ 88, 80, 78, 72, 70, 00, // 64 bit BQ=2 - 00, 79, 77, 71, 69, 49, // 64 bit BQ=1 - 88, 80, 78, 72, 70, 00, // 128 bit BQ=2 - 00, 72, 70, 64, 62, 44, // 128 bit BQ=1 - 73, 65, 63, 57, 55, 00, // 64 bit BQ=2 - 00, 64, 62, 56, 54, 34, // 64 bit BQ=1 - 78, 70, 68, 62, 60, 00, // 128 bit BQ=2 - 00, 62, 60, 54, 52, 34}; // 128 bit BQ=1 - - oldREFIndex=(USHORT)REFIndex; //push REFIndex(CRT2 now) - oldModeIDOffset=(USHORT)ModeIDOffset; //push ModeIDOffset - - CRT1ModeNo=(UCHAR)GetReg1(P3d4,0x34); //get CRT1 ModeNo - SearchModeID(ROMAddr,CRT1ModeNo); //Get ModeID Table - - GetRatePtr(ROMAddr,CRT1ModeNo); //Set REFIndex-> for crt1 refreshrate - temp1=GetVCLK(ROMAddr,CRT1ModeNo,HwDeviceExtension); - temp2=GetColorTh(ROMAddr); - temp3=GetMCLK(ROMAddr); - temp=((USHORT)(temp1*temp2)/temp3); //temp->bx - temp1=(UCHAR)GetReg1(P3c4,0x14); //SR_14 - temp1=temp1>>6; - temp1=temp1<<1; - if(temp1==0) temp1=1; - temp1=temp1<<2; //temp1->ax - - longtemp=temp1-temp; - - temp2=(USHORT)((28*16)/(int)longtemp); //temp2->cx - if(!((temp2*(int)longtemp)==(28*16))) temp2++; - - if( HwDeviceExtension->jChipID == SIS_Glamour ){ - temp1=CalcDelay(); - }else{ //for Trojan and Spartan - flag=(UCHAR)GetReg1(P3c4,0x14); //SR_14 - if(flag&0x80){ - latencyindex=12; //128 bit - }else{ - latencyindex=0; //64 bit - } - flag=GetQueueConfig(); - if(!(flag&0x01)){ - latencyindex+=24; //GUI timing =0 - } - if(flag&0x10){ - latencyindex+=6; //BQ =2 - } - latencyindex=latencyindex + (flag>>5); - temp1= LatencyFactor[latencyindex]; - temp1=temp1+15; - flag=(UCHAR)GetReg1(P3c4,0x14); //SR_14 - if(!(flag&0x80)){ - temp1=temp1+5; //64 bit - } - } - - temp2=temp2+temp1; - REFIndex=oldREFIndex; //pop REFIndex(CRT2) - ModeIDOffset=oldModeIDOffset; //pop ModeIDOffset - - vclk2ptr=GetVCLK2Ptr(ROMAddr,ModeNo); - temp1=*((USHORT *)(ROMAddr+vclk2ptr+(VCLKLen-2))); - temp3=GetColorTh(ROMAddr); - longtemp=temp1*temp2*temp3; - temp3=GetMCLK(ROMAddr); - temp3=temp3<<4; - temp2=(int)(longtemp/temp3); - if((long int)temp2*(long int)temp3<(long int)longtemp) temp2++; //temp2->cx - - temp1=(UCHAR)GetReg1(Part1Port,0x01); //part1port index 01 - - - if( (HwDeviceExtension->jChipID == SIS_Trojan ) && - ((HwDeviceExtension->revision_id & 0xf0) == 0x30) ) /* 630s */ - { - temp1=(temp1&(~0x1F))|0x19; - }else - { - temp1=(temp1&(~0x1F))|0x16; - } - SetReg1(Part1Port,0x01,temp1); - - if(temp2<=6) temp2=6; - if(temp2>0x14) temp2=0x14; - temp1=(UCHAR)GetReg1(Part1Port,0x02); //part1port index 02 - temp1=(temp1&(~0x1F))|temp2; - SetReg1(Part1Port,0x02,temp1); -} - -USHORT GetVCLK(ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - USHORT tempptr; - USHORT temp1; - tempptr=GetVCLKPtr(ROMAddr,ModeNo); - temp1=*((USHORT *)(ROMAddr+tempptr+(VCLKLen-2))); - - return temp1; -} - -USHORT GetQueueConfig(void) -{ - USHORT tempal,tempbl; - ULONG tempeax; - - SetReg4(0xcf8,0x80000050); - tempeax=GetReg3(0xcfc); - tempeax=(tempeax>>24)&0x0f; - tempbl=(USHORT)tempeax; - tempbl=tempbl<<4; - - SetReg4(0xcf8,0x800000A0); - tempeax=GetReg3(0xcfc); - tempeax=(tempeax>>24)&0x0f; - tempal=(USHORT)tempeax; - tempbl=tempbl|tempal; - - return(tempbl); -} - -USHORT GetVCLKPtr(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT tempal; - tempal=(UCHAR)GetReg2((USHORT)(P3ca+0x02)); // Port 3cch - tempal=((tempal>>2)&0x03); - if(ModeNo>0x13){ - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK - tempal=tempal&0x03F; - } - VCLKLen=GetVCLKLen(ROMAddr); - tempal=tempal*VCLKLen; - tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); // VCLKData - return ((USHORT)tempal); -} - -USHORT GetColorTh(ULONG ROMAddr) -{ - USHORT temp; - temp=GetColorDepth(ROMAddr); - temp=temp>>1; - if(temp==0) temp++; - return temp; -} - -USHORT GetMCLK(ULONG ROMAddr) -{ - USHORT tempmclkptr; - USHORT tempmclk; - tempmclkptr=GetMCLKPtr(ROMAddr); - tempmclk=*((USHORT *)(ROMAddr+tempmclkptr+0x03)); //di+3 - return tempmclk; -} - -USHORT GetMCLKPtr(ULONG ROMAddr) -{ - USHORT tempdi; - USHORT tempdramtype,tempax; - - tempdi=*((USHORT *)(ROMAddr+0x20C)); // MCLKData - tempdramtype=GetDRAMType(ROMAddr); - tempax=5*tempdramtype; - tempdi=tempdi+tempax; - return (tempdi); -} - -USHORT GetDRAMType(ULONG ROMAddr) -{ - USHORT tsoftsetting,temp3; - - tsoftsetting=*((UCHAR *)(ROMAddr+0x52)); - if(!(tsoftsetting&SoftDramType)){ - temp3=(UCHAR)GetReg1(P3c4,0x3A); - tsoftsetting=temp3; - } - tsoftsetting=tsoftsetting&0x07; - return(tsoftsetting); -} - -static USHORT CalcDelay() -{ - USHORT tempal,tempah,temp1,tempbx; - USHORT ThTiming[8]={1,2,2,3,0,1,1,2}; - USHORT ThLowB[24]={81,4,72,6,88,8,120,12, - 55,4,54,6,66,8,90,12, - 42,4,45,6,55,8,75,12}; - - tempah=(UCHAR)GetReg1(P3c4,0x18); //SR_18 - tempah=tempah&0x62; - tempah=tempah>>1; - tempal=tempah; - tempah=tempah>>3; - tempal=tempal|tempah; - tempal=tempal&0x07; - - temp1=ThTiming[tempal]; //temp1->cl - - tempbx=(UCHAR)GetReg1(P3c4,0x16); //SR_16 - tempbx=tempbx>>6; - tempah=(UCHAR)GetReg1(P3c4,0x14); //SR_14 - tempah=((tempah>>4)&0x0C); - tempbx=((tempbx|tempah)<<1); - - tempal=ThLowB[tempbx+1]*temp1; - tempbx=ThLowB[tempbx]; - tempbx=tempal+tempbx; - - return(tempbx); -} - -USHORT GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT tempal; - USHORT LCDXlat1VCLK[4]={VCLK65,VCLK65,VCLK65,VCLK65}; - USHORT LCDXlat2VCLK[4]={VCLK108_2,VCLK108_2,VCLK108_2,VCLK108_2}; - - if(ModeNo<=0x13){ - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC - }else{ - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC - } - tempal=tempal>>6; - if(LCDResInfo!=Panel1024x768){ - tempal=LCDXlat2VCLK[tempal]; - }else{ - tempal=LCDXlat1VCLK[tempal]; - } - - if(VBInfo&SetCRT2ToLCD){ - tempal=tempal; - }else if(VBInfo&SetCRT2ToTV){ - if(SetFlag&RPLLDIV2XO){ - tempal=TVVCLKDIV2; - }else{ - tempal=TVVCLK; - } - }else{ - tempal=(UCHAR)GetReg2((USHORT)(P3ca+0x02)); // Port 3cch - tempal=((tempal>>2)&0x03); - if(ModeNo>0x13){ - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK - tempal=tempal&0x03F; - } - } - VCLKLen=GetVCLKLen(ROMAddr); - tempal=tempal*VCLKLen; - tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); // VCLKData - return ((USHORT)tempal); -} - -USHORT GetVCLKLen(ULONG ROMAddr) -{ - USHORT VCLKDataStart,vclklabel,temp; - VCLKDataStart=*((USHORT *)(ROMAddr+0x208)); - for(temp=0;;temp++){ - vclklabel=*((USHORT *)(ROMAddr+VCLKDataStart+temp)); - if(vclklabel==VCLKStartFreq){ - temp=temp+2; - return(temp); - } - } - return(0); -} - - -VOID SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) -{ - USHORT temp1,tempah=0; - USHORT temp; - USHORT Part1Port; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - if(IF_DEF_LVDS==1){ //LVDS - if(VBInfo&SetCRT2ToLCD){ - tempah=LCDInfo; - if(!(tempah&LCDSync)){ - temp=*((USHORT *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag - tempah=(temp>>8)&0x0C0; - }else{ - tempah=tempah&0x0C0; - } - } - }else{ - temp=*((USHORT *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag - tempah=(temp>>8)&0x0C0; - } - temp1=(UCHAR)GetReg1(Part1Port,0x19); //part1port index 02 - temp1=(temp1&(~0x0C0))|tempah; - SetReg1(Part1Port,0x19,temp1); -} - -VOID GetCRT1Ptr(ULONG ROMAddr) -{ - USHORT temprefcrt1; - USHORT temp; - temp=*((UCHAR *)(ROMAddr+REFIndex+0x02)); //di+Ext_CRT1CRTC - temp=temp&0x03F; - temp=temp*CRT1Len; - temprefcrt1=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table - REFIndex=temprefcrt1+temp; // di->CRT1Table+Ext_CRT1CRTC*CRT1Len -} - -USHORT GetVGAHT2() -{ - long int temp1,temp2; - - temp1=(VGAVT-VGAVDE)*RVBHCMAX; - temp1=temp1&0x0FFFF; - temp2=(VT-VDE)*RVBHCFACT; - temp2=temp2&0x0FFFF; - temp2=temp2*HT; - temp2=temp2/temp1; - return((USHORT)temp2); -} - -VOID SetGroup2(USHORT BaseAddr,ULONG ROMAddr) -{ - USHORT tempah,tempbl,tempbh,tempcl,i,j,tempcx,pushcx,tempbx,tempax; - USHORT tempmodeflag,tempflowflag; - UCHAR *temp1; - USHORT *temp2; - USHORT pushbx; - USHORT Part2Port; - long int longtemp; - - Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; - - tempcx=VBInfo; - tempah=VBInfo&0x0FF; - tempbl=VBInfo&0x0FF; - tempbh=VBInfo&0x0FF; - tempbx=(tempbl&0xFF)|(tempbh<<8); - tempbl=tempbl&0x10; - tempbh=(tempbh&0x04)<<1; - tempah=(tempah&0x08)>>1; - tempah=tempah|tempbh; - tempbl=tempbl>>3; - tempah=tempah|tempbl; - tempah=tempah^0x0C; - - if(VBInfo&SetPALTV){ - temp1=(UCHAR *)(ROMAddr+0x0F1); //PALPhase - temp2=PALTiming; - }else{ - tempah=tempah|0x10; - temp1=(UCHAR *)(ROMAddr+0x0ED); //NTSCPhase - temp2=NTSCTiming; - } - - SetReg1(Part2Port,0x0,tempah); - for(i=0x31;i<=0x34;i++,temp1++){ - SetReg1(Part2Port,i,*(UCHAR *)temp1); - } - for(i=0x01,j=0;i<=0x2D;i++,j++){ - SetReg1(Part2Port,i,temp2[j]); - } - for(i=0x39;i<=0x45;i++,j++){ - SetReg1(Part2Port,i,temp2[j]); //di->temp2[j] - } - - tempah=GetReg1(Part2Port,0x0A); - tempah=tempah|NewFlickerMode; - SetReg1(Part2Port,0x0A,tempah); - - SetReg1(Part2Port,0x35,RY1COE); - SetReg1(Part2Port,0x36,RY2COE); - SetReg1(Part2Port,0x37,RY3COE); - SetReg1(Part2Port,0x38,RY4COE); - - tempcx=HT-1; - tempah=tempcx&0xFF; - SetReg1(Part2Port,0x1B,tempah); - tempah=(tempcx&0xFF00)>>8; - SetRegANDOR(Part2Port,0x1D,~0x0F,(UCHAR)tempah); - - tempcx=HT>>1; - pushcx=tempcx; - - tempcx=tempcx+7; - tempah=(tempcx&0xFF); - tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x22,~0x0F0,tempah); - - - tempbx=temp2[j]; - tempbx=tempbx+tempcx; - tempah=tempbx&0xFF; - SetReg1(Part2Port,0x24,tempah); - tempah=(tempbx&0xFF00)>>8; - tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x25,~0x0F0,tempah); - - tempbx=tempbx+8; - - tempah=((tempbx&0xFF)<<4)&0xFF; - SetRegANDOR(Part2Port,0x29,~0x0F0,tempah); - - tempcx=tempcx+temp2[++j]; - tempah=tempcx&0xFF; - SetReg1(Part2Port,0x27,tempah); - tempah=(((tempcx&0xFF00)>>8)<<4)&0xFF; - SetRegANDOR(Part2Port,0x28,~0x0F0,tempah); - - tempcx=tempcx+8; - - tempah=tempcx&0xFF; - tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x2A,~0x0F0,tempah); - - tempcx=pushcx; //pop cx - tempcx=tempcx-temp2[++j]; - tempah=tempcx&0xFF; - tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x2D,~0x0F0,tempah); - - tempcx=tempcx-11; - if(!(VBInfo&SetCRT2ToTV)){ - tempax=GetVGAHT2(); - tempcx=tempax-1; - } - tempah=tempcx&0xFF; - SetReg1(Part2Port,0x2E,tempah); - - tempbx=VDE; - if(VGAVDE==360){ - tempbx=746; - } - if(VGAVDE==375){ - tempbx=746; - } - if(VGAVDE==405){ - tempbx=853; - } - if((VBInfo&SetCRT2ToTV)){ - tempbx=tempbx>>1; - } - - tempbx=tempbx-2; - tempah=tempbx&0xFF; - SetReg1(Part2Port,0x2F,tempah); - - tempah=(tempcx&0xFF00)>>8; - tempbh=(tempbx&0xFF00)>>8; - tempbh=(tempbh<<6)&0xFF; - tempah=tempah|tempbh; - //assuming <<ifndef>> hivisiontv - tempah=tempah|0x10; - if(!(VBInfo&SetCRT2ToSVIDEO)){ - tempah=tempah|0x20; - } - - SetReg1(Part2Port,0x30,tempah); - - tempbh=0; - tempbx=tempbx&0xFF; - - tempmodeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - tempflowflag=0; - if(!(tempmodeflag&HalfDCLK)){ - tempcx=VGAHDE; - if(tempcx>=HDE){ - tempbh=tempbh|0x20; - tempbx=(tempbh<<8)|(tempbx&0xFF); - tempah=0; - } - } - tempcx=0x0101; - if(!(tempbh&0x20)){ - if(tempmodeflag&HalfDCLK){ - tempcl=((tempcx&0xFF)<<1)&0xFF; - tempcx=(tempcx&0xFF00)|tempcl; - } - pushbx=tempbx; - tempax=VGAHDE; - tempbx=(tempcx&0xFF00)>>8; - longtemp=tempax*tempbx; - tempcx=tempcx&0xFF; - longtemp=longtemp/tempcx; - longtemp=longtemp*8*1024; - tempax=(USHORT)((longtemp)/HDE); - if(tempax*HDE<longtemp){ - tempax=tempax+1; - }else{ - tempax=tempax; - } - tempbx=pushbx; - tempah=((tempax&0xFF00)>>8)&0x01F; - tempbh=tempbh|tempah; - tempah=tempax&0xFF; - } - - SetReg1(Part2Port,0x44,tempah); - tempah=tempbh; - SetRegANDOR(Part2Port,0x45,~0x03F,tempah); - - if(VBInfo&SetCRT2ToTV){ - return; - } - - tempah=0x01; - if(LCDResInfo==Panel1280x1024){ - if(ModeType==ModeEGA){ - if(VGAHDE>=1024){ - tempah=0x02; - } - } - } - SetReg1(Part2Port,0x0B,tempah); - - tempbx=HDE-1; //RHACTE=HDE-1 - tempah=tempbx&0xFF; - SetReg1(Part2Port,0x2C,tempah); - tempah=(tempbx&0xFF00)>>8; - tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x2B,~0x0F0,tempah); - - tempbx=VDE-1; //RTVACTEO=(VDE-1)&0xFF - tempah=tempbx&0xFF; - SetReg1(Part2Port,0x03,tempah); - tempah=((tempbx&0xFF00)>>8)&0x07; - SetRegANDOR(Part2Port,0x0C,~0x07,tempah); - - tempcx=VT-1; - tempah=tempcx&0xFF; //RVTVT=VT-1 - SetReg1(Part2Port,0x19,tempah); - tempah=(tempcx&0xFF00)>>8; - tempah=(tempah<<5)&0xFF; - if(LCDInfo&LCDRGB18Bit){ - tempah=tempah|0x10; - } - SetReg1(Part2Port,0x1A,tempah); - - tempcx++; - if(LCDResInfo==Panel1024x768){ - tempbx=768; - }else{ - tempbx=1024; - } - - if(tempbx==VDE){ - tempax=1; - }else{ - tempax=tempbx; - tempax=(tempax-VDE)>>1; - } - tempcx=tempcx-tempax; //lcdvdes - tempbx=tempbx-tempax; //lcdvdee - - tempah=tempcx&0xFF; //RVEQ1EQ=lcdvdes - SetReg1(Part2Port,0x05,tempah); - tempah=tempbx&0xFF; //RVEQ2EQ=lcdvdee - SetReg1(Part2Port,0x06,tempah); - - tempah=(tempbx&0xFF00)>>8; - tempah=(tempah<<3)&0xFF; - tempah=tempah|((tempcx&0xFF00)>>8); - //RTVACTSE=(lcdvdes&0x700>>8)+(lcdvdee&0x700>>5); - SetReg1(Part2Port,0x02,tempah); - - - tempcx=(VT-VDE)>>4; //(VT-VDE)>>4 - tempbx=(VT+VDE)>>1; - tempah=tempbx&0xFF; //RTVACTEE=lcdvrs - SetReg1(Part2Port,0x04,tempah); - - tempah=(tempbx&0xFF00)>>8; - tempah=(tempah<<4)&0xFF; - tempbx=tempbx+tempcx+1; - tempbl=(tempbx&0x0F); - tempah=tempah|tempbl; //RTVACTSO=lcdvrs&0x700>>4+lcdvre - SetReg1(Part2Port,0x01,tempah); - - tempah=GetReg1(Part2Port,0x09); - tempah=tempah&0xF0; - SetReg1(Part2Port,0x09,tempah); - - tempah=GetReg1(Part2Port,0x0A); - tempah=tempah&0xF0; - SetReg1(Part2Port,0x0A,tempah); - - tempcx=(HT-HDE)>>2; //(HT-HDE)>>2 - tempbx=(HDE+7); //lcdhdee - tempah=tempbx&0xFF; //RHEQPLE=lcdhdee - SetReg1(Part2Port,0x23,tempah); - tempah=(tempbx&0xFF00)>>8; - SetRegANDOR(Part2Port,0x25,~0x0F,tempah); - - SetReg1(Part2Port,0x1F,0x07); //RHBLKE=lcdhdes - tempah=GetReg1(Part2Port,0x20); - tempah=tempah&0x0F; - SetReg1(Part2Port,0x20,tempah); - - tempbx=tempbx+tempcx; - tempah=tempbx&0xFF; //RHBURSTS=lcdhrs - SetReg1(Part2Port,0x1C,tempah); - tempah=(tempbx&0xFF00)>>8; - tempah=(tempah<<4)&0xFF; - SetRegANDOR(Part2Port,0x1D,~0x0F0,tempah); - - tempbx=tempbx+tempcx; - tempah=tempbx&0xFF; //RHSYEXP2S=lcdhre - SetReg1(Part2Port,0x21,tempah); - - tempah=GetReg1(Part2Port,0x17); - tempah=tempah&0xFB; - SetReg1(Part2Port,0x17,tempah); - - tempah=GetReg1(Part2Port,0x18); - tempah=tempah&0xDF; - SetReg1(Part2Port,0x18,tempah); - return; -} - -VOID SetGroup3(USHORT BaseAddr) -{ - USHORT i; - USHORT *tempdi; - USHORT Part3Port; - Part3Port=BaseAddr+IND_SIS_CRT2_PORT_12; - if(VBInfo&SetPALTV){ - tempdi=PALGroup3Data; - }else{ - tempdi=NTSCGroup3Data; - } - - for(i=0;i<=0x3E;i++){ - SetReg1(Part3Port,i,tempdi[i]); - } - return; -} - -VOID SetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) -{ - USHORT Part4Port; - USHORT tempax,tempah,tempcx,tempbx,tempbh,tempch,tempmodeflag; - long int tempebx,tempeax,templong; - Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - - tempax=0x0c; - if(VBInfo&SetCRT2ToTV){ - if(VBInfo&SetInSlaveMode){ - if(!(SetFlag&TVSimuMode)){ - SetFlag=SetFlag|RPLLDIV2XO; - tempax=tempax|0x04000; - } - }else{ - SetFlag=SetFlag|RPLLDIV2XO; - tempax=tempax|0x04000; - } - } - - if(LCDResInfo!=Panel1024x768){ - tempax=tempax|0x08000; - } - tempah=(tempax&0xFF00)>>8; - SetReg1(Part4Port,0x0C,tempah); - - tempah=RVBHCFACT; - SetReg1(Part4Port,0x13,tempah); - - tempbx=RVBHCMAX; - tempah=tempbx&0xFF; - SetReg1(Part4Port,0x14,tempah); - tempbh=(((tempbx&0xFF00)>>8)<<7)&0xFF; - - tempcx=VGAHT-1; - tempah=tempcx&0xFF; - SetReg1(Part4Port,0x16,tempah); - tempch=(((tempcx&0xFF00)>>8)<<3)&0xFF; - tempbh=tempbh|tempch; - - tempcx=VGAVT-1; - if(!(VBInfo&SetCRT2ToTV)){ - tempcx=tempcx-5; - } - tempah=tempcx&0xFF; - SetReg1(Part4Port,0x17,tempah); - tempbh=tempbh|((tempcx&0xFF00)>>8); - tempah=tempbh; - SetReg1(Part4Port,0x15,tempah); - - tempcx=VBInfo; - tempbx=VGAHDE; - tempmodeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(tempmodeflag&HalfDCLK){ - tempbx=tempbx>>1; - } - - if(VBInfo&SetCRT2ToLCD){ - tempah=0; - if(tempbx>800){ - tempah=0x60; - } - }else{ - tempah=0x080; - } - if(LCDResInfo!=Panel1280x1024){ - tempah=tempah|0x0A; - } - - SetRegANDOR(Part4Port,0x0E,~0xEF,tempah); - - tempebx=VDE; - - tempcx=RVBHRS; - tempah=tempcx&0xFF; - SetReg1(Part4Port,0x18,tempah); - - tempeax=VGAVDE; - tempcx=tempcx|0x04000; - tempeax=tempeax-tempebx; - if(tempeax<0){ - tempcx=tempcx^(0x04000); - tempeax=VGAVDE; - } - - templong=(tempeax*256*1024)/tempebx; - if(tempeax*256*1024-templong*tempebx>0){ - tempebx=templong+1; - }else{ - tempebx=templong; - } - - - tempah=(USHORT)(tempebx&0xFF); - SetReg1(Part4Port,0x1B,tempah); - tempah=(USHORT)((tempebx&0xFF00)>>8); - SetReg1(Part4Port,0x1A,tempah); - tempebx=tempebx>>16; - tempah=(USHORT)(tempebx&0xFF); - tempah=(tempah<<4)&0xFF; - tempah=tempah|((tempcx&0xFF00)>>8); - SetReg1(Part4Port,0x19,tempah); - - SetCRT2VCLK(BaseAddr,ROMAddr,ModeNo); -} - -VOID SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo) -{ - USHORT vclk2ptr; - USHORT tempah,temp1; - USHORT Part4Port; - Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - vclk2ptr=GetVCLK2Ptr(ROMAddr,ModeNo); - SetReg1(Part4Port,0x0A,0x01); - tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x01)); //di+1 - SetReg1(Part4Port,0x0B,tempah); - tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x00)); //di - SetReg1(Part4Port,0x0A,tempah); - SetReg1(Part4Port,0x12,0x00); - tempah=0x08; - if(VBInfo&SetCRT2ToRAMDAC){ - tempah=tempah|0x020; - } - temp1=GetReg1(Part4Port,0x12); - tempah=tempah|temp1; - SetReg1(Part4Port,0x12,tempah); -} - -VOID SetGroup5(USHORT BaseAddr,ULONG ROMAddr) -{ - USHORT Part5Port; - USHORT Pindex,Pdata; - Part5Port=BaseAddr+IND_SIS_CRT2_PORT_14+2; - Pindex=Part5Port; - Pdata=Part5Port+1; - if(ModeType==ModeVGA){ - if(!(VBInfo&(SetInSlaveMode|LoadDACFlag|CRT2DisplayFlag))){ - EnableCRT2(); - LoadDAC2(ROMAddr,Part5Port); - } - } - return; -} - -VOID EnableCRT2() -{ - USHORT temp1; - temp1=GetReg1(P3c4,0x1E); - temp1=temp1|0x20; - SetReg1(P3c4,0x1E,temp1); //SR 1E -} - -VOID LoadDAC2(ULONG ROMAddr,USHORT Part5Port) -{ - USHORT data,data2; - USHORT time,i,j,k; - USHORT m,n,o; - USHORT si,di,bx,dl; - USHORT al,ah,dh; - USHORT *table=VGA_DAC; - USHORT Pindex,Pdata; - Pindex=Part5Port; - Pdata=Part5Port+1; - data=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); - data=data&DACInfoFlag; - time=64; - if(data==0x00) table=MDA_DAC; - if(data==0x08) table=CGA_DAC; - if(data==0x10) table=EGA_DAC; - if(data==0x18) { - time=256; - table=VGA_DAC; - } - if(time==256) j=16; - else j=time; - - //SetReg3(P3c6,0xFF); - SetReg3(Pindex,0x00); - - for(i=0;i<j;i++) { - data=table[i]; - for(k=0;k<3;k++) { - data2=0; - if(data&0x01) data2=0x2A; - if(data&0x02) data2=data2+0x15; - SetReg3(Pdata,data2); - data=data>>2; - } - } - - if(time==256) { - for(i=16;i<32;i++) { - data=table[i]; - for(k=0;k<3;k++) SetReg3(Pdata,data); - } - si=32; - for(m=0;m<9;m++) { - di=si; - bx=si+0x04; - dl=0; - for(n=0;n<3;n++) { - for(o=0;o<5;o++) { - dh=table[si]; - ah=table[di]; - al=table[bx]; - si++; - WriteDAC2(Pdata,dl,ah,al,dh); - } // for 5 - si=si-2; - for(o=0;o<3;o++) { - dh=table[bx]; - ah=table[di]; - al=table[si]; - si--; - WriteDAC2(Pdata,dl,ah,al,dh); - } // for 3 - dl++; - } // for 3 - si=si+5; - } // for 9 - } -} - -VOID WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh) -{ - USHORT temp; - USHORT bh,bl; - - bh=ah; - bl=al; - if(dl!=0) { - temp=bh; - bh=dh; - dh=temp; - if(dl==1) { - temp=bl; - bl=dh; - dh=temp; - } - else { - temp=bl; - bl=bh; - bh=temp; - } - } - SetReg3(Pdata,(USHORT)dh); - SetReg3(Pdata,(USHORT)bh); - SetReg3(Pdata,(USHORT)bl); -} - -VOID LockCRT2(USHORT BaseAddr) -{ - USHORT Part1Port; - USHORT Part4Port; - USHORT temp1; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - temp1=GetReg1(Part1Port,0x24); - temp1=temp1&0xFE; - SetReg1(Part1Port,0x24,temp1); -} - -VOID SetLockRegs() -{ - USHORT temp1; - - if((VBInfo&SetInSlaveMode)&&(!(VBInfo&SetCRT2ToRAMDAC))){ - VBLongWait(); - temp1=GetReg1(P3c4,0x32); - temp1=temp1|0x20; - SetReg1(P3c4,0x32,temp1); - VBLongWait(); - } -} - -VOID EnableBridge(USHORT BaseAddr) -{ - USHORT part2_02,part2_05; - USHORT Part2Port,Part1Port; - Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - - if(IF_DEF_LVDS==0){ - part2_02=(UCHAR)GetReg1(Part2Port,0x02); - part2_05=(UCHAR)GetReg1(Part2Port,0x05); - SetReg1(Part2Port,0x02,0x38); - SetReg1(Part2Port,0x05,0xFF); - LongWait(); - SetRegANDOR(Part2Port,0x00,~0x0E0,0x020); - WaitVBRetrace(BaseAddr); - SetReg1(Part2Port,0x02,part2_02); - SetReg1(Part2Port,0x05,part2_05); - }else{ - EnableCRT2(); - UnLockCRT2(BaseAddr); - SetRegANDOR(Part1Port,0x02,~0x040,0x0); - } -} - -USHORT GetLockInfo(USHORT pattern) -{ - USHORT temp1; - temp1=GetReg1(P3d4,0x36); - return(temp1&pattern); -} - -VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr) -{ - USHORT flag1,tempbx,tempbl,tempbh,tempah; - - SetFlag=0; - tempbx=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - tempbl=tempbx&ModeInfoFlag; - ModeType=tempbl; - tempbx=0; - flag1=GetReg1(P3c4,0x38); //call BridgeisOn - if(!(flag1&0x20)){ - VBInfo=CRT2DisplayFlag; - return; - } - tempbl=GetReg1(P3d4,0x30); - tempbh=GetReg1(P3d4,0x31); - if(!(tempbl&0x07C)){ - VBInfo=CRT2DisplayFlag; - return; - } - if(IF_DEF_LVDS==1){ //for LVDS - if(!(tempbl&SetCRT2ToLCD)){ - VBInfo=CRT2DisplayFlag; - return; - } - } - if(IF_DEF_LVDS==0){ //for 301 - if(tempbl&SetCRT2ToRAMDAC){ - tempbl=tempbl&(SetCRT2ToRAMDAC|SwitchToCRT2|SetSimuScanMode); - }else if(tempbl&SetCRT2ToLCD){ - tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode); - }else if(tempbl&SetCRT2ToSCART){ - tempbl=tempbl&(SetCRT2ToSCART|SwitchToCRT2|SetSimuScanMode); - }else if(tempbl&SetCRT2ToHiVisionTV){ - tempbl=tempbl&(SetCRT2ToHiVisionTV|SwitchToCRT2|SetSimuScanMode); - } - }else{ //for LVDS - if(tempbl&SetCRT2ToLCD){ - tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode); - } - } - tempah=GetReg1(P3d4,0x31); - if(tempah&(CRT2DisplayFlag>>8)){ - if(!(tempbl&(SwitchToCRT2|SetSimuScanMode))){ - tempbx=SetSimuScanMode|CRT2DisplayFlag; - tempbh=((tempbx&0xFF00)>>8); - tempbl=tempbx&0xFF; - } - } - if(!(tempbh&(DriverMode>>8))){ - tempbl=tempbl|SetSimuScanMode; - } - VBInfo=tempbl|(tempbh<<8); - if(!(VBInfo&SetSimuScanMode)){ - if(!(VBInfo&SwitchToCRT2)){ - if(BridgeIsEnable(BaseAddr)){ - if(BridgeInSlave()){ - VBInfo=VBInfo|SetSimuScanMode; - } - } - } - } - if(!((VBInfo&(SetSimuScanMode|SwitchToCRT2)))){ - return; - } - if(!(VBInfo&DriverMode)){ - VBInfo=VBInfo|SetInSlaveMode; - if((VBInfo&SetCRT2ToTV)&&(!(VBInfo&SetNotSimuTVMode))){ - SetFlag=SetFlag|TVSimuMode; - } - return; - } - flag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(!(flag1&(CRT2Mode|CRT2DisplayFlag))){ - VBInfo=VBInfo|SetInSlaveMode; - if((VBInfo&SetCRT2ToTV)&&(!(VBInfo&SetNotSimuTVMode))){ - SetFlag=SetFlag|TVSimuMode; - } - } -} - -BOOLEAN BridgeIsEnable(USHORT BaseAddr) -{ - USHORT flag1; - USHORT Part1Port; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - - if(IF_DEF_LVDS==1){ - return 1; - } - flag1=GetReg1(P3c4,0x38); //call BridgeisOn - if(!(flag1&0x20)){ return 0;} - flag1=GetReg1(Part1Port,0x0); - if(flag1&0x0a0){ - return 1; - }else{ - return 0; - } -} - -BOOLEAN BridgeInSlave() -{ - USHORT flag1; - flag1=GetReg1(P3d4,0x31); - if(flag1&(SetInSlaveMode>>8)){ - return 1; - }else{ - return 0; - } -} - -BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4) -{ - USHORT tempah,tempbh,tempflag; - - tempah=(UCHAR)GetReg1(P3d4,0x36); - tempbh=tempah; - tempah=tempah&0x0F; - if(tempah>Panel1280x1024) tempah=Panel1024x768; - LCDResInfo=tempah; - tempbh=tempbh>>4; - LCDTypeInfo=tempbh; - - tempah=(UCHAR)GetReg1(P3d4,0x37); - LCDInfo=tempah; - if(IF_DEF_TRUMPION){ - LCDInfo=LCDInfo&(~LCDNonExpanding); - } - if(IF_DEF_LVDS==1){ - tempflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(tempflag&HalfDCLK){ - if(IF_DEF_TRUMPION==0){ - if(!(LCDInfo&LCDNonExpanding)){ - if(LCDResInfo==Panel1024x768){ - tempflag=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo - if(tempflag==4){ //512x384 - SetFlag=SetFlag|EnableLVDSDDA; - } - }else{ - if(LCDResInfo==Panel800x600){ - tempflag=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo - if(tempflag==3){ //400x300 - SetFlag=SetFlag|EnableLVDSDDA; - } - } - } - }else{ - SetFlag=SetFlag|EnableLVDSDDA; - } - }else{ - SetFlag=SetFlag|EnableLVDSDDA; - } - } - } - - if(!(VBInfo&SetCRT2ToLCD)){ - return 1; - } - if(!(VBInfo&(SetSimuScanMode|SwitchToCRT2))){ - return 1; - } - if(VBInfo&SetInSlaveMode){ - if(VBInfo&SetNotSimuTVMode){ - SetFlag=SetFlag|LCDVESATiming; - } - }else{ - SetFlag=SetFlag|LCDVESATiming; - } - return 1; -} - -VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - SetReg1(P3d4,0x37,0x00); -} - -BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - USHORT tempah; - tempah=(HwDeviceExtension->usLCDType);// set in sisv.c - //0:no lcd 1:1024x768 2:1280x1024 - if(tempah>0) tempah++; // usLCDType: - // 0:no lcd 1:800x600 2:1024x768 3:1280x1024 - SetReg1(P3d4,0x36,tempah);//cr 36 0:no LCD 1:800x600 2:1024x768 3:1280x1024 - if(tempah>0) return 1; - else return 0; -} - -VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr) -{ - USHORT tempah,temp; - - if(IF_DEF_LVDS==0){ //301 - if(PRIMARY_VGA==1){ //primary vga - if(HwDeviceExtension->jChipID >= SIS_Trojan){ - tempah=GetReg1(P3c4,0x17); - if(tempah&ModeSwitchStatus){ - tempah=GetReg1(P3c4,0x16); - tempah=tempah&ActivePAL; - tempah=tempah>>ActivePALShift; - }else{ - temp=*((UCHAR *)(ROMAddr+SoftSettingAddr)); - if(temp&SoftTVType){ - tempah=*((UCHAR *)(ROMAddr+ModeSettingAddr)); - }else{ - tempah=GetReg1(P3c4,0x38); //SR 38 - } - } - }else{ - temp=*((UCHAR *)(ROMAddr+SoftSettingAddr)); - if(temp&SoftTVType){ - tempah=*((UCHAR *)(ROMAddr+ModeSettingAddr)); - }else{ - tempah=GetReg1(P3c4,0x38); //SR 38 - } - } - tempah=tempah&0x01; //get SR 38 D0 TV Type Selection - //0:NTSC 1:PAL - SetRegANDOR(P3d4,0x31,~0x01,tempah);//set CR 31 D0= SR 38 D0 - } - else{ //Secondary - tempah=GetReg1(P3c4,0x38); //SR 38 - tempah=tempah&0x01; //get SR 38 D0 TV Type Selection - //0:NTSC 1:PAL - SetRegANDOR(P3d4,0x31,~0x01,tempah);//set CR 31 D0= SR 38 D0 - } - return; - }else{ //LVDS - tempah=GetReg1(P3c4,0x16); //SR 16 - tempah=tempah&ActiveNonExpanding; - tempah=tempah>>ActiveNonExpandingShift; - tempah=tempah&0x01; - tempah=tempah<<LCDNonExpandingShift; - SetRegANDOR(P3d4,0x37,~LCDNonExpanding,tempah); - return; - } -} - -BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr) -{ - USHORT flag1,tempbx,tempal,tempah,tempcx,i; - USHORT Part2Port,Part4Port; - USHORT RGBSenseData,YCSenseData,VideoSenseData; - USHORT P2reg0,SenseModeNo,OutputSelect; - Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10; - Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14; - RGBSenseData=*((USHORT *)(ROMAddr+0xF8)); //0:F8 in rompost.asm - YCSenseData=*((USHORT *)(ROMAddr+0xFA)); //0:FA in rompost.asm - VideoSenseData=*((USHORT *)(ROMAddr+0xFC)); //0:FC in rompost.asm - - if(IF_DEF_LVDS==1){ - GetPanelID(); - tempah=LCDSense; - SetRegANDOR(P3d4,0x32,~0x5F,tempah); //Set CR 32 - return 0; - } - - flag1=GetReg1(P3c4,0x38); //call BridgeisOn - if(!(flag1&0x20)){ return 0;} - P2reg0=GetReg1(Part2Port,0x00); //save Part2 Reg index 0 - - if(!(BridgeIsEnable(BaseAddr))){ - SenseModeNo=0x2E; - ModeType=ModeVGA; - VBInfo=SetCRT2ToRAMDAC; - SetFlag=0; - SetCRT2Group(BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension); - //here perform I/O delay ,read SR 05 - for(i=0;i<0x7FFF;i++){ - flag1=GetReg1(P3c4,0x05); - } - } - - SetReg1(Part2Port,0x00,0x1C); //Set part2 index 0= 0x1C - tempah=0; - - OutputSelect=*((UCHAR *)(ROMAddr+0xFE)); //OutputSelect 0:FE in Rompost.asm - if(OutputSelect&SetSCARTOutput){ - tempal=SCARTSense; - }else{ - tempal=Monitor2Sense; - } - tempbx=RGBSenseData; - tempcx=0x0E08; - if(Sense(Part4Port,tempbx,tempcx)){ - if(Sense(Part4Port,tempbx,tempcx)){ - tempah=tempah|tempal; - } - } - tempbx=YCSenseData; - tempcx=0x0604; - if(Sense(Part4Port,tempbx,tempcx)){ - if(Sense(Part4Port,tempbx,tempcx)){ - tempah=tempah|SVIDEOSense; - //Skipped lines about HiTVSense, assuming not HiTV - } - } - - //Assuming not HiTV ,below is of ifndef HiVisionTV - if(OutputSelect&BoardTVType){ - tempbx=VideoSenseData; - tempcx=0x0804; - if(Sense(Part4Port,tempbx,tempcx)){ - if(Sense(Part4Port,tempbx,tempcx)){ - tempah=tempah|AVIDEOSense; - } - } - }else{ - if(!(tempah&SVIDEOSense)){ - tempbx=VideoSenseData; - tempcx=0x0804; - if(Sense(Part4Port,tempbx,tempcx)){ - if(Sense(Part4Port,tempbx,tempcx)){ - tempah=tempah|AVIDEOSense; - } - } - } - } - //end of ifndef HivisionTv - if(SenseLCD(HwDeviceExtension,Part4Port,ROMAddr)){ - if(SenseLCD(HwDeviceExtension,Part4Port,ROMAddr)){ - tempah=tempah|LCDSense; - } - } - - tempbx=0; - tempcx=0; - Sense(Part4Port,tempbx,tempcx); - - SetRegANDOR(P3d4,0x32,~0x5F,tempah); //Set CR 32 - SetReg1(Part2Port,0x00,P2reg0); //recover Part2 reg index 0 - - //here skipped lines about DisableCRT2Display - return 0; -} - -BOOLEAN Sense(USHORT Part4Port,USHORT inputbx,USHORT inputcx) -{ - USHORT tempah,tempcl,tempch; - - tempah=inputbx&0xFF; - SetReg1(Part4Port,0x11,tempah);//Part4 index 11 - tempah=(inputbx&0xFF00)>>8; - tempcl=inputcx&0xFF; - tempah=tempah|tempcl; - SetRegANDOR(Part4Port,0x10,~0x1F,tempah);//Part4 index 10 - - tempch=(inputcx&0xFF00)>>8; - tempch=tempch&0x7F; - //here skipped lines about call Delay - tempah=GetReg1(Part4Port,0x03); //Part4 index 03 - tempah=tempah^(0x0E); - tempah=tempah&tempch; - if(tempah>0) return 1; - else return 0; -} - -BOOLEAN SenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr) -{ - USHORT SoftSetting; - USHORT tempah; - SoftSetting=*((UCHAR *)(ROMAddr+0x52));//0:52 in rompost.asm - if(GetLCDDDCInfo(HwDeviceExtension)){ - return 1; - } - if(SoftSetting&HotPlugFunction){ - tempah=GetReg1(Part4Port,0x0F); - tempah=tempah&0x3F; - SetReg1(Part4Port,0x0F,tempah); //Part4 index 0F - if(Sense(Part4Port,0x0,0x9010)){ - return 1; - }else{ - return 0; - } - }else{ - return 0; - } -} -#endif - -VOID SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR) -{ - USHORT temp1; - temp1=GetReg1(Port,Index); //part1port index 02 - temp1=(temp1&(DataAND))|DataOR; - SetReg1(Port,Index,temp1); -} - -BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension) -{ - USHORT flag1 ; - USHORT DAC_TEST_PARMS[3]={0x0F,0x0F,0x0F}; - USHORT DAC_CLR_PARMS[3]={0x00,0x00,0x00}; - - flag1=GetReg1(P3c4,0x38); //call BridgeisOn - if((flag1&0x20)){ - SetReg1(P3d4,0x30,0x41); - } - - SiSSetMode(HwDeviceExtension,0x2E); //set mode to 0x2E instead of 0x3 - - ClearDAC(P3c8); - ClearALLBuffer(HwDeviceExtension); - - LongWait(); //wait vertical retrace - LongWait(); - - flag1=TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1], - DAC_TEST_PARMS[2]); - if(flag1==0){ - flag1=TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1], - DAC_TEST_PARMS[2]); - } - if(flag1==1){ - SetRegANDOR(P3d4,0x32,~Monitor1Sense,Monitor1Sense); - }else{ - SetRegANDOR(P3d4,0x32,~Monitor1Sense,0x0); - } - TestMonitorType(DAC_CLR_PARMS[0],DAC_CLR_PARMS[1],DAC_CLR_PARMS[2]); - - SetReg1(P3d4,0x34,0x4A); //Preset default CRT1 ModeNo =0x4A - //which is used in SetCRT2FIFO() - return 1; -} - -BOOLEAN TestMonitorType(USHORT d1,USHORT d2,USHORT d3) -{ - USHORT temp; - SetReg3(P3c6,0xFF); - SetReg3(P3c8,0x00); - SetReg3(P3c9,d1); - SetReg3(P3c9,d2); - SetReg3(P3c9,d3); - WaitDisplay(); //wait horizontal retrace - temp=GetReg2(P3c2); - if(temp&0x10) return 1; - else return 0; -} - -VOID WaitDisplay(void) -{ - USHORT temp; - - for(temp=0;temp==0;){ - temp=GetReg2(P3da); - temp=temp&0x01; - } - for(;temp==1;){ - temp=GetReg2(P3da); - temp=temp&0x01; - } -} - -VOID LongWait(void) -{ - USHORT temp; - - for(temp=1;temp>0;){ - temp=GetReg2(P3da); - temp=temp&0x08; - } - for(;temp==0;){ - temp=GetReg2(P3da); - temp=temp&0x08; - } -} - -#ifndef CONFIG_FB_SIS_LINUXBIOS - -VOID VBLongWait(VOID) -{ - USHORT regsr1f,tempah,temp; - - regsr1f=GetReg1(P3c4,0x1F); - tempah=regsr1f&(~0xC0); - SetReg1(P3c4,0x1F,tempah); - - for(temp=1;temp>0;){ - temp=GetReg2(P3da); - temp=temp&0x08; - } - for(;temp==0;){ - temp=GetReg2(P3da); - temp=temp&0x08; - } - - SetReg1(P3c4,0x1F,regsr1f); - return; -} - -BOOLEAN WaitVBRetrace(USHORT BaseAddr) -{ - USHORT temp; - USHORT Part1Port; - Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04; - temp=GetReg1(Part1Port,0x00); - if(!(temp&0x80)){ - return 0; - } - - for(temp=0;temp==0;){ - temp=GetReg1(Part1Port,0x25); - temp=temp&0x01; - } - for(;temp>0;){ - temp=GetReg1(Part1Port,0x25); - temp=temp&0x01; - } - return 1; -} - -BOOLEAN GetPanelID(VOID) -{ - USHORT PanelTypeTable[16]={ SyncPP|Panel800x600|PanelType00, - SyncPP|Panel1024x768|PanelType01, - SyncPP|Panel1024x768|PanelType02, - SyncPP|Panel1024x768|PanelType03, - SyncPP|Panel1024x768|PanelType04, - SyncPP|Panel1024x768|PanelType05, - SyncPP|Panel1024x768|PanelType06, - SyncPP|Panel1024x768|PanelType07, - SyncPP|Panel1024x768|PanelType08, - SyncPP|Panel1024x768|PanelType09, - SyncPP|Panel800x600|PanelType0A, - SyncPP|Panel1024x768|PanelType0B, - SyncPP|Panel1024x768|PanelType0C, - SyncPP|Panel1024x768|PanelType0D, - SyncPP|Panel1024x768|PanelType0E, - SyncPP|Panel1024x768|PanelType0F}; - // Bit 15 BPLVSPLTY - // Bit 14 BPLHSPLTY - // Bit 6-3 Panel Type - // Bit 2-0 Display Resolution(001:800x600 010:1024x768 011:1280x1024) - USHORT tempah,tempbx; - USHORT return_flag; - - tempah=GetReg1(P3c4,0x18); - tempbx=tempah&0x0F; - if(tempah&0x10){ - return_flag=1; - }else{ - return_flag=0; - } - - if(return_flag==0){ - if(IF_DEF_LVDS==1){ - tempbx=0; - tempah=GetReg1(P3c4,0x38); - if(tempah&0x40) tempbx=tempbx|0x08; - if(tempah&0x20) tempbx=tempbx|0x02; - if(tempah&0x01) tempbx=tempbx|0x01; - tempah=GetReg1(P3c4,0x39); - if(tempah&0x80) tempbx=tempbx|0x04; - }else{ - return 0; - } - } - - if(IF_DEF_TRUMPION==1){ - tempbx=1; - } - tempbx=PanelTypeTable[tempbx]; //LVDS table entry - tempbx=tempbx|(USHORT)(LCDSync<<8); - - tempah=tempbx&0x0FF; - SetReg1(P3d4,0x36,tempah); - tempah=(tempbx&0xFF00)>>8; - SetRegANDOR(P3d4,0x37,~LCDSyncBit,tempah); - return 1; -} - -VOID ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT OldREFIndex,temp,tempah,i,modeflag1; - - OldREFIndex=(USHORT)REFIndex; - temp=GetLVDSCRT1Ptr(ROMAddr,ModeNo); - if(temp==0){ - REFIndex=OldREFIndex; - return; - } - tempah=(UCHAR)GetReg1(P3d4,0x11);//unlock cr0-7 - tempah=tempah&0x7F; - SetReg1(P3d4,0x11,tempah); - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3d4,0x0,tempah); - REFIndex++; - for(i=0x02;i<=0x05;REFIndex++){ - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3d4,i,tempah); - } - for(i=0x06;i<=0x07;REFIndex++){ - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3d4,i,tempah); - } - for(i=0x10;i<=0x11;REFIndex++){ - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3d4,i,tempah); - } - for(i=0x15;i<=0x16;REFIndex++){ - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3d4,i,tempah); - } - - for(i=0x0A;i<=0x0C;REFIndex++){ - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3c4,i,tempah); - } - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - tempah=tempah&0x0E0; - SetReg1(P3c4,0x0E,tempah); - - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - tempah=tempah&0x01; - tempah=tempah<<5; - modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(modeflag1&DoubleScanMode){ - tempah=tempah|0x080; - } - SetRegANDOR(P3d4,0x09,~0x020,tempah); - REFIndex=OldREFIndex; - return; -} - -VOID SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo) -{ - USHORT OldREFIndex,tempah,tempal; - USHORT P3cc=P3c9+3; - OldREFIndex=(USHORT)REFIndex; - if(IF_DEF_TRUMPION==0){ //no trumpion - tempal=GetReg2(P3cc); - tempal=tempal&0x0C; - SetReg3(P3c2,tempal); - REFIndex=GetVCLKPtr(ROMAddr,ModeNo); - }else{ //trumpion - SetFlag=SetFlag&(~ProgrammingCRT2); - tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK - tempal=tempal&0x03F; - if(tempal==0x02){ //31.5MHz - REFIndex=REFIndex-Ext2StructSize; - } - REFIndex=GetVCLKPtr(ROMAddr,ModeNo); - SetFlag=SetFlag|ProgrammingCRT2; - } - tempal=0x02B; - if(!(VBInfo&SetInSlaveMode)){ - tempal=tempal+3; - } - tempah=*((UCHAR *)(ROMAddr+REFIndex)); - SetReg1(P3c4,tempal,tempah); - tempah=*((UCHAR *)(ROMAddr+REFIndex+1)); - tempal++; - SetReg1(P3c4,tempal,tempah); - REFIndex=OldREFIndex; - return; -} - -USHORT GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT tempcl,tempbx,tempal,tempptr,LVDSDesPtrData; - tempcl=LVDSDesDataLen; - tempbx=LCDTypeInfo; - if(LCDInfo&LCDNonExpanding){ - tempbx=tempbx+16; - } - if(ModeNo<=0x13){ - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC - }else{ - tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC - } - tempal=tempal&0x1F; - tempal=tempal*tempcl; - tempbx=tempbx<<1; - LVDSDesPtrData=*((USHORT *)(ROMAddr+ADR_LVDSDesPtrData)); - tempptr=*((USHORT *)(ROMAddr+LVDSDesPtrData+tempbx)); - tempptr=tempptr+tempal; - return(tempptr); - -} - -BOOLEAN GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo) -{ - USHORT tempal,tempbx,modeflag1; - USHORT LVDSCRT1DataPtr; - - if(!(VBInfo&SetInSlaveMode)){ - return 0; - } - if(ModeNo<=0x13){ - tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC - }else{ - tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC - } - tempal=tempal&0x3F; - - tempbx=LCDResInfo; - tempbx=tempbx-Panel800x600; - if(LCDInfo&LCDNonExpanding){ - tempbx=tempbx+6; - } - modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag - if(modeflag1&HalfDCLK){ - tempbx=tempbx+3; - } - tempbx=tempbx<<1; - LVDSCRT1DataPtr=*((USHORT *)(ROMAddr+ADR_LVDSCRT1DataPtr)); - REFIndex=*((USHORT *)(ROMAddr+LVDSCRT1DataPtr+tempbx)); - tempal=tempal*LVDSCRT1Len; - REFIndex=REFIndex+tempal; - return 1; -} - -#endif diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/sis_301.h linux/drivers/video/sis/sis_301.h --- v2.4.14/linux/drivers/video/sis/sis_301.h Tue Mar 6 19:28:33 2001 +++ linux/drivers/video/sis/sis_301.h Wed Dec 31 16:00:00 1969 @@ -1,224 +0,0 @@ -#include <linux/config.h> -#include "initdef.h" - -USHORT SetFlag,RVBHCFACT,RVBHCMAX,VGAVT,VGAHT,VT,HT,VGAVDE,VGAHDE; -USHORT VDE,HDE,RVBHRS,NewFlickerMode,RY1COE,RY2COE,RY3COE,RY4COE; -extern USHORT LCDResInfo,LCDTypeInfo,LCDInfo; -USHORT VCLKLen; -USHORT LCDHDES,LCDVDES; - -USHORT StResInfo[5][2]={{640,400},{640,350},{720,400},{720,350},{640,480}}; - -USHORT ModeResInfo[15][4]={{320,200,8,8},{320,240,8,8},{320,400,8,8}, - {400,300,8,8},{512,384,8,8},{640,400,8,16}, - {640,480,8,16},{800,600,8,16},{1024,768,8,16}, - {1280,1024,8,16},{1600,1200,8,16},{1920,1440,8,16}, - {720,480,8,16},{720,576,8,16},{1280,960,8,16}}; - - -USHORT NTSCTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C, - 0x094,0x049,0x001,0x00A,0x006,0x00D,0x004,0x00A, - 0x006,0x014,0x00D,0x004,0x00A,0x000,0x085,0x01B, - 0x00C,0x050,0x000,0x099,0x000,0x0EC,0x04A,0x017, - 0x088,0x000,0x04B,0x000,0x000,0x0E2,0x000,0x002, - 0x003,0x00A,0x065,0x09D,0x008, - 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C, - 0x060,0x014,0x050,0x000,0x040, - 0x00044,0x002DB,0x0003B};//Ajust xxx - -USHORT PALTiming[61]={ 0x019,0x052,0x035,0x06E,0x004,0x038,0x03D,0x070, - 0x094,0x049,0x001,0x012,0x006,0x03E,0x035,0x06D, - 0x006,0x014,0x03E,0x035,0x06D,0x000,0x045,0x02B, - 0x070,0x050,0x000,0x097,0x000,0x0D7,0x05D,0x017, - 0x088,0x000,0x045,0x000,0x000,0x0E8,0x000,0x002, - 0x00D,0x000,0x068,0x0B0,0x00B, - 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C, - 0x060,0x014,0x063,0x000,0x040, - 0x0003E,0x002E1,0x00028};//Ajust xxx - -USHORT HiTVTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C, - 0x094,0x049,0x001,0x00A,0x006,0x00D,0x004,0x00A, - 0x006,0x014,0x00D,0x004,0x00A,0x000,0x085,0x01B, - 0x00C,0x050,0x000,0x099,0x000,0x0EC,0x04A,0x017, - 0x088,0x000,0x04B,0x000,0x000,0x0E2,0x000,0x002, - 0x003,0x00A,0x065,0x09D,0x008, - 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C, - 0x060,0x014,0x050,0x000,0x040, - 0x00027,0x0FFFC,0x0003B};//Ajust xxx - -USHORT HiTVTimingSimu[61]={0x020,0x054,0x02C,0x060,0x008,0x031,0x03A,0x061, - 0x028,0x002,0x001,0x03D,0x006,0x00D,0x004,0x00A, - 0x006,0x014,0x00D,0x004,0x00A,0x000,0x0C5,0x03F, - 0x064,0x090,0x000,0x0AA,0x000,0x006,0x060,0x003, - 0x011,0x005,0x011,0x00F,0x010,0x011,0x000,0x000, - 0x005,0x005,0x034,0x034,0x008, - 0x092,0x00F,0x040,0x060,0x080,0x014,0x090,0x08C, - 0x060,0x004,0x05F,0x000,0x060, - 0x0000E,0x0FFFC,0x00042};//Ajust xxx - -USHORT HiTVGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x05B, - 0x0FF,0x021,0x0AD,0x0AD,0x055,0x077,0x02A,0x0A6, - 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020, - 0x08C,0x06E,0x060,0x02D,0x056,0x047,0x070,0x044, - 0x056,0x036,0x04F,0x06E,0x03F,0x080,0x000,0x080, - 0x045,0x07D,0x003,0x0A5,0x076,0x020,0x01A,0x0A4, - 0x014,0x005,0x003,0x07E,0x064,0x031,0x014,0x075, - 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001}; - -USHORT HiTVGroup3Simu[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x094, - 0x0DA,0x020,0x0B7,0x0B7,0x055,0x047,0x02A,0x0A6, - 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020, - 0x08C,0x06E,0x060,0x015,0x026,0x0D3,0x0E4,0x011, - 0x056,0x036,0x04F,0x06E,0x03F,0x080,0x000,0x080, - 0x066,0x035,0x001,0x047,0x00E,0x010,0x0BE,0x0B4, - 0x001,0x005,0x003,0x07E,0x065,0x031,0x014,0x075, - 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001}; - -USHORT NTSCGroup3Data[63]= {0x000,0x014,0x015,0x025,0x055,0x015,0x00B,0x089, - 0x0D7,0x040,0x0B0,0x0B0,0x0FF,0x0C4,0x045,0x0A6, - 0x025,0x02F,0x067,0x0F6,0x0BF,0x0FF,0x08E,0x020, - 0x08C,0x0DA,0x060,0x092,0x0C8,0x055,0x08B,0x000, - 0x051,0x004,0x018,0x00A,0x0F8,0x087,0x000,0x080, - 0x03B,0x03B,0x000,0x0F0,0x0F0,0x000,0x0F0,0x0F0, - 0x000,0x051,0x00F,0x00F,0x008,0x00F,0x008,0x06F, - 0x018,0x005,0x005,0x005,0x04C,0x0AA,0x001}; - -USHORT PALGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x085, - 0x0C3,0x020,0x0A4,0x0A4,0x055,0x047,0x02A,0x0A6, - 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020, - 0x08C,0x0DC,0x060,0x092,0x0C8,0x04F,0x085,0x000, - 0x056,0x036,0x04F,0x06E,0x0FE,0x083,0x054,0x081, - 0x030,0x030,0x000,0x0F3,0x0F3,0x000,0x0A2,0x0A2, - 0x000,0x048,0x0FE,0x07E,0x008,0x040,0x008,0x091, - 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001}; - -VOID overwriteregs(ULONG ROMAddr, USHORT BaseAddr); -VOID SetDefCRT2ExtRegs(USHORT BaseAddr); -BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -USHORT GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo); -BOOLEAN AjustCRT2Rate(ULONG ROMAddr); -VOID SaveCRT2Info(USHORT ModeNo); -VOID DisableLockRegs(VOID); -VOID DisableCRT2(VOID); -VOID DisableBridge(USHORT BaseAddr); -VOID GetCRT2Data(ULONG ROMAddr,USHORT ModeNo); -VOID GetResInfo(ULONG ROMAddr,USHORT ModeNo); -VOID GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo); -VOID GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo); -VOID UnLockCRT2(USHORT BaseAddr); -VOID SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo); -VOID SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -VOID SetCRT2Offset(USHORT Part1Port,ULONG ROMAddr); -USHORT GetOffset(ULONG ROMAddr); -USHORT GetColorDepth(ULONG ROMAddr); -VOID SetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -USHORT GetVCLK(ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -USHORT GetVCLKPtr(ULONG ROMAddr,USHORT ModeNo); -USHORT GetColorTh(ULONG ROMAddr); -USHORT GetMCLK(ULONG ROMAddr); -USHORT GetMCLKPtr(ULONG ROMAddr); -USHORT GetDRAMType(ULONG ROMAddr); -#ifndef CONFIG_FB_SIS_LINUXBIOS -static USHORT CalcDelay(VOID); -#endif -USHORT GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo); -VOID SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo); -VOID GetCRT1Ptr(ULONG ROMAddr); -VOID SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR); -USHORT GetVGAHT2(VOID); -VOID SetGroup2(USHORT BaseAddr,ULONG ROMAddr); -VOID SetGroup3(USHORT BaseAddr); -VOID SetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo); -VOID SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo); -VOID SetGroup5(USHORT BaseAddr,ULONG ROMAddr); -VOID EnableCRT2(VOID); -VOID LoadDAC2(ULONG ROMAddr,USHORT Part5Port); -VOID WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh); -VOID LockCRT2(USHORT BaseAddr); -VOID SetLockRegs(VOID); -VOID EnableBridge(USHORT BaseAddr); -USHORT GetLockInfo(USHORT pattern); -VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr); -BOOLEAN BridgeIsEnable(USHORT BaseAddr); -BOOLEAN BridgeInSlave(VOID); -BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4); -VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension); -BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension); -VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr); -BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr); -BOOLEAN Sense(USHORT Part4Port,USHORT inputbx,USHORT inputcx); -BOOLEAN SenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr); -BOOLEAN TestMonitorType(USHORT d1,USHORT d2,USHORT d3); -VOID WaitDisplay(VOID); -BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension); -VOID LongWait(VOID); -//VOID ClearALLBuffer(PHW_DEVICE_EXTENSION HwDeviceExtension); -USHORT GetQueueConfig(VOID); -VOID VBLongWait(VOID); -USHORT GetVCLKLen(ULONG ROMAddr); -BOOLEAN WaitVBRetrace(USHORT BaseAddr); -VOID GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo); -VOID ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo); -VOID SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo); -VOID GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo); -VOID GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo); -USHORT GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo); -VOID SetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -VOID SetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, - PHW_DEVICE_EXTENSION HwDeviceExtension); -VOID SetTPData(VOID); -BOOLEAN GetPanelID(VOID); -BOOLEAN GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo); - -extern USHORT DRAMType[17][5]; -extern USHORT MDA_DAC[]; -extern USHORT CGA_DAC[]; -extern USHORT EGA_DAC[]; -extern USHORT VGA_DAC[]; - -extern USHORT P3c4,P3d4,P3c0,P3ce,P3c2,P3ca,P3c6,P3c7,P3c8,P3c9,P3da; -extern USHORT flag_clearbuffer; //0:no clear frame buffer 1:clear frame buffer -extern int RAMType; -extern int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,VCLKData,MCLKData, ECLKData; -extern int REFIndex,ModeType; -extern USHORT VBInfo,LCDResInfo,LCDTypeInfo,LCDInfo; -extern USHORT IF_DEF_LVDS,IF_DEF_TRUMPION; - -extern VOID SetMemoryClock(ULONG); -extern VOID SetDRAMSize(PHW_DEVICE_EXTENSION); -extern BOOLEAN SearchModeID(ULONG, USHORT); -extern BOOLEAN CheckMemorySize(ULONG); -extern VOID GetModePtr(ULONG, USHORT); -extern BOOLEAN GetRatePtr(ULONG, USHORT); -extern VOID SetSeqRegs(ULONG); -extern VOID SetMiscRegs(ULONG); -extern VOID SetCRTCRegs(ULONG); -extern VOID SetATTRegs(ULONG); -extern VOID SetGRCRegs(ULONG); -extern VOID ClearExt1Regs(VOID); -extern VOID SetSync(ULONG); -extern VOID SetCRT1CRTC(ULONG); -extern VOID SetCRT1Offset(ULONG); -extern VOID SetCRT1FIFO(ULONG); -extern VOID SetCRT1VCLK(ULONG); -extern VOID LoadDAC(ULONG); -extern VOID DisplayOn(VOID); -extern VOID SetCRT1ModeRegs(ULONG, USHORT); -extern VOID SetVCLKState(ULONG, USHORT); -extern VOID WriteDAC(USHORT, USHORT, USHORT, USHORT); -extern VOID ClearBuffer(PHW_DEVICE_EXTENSION); -//extern VOID ClearDAC(ULONG); -extern void ClearDAC(u16 port); -extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, - USHORT ModeNo); -extern void SetReg1(u16 port, u16 index, u16 data); -extern void SetReg3(u16 port, u16 data); -extern void SetReg4(u16 port, unsigned long data); -extern u8 GetReg1(u16 port, u16 index); -extern u8 GetReg2(u16 port); -extern u32 GetReg3(u16 port); diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/sis_main.c linux/drivers/video/sis/sis_main.c --- v2.4.14/linux/drivers/video/sis/sis_main.c Mon Nov 5 15:55:33 2001 +++ linux/drivers/video/sis/sis_main.c Fri Nov 9 14:11:14 2001 @@ -1,5 +1,5 @@ /* - * SiS 300/630/540 frame buffer device For Kernal 2.4.x + * SiS 300/630/540/315H/315 frame buffer device For Kernal 2.4.x * * This driver is partly based on the VBE 2.0 compliant graphic * boards framebuffer driver, which is @@ -8,7 +8,7 @@ * */ -#undef SISFBDEBUG +//#undef SISFBDEBUG #include <linux/config.h> #include <linux/module.h> @@ -27,10 +27,13 @@ #include <linux/pci.h> #include <linux/vt_kern.h> #include <linux/capability.h> -#include <linux/sisfb.h> #include <linux/fs.h> +#include <linux/agp_backend.h> +#include <linux/types.h> +#include <linux/sisfb.h> #include <asm/io.h> +#include <asm/mtrr.h> #include <video/fbcon.h> #include <video/fbcon-cfb8.h> @@ -38,568 +41,543 @@ #include <video/fbcon-cfb24.h> #include <video/fbcon-cfb32.h> -#include "sis.h" -#ifdef NOBIOS -#include "bios.h" -#endif - -/* ------------------- Constant Definitions ------------------------- */ - -/* capabilities */ -#define TURBO_QUEUE_CAP 0x80 -#define HW_CURSOR_CAP 0x40 +#include "osdef.h" +#include "vgatypes.h" +#include "sis_main.h" -/* VGA register Offsets */ -#define SEQ_ADR (0x14) -#define SEQ_DATA (0x15) -#define DAC_ADR (0x18) -#define DAC_DATA (0x19) -#define CRTC_ADR (0x24) -#define CRTC_DATA (0x25) +/* -------------------- Macro definitions ---------------------------- */ -#define DAC2_ADR 0x16 - 0x30 -#define DAC2_DATA 0x17 - 0x30 - - -/* SiS indexed register indexes */ -#define IND_SIS_PASSWORD (0x05) -#define IND_SIS_DRAM_SIZE (0x14) -#define IND_SIS_MODULE_ENABLE (0x1E) -#define IND_SIS_PCI_ADDRESS_SET (0x20) -#define IND_SIS_TURBOQUEUE_ADR (0x26) -#define IND_SIS_TURBOQUEUE_SET (0x27) - -/* Sis register value */ -#define SIS_PASSWORD (0x86) - -#define SIS_2D_ENABLE (0x40) +#ifdef SISFBDEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif -#define SIS_MEM_MAP_IO_ENABLE (0x01) -#define SIS_PCI_ADDR_ENABLE (0x80) +#define vgawb(reg,data) \ + (outb(data, ivideo.vga_base+reg)) +#define vgaww(reg,data) \ + (outw(data, ivideo.vga_base+reg)) +#define vgawl(reg,data) \ + (outl(data, ivideo.vga_base+reg)) +#define vgarb(reg) \ + (inb(ivideo.vga_base+reg)) -//#define MMIO_SIZE 0x10000 /* 64K MMIO capability */ -#define MAX_ROM_SCAN 0x10000 +/* --------------- Hardware Access Routines -------------------------- */ -#define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */ -#define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */ +void sisfb_set_reg1 (u16 port, u16 index, u16 data) +{ + outb ((u8) (index & 0xff), port); + port++; + outb ((u8) (data & 0xff), port); +} -/* Mode set stuff */ -#define DEFAULT_MODE 0 /* 640x480x8 */ -#define DEFAULT_LCDMODE 9 /* 800x600x8 */ -#define DEFAULT_TVMODE 9 /* 800x600x8 */ +void sisfb_set_reg3 (u16 port, u16 data) +{ + outb ((u8) (data & 0xff), port); +} -/* heap stuff */ -#define OH_ALLOC_SIZE 4000 -#define SENTINEL 0x7fffffff +void sisfb_set_reg4 (u16 port, unsigned long data) +{ + outl ((u32) (data & 0xffffffff), port); +} -#define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */ -#define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */ +u8 sisfb_get_reg1 (u16 port, u16 index) +{ + u8 data; -/* ------------------- Global Variables ----------------------------- */ + outb ((u8) (index & 0xff), port); + port += 1; + data = inb (port); + return (data); +} -struct video_info ivideo; -HW_DEVICE_EXTENSION HwExt={0,0,0,0,0,0}; +u8 sisfb_get_reg2 (u16 port) +{ + u8 data; -struct GlyInfo { - unsigned char ch; - int fontwidth; - int fontheight; - u8 gmask[72]; - int ngmask; -}; + data = inb (port); -/* Supported SiS Chips list */ -static struct board { - u16 vendor, device; - const char *name; -} dev_list[] = { - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_730_VGA, "SIS 730"}, - {0, 0, NULL} -}; + return (data); +} -/* card parameters */ -unsigned long rom_base; -unsigned long rom_vbase; - -/* mode */ -static int video_type = FB_TYPE_PACKED_PIXELS; -static int video_linelength; -static int video_cmap_len; -static int sisfb_off = 0; -static int crt1off = 0; - -static struct fb_var_screeninfo default_var = { - 0, 0, 0, 0, - 0, 0, - 0, - 0, - {0, 8, 0}, - {0, 8, 0}, - {0, 8, 0}, - {0, 0, 0}, - 0, - FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, - FB_VMODE_NONINTERLACED, - {0, 0, 0, 0, 0, 0} -}; +u32 sisfb_get_reg3 (u16 port) +{ + u32 data; -static struct display disp; -static struct fb_info fb_info; -static struct { - u16 blue, green, red, pad; -} palette[256]; -static union { -#ifdef FBCON_HAS_CFB16 - u16 cfb16[16]; -#endif -#ifdef FBCON_HAS_CFB24 - u32 cfb24[16]; -#endif -#ifdef FBCON_HAS_CFB32 - u32 cfb32[16]; -#endif -} fbcon_cmap; + data = inl (port); + return (data); +} -static int inverse = 0; -static int currcon = 0; +/* --------------- Interface to BIOS code ---------------------------- */ -static struct display_switch sisfb_sw; +BOOLEAN sisfb_query_VGA_config_space (PSIS_HW_DEVICE_INFO psishw_ext, + unsigned long offset, unsigned long set, + unsigned long *value) +{ + static struct pci_dev *pdev = NULL; + static unsigned char init = 0, valid_pdev = 0; -static u8 caps = 0; -static unsigned long MMIO_SIZE = 0; - -/* ModeSet stuff */ -unsigned char uDispType = 0; -int mode_idx = -1; -u8 mode_no = 0; -u8 rate_idx = 0; - -static const struct _sisbios_mode { - char name[15]; - u8 mode_no; - u16 xres; - u16 yres; - u16 bpp; - u16 rate_idx; - u16 cols; - u16 rows; -} sisbios_mode[] = { - {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30}, - {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30}, - {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30}, - {"720x480x8", 0x31, 720, 480, 8, 1, 90, 30}, /* NTSC TV */ - {"720x480x16", 0x33, 720, 480, 16, 1, 90, 30}, - {"720x480x32", 0x35, 720, 480, 32, 1, 90, 30}, - {"720x576x8", 0x32, 720, 576, 8, 1, 90, 36}, /* PAL TV */ - {"720x576x16", 0x34, 720, 576, 16, 1, 90, 36}, - {"720x576x32", 0x36, 720, 576, 32, 1, 90, 36}, - {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37}, - {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37}, - {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37}, - {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48}, - {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48}, - {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48}, - {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64}, - {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64}, - {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64}, - {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75}, - {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75}, - {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75}, - {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75}, - {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75}, - {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75}, - {"\0", 0x00, 0, 0, 0, 0, 0, 0} -}; + if (!set) + DPRINTK ("Get VGA offset 0x%lx\n", offset); + else + DPRINTK ("Set offset 0x%lx to 0x%lx\n", offset, *value); -static struct _vrate { - u16 idx; - u16 xres; - u16 yres; - u16 refresh; -} vrate[] = { - {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85}, - {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200}, - {1, 720, 480, 60}, - {1, 720, 576, 50}, - {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75}, - {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160}, - {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75}, - {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120}, - {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85}, - {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75}, - {5, 1600, 1200, 85}, - {1, 1920, 1440, 60}, - {0, 0, 0, 0} -}; + if (!init) { + init = TRUE; + pci_for_each_dev (pdev) { + DPRINTK ("Current: 0x%x, target: 0x%x\n", pdev->device, + ivideo.chip_id); + if ((pdev->vendor == PCI_VENDOR_ID_SI) + && (pdev->device == ivideo.chip_id)) { + valid_pdev = TRUE; + break; + } + } + } + if (!valid_pdev) { + printk (KERN_DEBUG "Can't find SiS %d VGA device.\n", + ivideo.chip_id); + return FALSE; + } -/* HEAP stuff */ + if (set == 0) + pci_read_config_dword (pdev, offset, (u32 *) value); + else + pci_write_config_dword (pdev, offset, (u32) (*value)); -struct OH { - struct OH *pohNext; - struct OH *pohPrev; - unsigned long ulOffset; - unsigned long ulSize; -}; + return TRUE; +} -struct OHALLOC { - struct OHALLOC *pohaNext; - struct OH aoh[1]; -}; +BOOLEAN sisfb_query_north_bridge_space (PSIS_HW_DEVICE_INFO psishw_ext, + unsigned long offset, unsigned long set, + unsigned long *value) +{ + static struct pci_dev *pdev = NULL; + static unsigned char init = 0, valid_pdev = 0; + u16 nbridge_id = 0; -struct HEAP { - struct OH ohFree; - struct OH ohUsed; - struct OH *pohFreeList; - struct OHALLOC *pohaChain; + if (!init) { + init = TRUE; + switch (ivideo.chip) { + case SIS_540: + nbridge_id = PCI_DEVICE_ID_SI_540; + break; + case SIS_630: + nbridge_id = PCI_DEVICE_ID_SI_630; + break; + case SIS_730: + nbridge_id = PCI_DEVICE_ID_SI_730; + break; + case SIS_550: + nbridge_id = PCI_DEVICE_ID_SI_550; + break; + default: + nbridge_id = 0; + break; + } - unsigned long ulMaxFreeSize; -}; + pci_for_each_dev (pdev) { + DPRINTK ("Current: 0x%x, target: 0x%x\n", pdev->device, + ivideo.chip_id); + if ((pdev->vendor == PCI_VENDOR_ID_SI) + && (pdev->device == nbridge_id)) { + valid_pdev = TRUE; + break; + } + } + } -struct HEAP heap; -unsigned long heap_start; -unsigned long heap_end; -unsigned long heap_size; + if (!valid_pdev) { + printk (KERN_DEBUG "Can't find SiS %d North Bridge device.\n", + nbridge_id); + return FALSE; + } -unsigned int tqueue_pos; -unsigned long hwcursor_vbase; + if (set == 0) + pci_read_config_dword (pdev, offset, (u32 *) value); + else + pci_write_config_dword (pdev, offset, (u32) (*value)); + return TRUE; +} -/* -------------------- Macro definitions --------------------------- */ +/* -------------------- Export functions ----------------------------- */ -#ifdef SISFBDEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) -#else -#define DPRINTK(fmt, args...) -#endif +static void sis_get_glyph (SIS_GLYINFO * gly) +{ + struct display *p = &fb_display[currcon]; + u16 c; + u8 *cdat; + int widthb; + u8 *gbuf = gly->gmask; + int size; -#define vgawb(reg,data) \ - (outb(data, ivideo.vga_base+reg)) -#define vgaww(reg,data) \ - (outw(data, ivideo.vga_base+reg)) -#define vgawl(reg,data) \ - (outl(data, ivideo.vga_base+reg)) -#define vgarb(reg) \ - (inb(ivideo.vga_base+reg)) + gly->fontheight = fontheight (p); + gly->fontwidth = fontwidth (p); + widthb = (fontwidth (p) + 7) / 8; -/* ---------------------- Routine Prototype ------------------------- */ + c = gly->ch & p->charmask; + if (fontwidth (p) <= 8) + cdat = p->fontdata + c * fontheight (p); + else + cdat = p->fontdata + (c * fontheight (p) << 1); -/* Interface used by the world */ -int sisfb_setup(char *options); -static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info); -static int sisfb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int sisfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info); -static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); -static int sisfb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con, - struct fb_info *info); + size = fontheight (p) * widthb; + memcpy (gbuf, cdat, size); + gly->ngmask = size; +} -/* Interface to the low level console driver */ -int sisfb_init(void); -static int sisfb_update_var(int con, struct fb_info *info); -static int sisfb_switch(int con, struct fb_info *info); -static void sisfb_blank(int blank, struct fb_info *info); +void sis_dispinfo (struct ap_data *rec) +{ + rec->minfo.bpp = ivideo.video_bpp; + rec->minfo.xres = ivideo.video_width; + rec->minfo.yres = ivideo.video_height; + rec->minfo.v_xres = ivideo.video_vwidth; + rec->minfo.v_yres = ivideo.video_vheight; + rec->minfo.org_x = ivideo.org_x; + rec->minfo.org_y = ivideo.org_y; + rec->minfo.vrate = ivideo.refresh_rate; + rec->iobase = ivideo.vga_base - 0x30; + rec->mem_size = ivideo.video_size; + rec->disp_state = ivideo.disp_state; + rec->version = (VER_MAJOR << 24) | (VER_MINOR << 16) | VER_LEVEL; + rec->hasVB = ivideo.hasVB; + rec->TV_type = ivideo.TV_type; + rec->TV_plug = ivideo.TV_plug; + rec->chip = ivideo.chip; +} -/* Internal routines */ -static void crtc_to_var(struct fb_var_screeninfo *var); -static void sisfb_set_disp(int con, struct fb_var_screeninfo *var); -static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, - unsigned *blue, unsigned *transp, - struct fb_info *fb_info); -static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *fb_info); -static void do_install_cmap(int con, struct fb_info *info); -static int do_set_var(struct fb_var_screeninfo *var, int isactive, - struct fb_info *info); +/* ------------------ Internal Routines ------------------------------ */ -/* set-mode routines */ -void SetReg1(u16 port, u16 index, u16 data); -void SetReg3(u16 port, u16 data); -void SetReg4(u16 port, unsigned long data); -u8 GetReg1(u16 port, u16 index); -u8 GetReg2(u16 port); -u32 GetReg3(u16 port); -extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension, - USHORT ModeNo); -extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension); -static void pre_setmode(void); -static void post_setmode(void); -static void search_mode(const char *name); -static u8 search_refresh_rate(unsigned int rate); +static void sisfb_search_mode (const char *name) +{ + int i = 0; -/* heap routines */ -static int sisfb_heap_init(void); -static struct OH *poh_new_node(void); -static struct OH *poh_allocate(unsigned long size); -static struct OH *poh_free(unsigned long base); -static void delete_node(struct OH *poh); -static void insert_node(struct OH *pohList, struct OH *poh); -static void free_node(struct OH *poh); + if (name == NULL) + return; -/* ---------------------- Internal Routines ------------------------- */ + while (sisbios_mode[i].mode_no != 0) { + if (!strcmp (name, sisbios_mode[i].name)) { + sisfb_mode_idx = i; + break; + } + i++; + } -inline static u32 RD32(unsigned char *base, s32 off) -{ - return readl(base + off); + if (sisfb_mode_idx < 0) + DPRINTK ("Invalid user mode : %s\n", name); } -inline static void WR32(unsigned char *base, s32 off, u32 v) +static void sisfb_validate_mode (void) { - writel(v, base + off); -} + switch (ivideo.disp_state & DISPTYPE_DISP2) { + case DISPTYPE_LCD: +// Eden Chen + switch (sishw_ext.ulCRT2LCDType) { + case LCD_1024x768: + if (sisbios_mode[sisfb_mode_idx].xres > 1024) + sisfb_mode_idx = -1; + break; + case LCD_1280x1024: + case LCD_1280x960: + if (sisbios_mode[sisfb_mode_idx].xres > 1280) + sisfb_mode_idx = -1; + break; + case LCD_2048x1536: + if (sisbios_mode[sisfb_mode_idx].xres > 2048) + sisfb_mode_idx = -1; + break; + case LCD_1920x1440: + if (sisbios_mode[sisfb_mode_idx].xres > 1920) + sisfb_mode_idx = -1; + break; + case LCD_1600x1200: + if (sisbios_mode[sisfb_mode_idx].xres > 1600) + sisfb_mode_idx = -1; + break; + case LCD_800x600: + if (sisbios_mode[sisfb_mode_idx].xres > 800) + sisfb_mode_idx = -1; + break; + case LCD_640x480: + if (sisbios_mode[sisfb_mode_idx].xres > 640) + sisfb_mode_idx = -1; + break; + default: + sisfb_mode_idx = -1; + } +// ~Eden Chen -inline static void WR16(unsigned char *base, s32 off, u16 v) -{ - writew(v, base + off); + if (sisbios_mode[sisfb_mode_idx].xres == 720) + sisfb_mode_idx = -1; + break; + case DISPTYPE_TV: + switch (sisbios_mode[sisfb_mode_idx].xres) { + case 800: + case 640: + break; + case 720: + if (ivideo.TV_type == TVMODE_NTSC) { + if (sisbios_mode[sisfb_mode_idx].yres != 480) + sisfb_mode_idx = -1; + } else if (ivideo.TV_type == TVMODE_PAL) { + if (sisbios_mode[sisfb_mode_idx].yres != 576) + sisfb_mode_idx = -1; + } + break; + /*karl */ + case 1024: + if (ivideo.TV_type == TVMODE_NTSC) { + if (sisbios_mode[sisfb_mode_idx].bpp == 32) + sisfb_mode_idx -= 1; + } + break; + default: + sisfb_mode_idx = -1; + } + break; + } } -inline static void WR8(unsigned char *base, s32 off, u8 v) +static u8 sisfb_search_refresh_rate (unsigned int rate) { - writeb(v, base + off); -} + u16 xres, yres; + int i = 0; -inline static u32 regrl(s32 off) -{ - return RD32(ivideo.mmio_vbase, off); -} + xres = sisbios_mode[sisfb_mode_idx].xres; + yres = sisbios_mode[sisfb_mode_idx].yres; -inline static void regwl(s32 off, u32 v) -{ - WR32(ivideo.mmio_vbase, off, v); -} + sisfb_rate_idx = 0; + while ((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) { + if ((sisfb_vrate[i].xres == xres) + && (sisfb_vrate[i].yres == yres)) { + if (sisfb_vrate[i].refresh == rate) { + sisfb_rate_idx = sisfb_vrate[i].idx; + break; + } else if (sisfb_vrate[i].refresh > rate) { + if ((sisfb_vrate[i].refresh - rate) <= 2) { + DPRINTK + ("Adjust rate from %d up to %d\n", + rate, sisfb_vrate[i].refresh); + sisfb_rate_idx = sisfb_vrate[i].idx; + ivideo.refresh_rate = + sisfb_vrate[i].refresh; + } else if (((rate - sisfb_vrate[i - 1].refresh) <= 2) + && (sisfb_vrate[i].idx != 1)) { + DPRINTK("Adjust rate from %d down to %d\n", + rate, sisfb_vrate[i - 1].refresh); + sisfb_rate_idx = sisfb_vrate[i - 1].idx; + ivideo.refresh_rate = sisfb_vrate[i - 1].refresh; + } + break; + } + } + i++; + } + + if (sisfb_rate_idx > 0) { + return sisfb_rate_idx; + } else { + DPRINTK ("Unsupported rate %d for %dx%d mode\n", rate, xres, + yres); + return 0; + } -inline static void regww(s32 off, u16 v) -{ - WR16(ivideo.mmio_vbase, off, v); } -inline static void regwb(s32 off, u8 v) +static int sis_getcolreg (unsigned regno, unsigned *red, unsigned *green, unsigned *blue, + unsigned *transp, struct fb_info *fb_info) { - WR8(ivideo.mmio_vbase, off, v); + if (regno >= video_cmap_len) + return 1; + + *red = palette[regno].red; + *green = palette[regno].green; + *blue = palette[regno].blue; + *transp = 0; + return 0; } -/* - * Get CRTC registers to set var - */ -static void crtc_to_var(struct fb_var_screeninfo *var) +static int sis_setcolreg (unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *fb_info) { - u16 VRE, VBE, VRS, VBS, VDE, VT; - u16 HRE, HBE, HRS, HBS, HDE, HT; - u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata; - int A, B, C, D, E, F, temp; - double hrate, drate; - - vgawb(SEQ_ADR, 0x6); - uSRdata = vgarb(SEQ_DATA); - if (uSRdata & 0x20) - var->vmode = FB_VMODE_INTERLACED; - else - var->vmode = FB_VMODE_NONINTERLACED; + if (regno >= video_cmap_len) + return 1; - switch ((uSRdata & 0x1c) >> 2) { - case 0: - var->bits_per_pixel = 8; - break; - case 2: - var->bits_per_pixel = 16; - break; - case 4: - var->bits_per_pixel = 32; - break; - } + palette[regno].red = red; + palette[regno].green = green; + palette[regno].blue = blue; - switch (var->bits_per_pixel) { + switch (ivideo.video_bpp) { +#ifdef FBCON_HAS_CFB8 case 8: - var->red.length = 6; - var->green.length = 6; - var->blue.length = 6; - video_cmap_len = 256; - break; - case 16: /* RGB 565 */ - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - video_cmap_len = 16; + vgawb (DAC_ADR, regno); + vgawb (DAC_DATA, red >> 10); + vgawb (DAC_DATA, green >> 10); + vgawb (DAC_DATA, blue >> 10); + if (ivideo.disp_state & DISPTYPE_DISP2) { + vgawb (DAC2_ADR, regno); + vgawb (DAC2_DATA, red >> 8); + vgawb (DAC2_DATA, green >> 8); + vgawb (DAC2_DATA, blue >> 8); + } break; - case 24: /* RGB 888 */ - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - video_cmap_len = 16; +#endif +#ifdef FBCON_HAS_CFB16 + case 15: + case 16: + fbcon_cmap.cfb16[regno] = + ((red & 0xf800)) | + ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 24: + red >>= 8; + green >>= 8; + blue >>= 8; + fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | (blue); break; +#endif +#ifdef FBCON_HAS_CFB32 case 32: - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - video_cmap_len = 16; + red >>= 8; + green >>= 8; + blue >>= 8; + fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue); break; +#endif } + return 0; +} - vgawb(SEQ_ADR, 0xa); - uSRdata = vgarb(SEQ_DATA); - - vgawb(CRTC_ADR, 0x6); - uCRdata = vgarb(CRTC_DATA); - vgawb(CRTC_ADR, 0x7); - uCRdata2 = vgarb(CRTC_DATA); - VT = - (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) | - ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) << - 10); - A = VT + 2; - - vgawb(CRTC_ADR, 0x12); - uCRdata = vgarb(CRTC_DATA); - VDE = - (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) | - ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9); - E = VDE + 1; - - vgawb(CRTC_ADR, 0x10); - uCRdata = vgarb(CRTC_DATA); - VRS = - (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) | - ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7); - F = VRS + 1 - E; - - vgawb(CRTC_ADR, 0x15); - uCRdata = vgarb(CRTC_DATA); - vgawb(CRTC_ADR, 0x9); - uCRdata3 = vgarb(CRTC_DATA); - VBS = - (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) | - ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8); - - vgawb(CRTC_ADR, 0x16); - uCRdata = vgarb(CRTC_DATA); - VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4); - temp = VBE - ((E - 1) & 511); - B = (temp > 0) ? temp : (temp + 512); - - vgawb(CRTC_ADR, 0x11); - uCRdata = vgarb(CRTC_DATA); - VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1); - temp = VRE - ((E + F - 1) & 31); - C = (temp > 0) ? temp : (temp + 32); - - D = B - F - C; - - var->yres = var->yres_virtual = E; - var->upper_margin = D; - var->lower_margin = F; - var->vsync_len = C; - - vgawb(SEQ_ADR, 0xb); - uSRdata = vgarb(SEQ_DATA); - - vgawb(CRTC_ADR, 0x0); - uCRdata = vgarb(CRTC_DATA); - HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8); - A = HT + 5; - - vgawb(CRTC_ADR, 0x1); - uCRdata = vgarb(CRTC_DATA); - HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6); - E = HDE + 1; +static int sisfb_do_set_var (struct fb_var_screeninfo *var, int isactive, + struct fb_info *info) +{ + unsigned int htotal = + var->left_margin + var->xres + var->right_margin + var->hsync_len; + unsigned int vtotal = + var->upper_margin + var->yres + var->lower_margin + var->vsync_len; + double drate = 0, hrate = 0; + int found_mode = 0; + int old_mode; - vgawb(CRTC_ADR, 0x4); - uCRdata = vgarb(CRTC_DATA); - HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2); - F = HRS - E - 3; + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) + vtotal <<= 1; + else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) + vtotal <<= 2; + else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + var->yres <<= 1; - vgawb(CRTC_ADR, 0x2); - uCRdata = vgarb(CRTC_DATA); - HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4); - - vgawb(SEQ_ADR, 0xc); - uSRdata = vgarb(SEQ_DATA); - vgawb(CRTC_ADR, 0x3); - uCRdata = vgarb(CRTC_DATA); - vgawb(CRTC_ADR, 0x5); - uCRdata2 = vgarb(CRTC_DATA); - HBE = - (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) | - ((u16) (uSRdata & 0x03) << 6); - HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3); + if (!htotal || !vtotal) { + DPRINTK ("Invalid 'var' Information!\n"); + return -EINVAL; + } - temp = HBE - ((E - 1) & 255); - B = (temp > 0) ? temp : (temp + 256); + drate = 1E12 / var->pixclock; + hrate = drate / htotal; + ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5); - temp = HRE - ((E + F + 3) & 63); - C = (temp > 0) ? temp : (temp + 64); + DPRINTK ("Chagne mode to %dx%dx%d-%dMHz\n", + var->xres, var->yres, var->bits_per_pixel, + ivideo.refresh_rate); + + old_mode = sisfb_mode_idx; + sisfb_mode_idx = 0; + + while ((sisbios_mode[sisfb_mode_idx].mode_no != 0) + && (sisbios_mode[sisfb_mode_idx].xres <= var->xres)) { + if ((sisbios_mode[sisfb_mode_idx].xres == var->xres) + && (sisbios_mode[sisfb_mode_idx].yres == var->yres) + && (sisbios_mode[sisfb_mode_idx].bpp == + var->bits_per_pixel)) { + sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no; + found_mode = 1; + break; + } + sisfb_mode_idx++; + } - D = B - F - C; + if (found_mode) + sisfb_validate_mode (); + else + sisfb_mode_idx = -1; - var->xres = var->xres_virtual = E * 8; - var->left_margin = D * 8; - var->right_margin = F * 8; - var->hsync_len = C * 8; + if (sisfb_mode_idx < 0) { + DPRINTK ("sisfb does not support mode %dx%d-%d\n", var->xres, + var->yres, var->bits_per_pixel); + sisfb_mode_idx = old_mode; + return -EINVAL; + } - var->activate = FB_ACTIVATE_NOW; + if (sisfb_search_refresh_rate (ivideo.refresh_rate) == 0) { + sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx; + ivideo.refresh_rate = 60; + } - var->sync = 0; + if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) { + sisfb_pre_setmode (); - uMRdata = vgarb(0x1C); - if (uMRdata & 0x80) - var->sync &= ~FB_SYNC_VERT_HIGH_ACT; - else - var->sync |= FB_SYNC_VERT_HIGH_ACT; +// Eden Chen +/* +#ifdef CONFIG_FB_SIS_300 + if (SiSSetMode(&sishw_ext, sisfb_mode_no)) { + DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no); + return -1; + } +#endif - if (uMRdata & 0x40) - var->sync &= ~FB_SYNC_HOR_HIGH_ACT; - else - var->sync |= FB_SYNC_HOR_HIGH_ACT; +#ifdef CONFIG_FB_SIS_315 + if (SiSSetMode310(&sishw_ext, sisfb_mode_no)) { + DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no); + return -1; + } - VT += 2; - VT <<= 1; - HT = (HT + 5) * 8; +#endif +*/ + if (SiSSetMode (&sishw_ext, sisfb_mode_no) == 0) { + DPRINTK ("set mode[0x%x]: failed\n", sisfb_mode_no); + return -1; + } + + vgawb (SEQ_ADR, IND_SIS_PASSWORD); + vgawb (SEQ_DATA, SIS_PASSWORD); +// ~Eden Chen + sisfb_post_setmode (); + + DPRINTK ("Set New Mode : %dx%dx%d-%d \n", + sisbios_mode[sisfb_mode_idx].xres, + sisbios_mode[sisfb_mode_idx].yres, + sisbios_mode[sisfb_mode_idx].bpp, ivideo.refresh_rate); + + ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp; + ivideo.video_vwidth = ivideo.video_width = + sisbios_mode[sisfb_mode_idx].xres; + ivideo.video_vheight = ivideo.video_height = + sisbios_mode[sisfb_mode_idx].yres; + ivideo.org_x = ivideo.org_y = 0; + video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3); - hrate = (double) ivideo.refresh_rate * (double) VT / 2; - drate = hrate * HT; - var->pixclock = (u32) (1E12 / drate); + } + return 0; } -static void sisfb_set_disp(int con, struct fb_var_screeninfo *var) +static void sisfb_set_disp (int con, struct fb_var_screeninfo *var) { struct fb_fix_screeninfo fix; struct display *display; struct display_switch *sw; - long flags; + u32 flags; if (con >= 0) display = &fb_display[con]; else - display = &disp; /* used during initialization */ + display = &disp; - sisfb_get_fix(&fix, con, 0); + sisfb_get_fix (&fix, con, 0); display->screen_base = ivideo.video_vbase; display->visual = fix.visual; @@ -609,12 +587,11 @@ display->ywrapstep = fix.ywrapstep; display->line_length = fix.line_length; display->next_line = fix.line_length; - /*display->can_soft_blank = 1; */ display->can_soft_blank = 0; - display->inverse = inverse; + display->inverse = sisfb_inverse; display->var = *var; - save_flags(flags); + save_flags (flags); switch (ivideo.video_bpp) { #ifdef FBCON_HAS_CFB8 case 8: @@ -644,852 +621,1380 @@ sw = &fbcon_dummy; return; } - memcpy(&sisfb_sw, sw, sizeof(*sw)); + memcpy (&sisfb_sw, sw, sizeof (*sw)); display->dispsw = &sisfb_sw; - restore_flags(flags); + restore_flags (flags); display->scrollmode = SCROLL_YREDRAW; sisfb_sw.bmove = fbcon_redraw_bmove; - } -/* - * Read a single color register and split it into colors/transparent. - * Return != 0 for invalid regno. - */ -static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, - unsigned *transp, struct fb_info *fb_info) +static void sisfb_do_install_cmap (int con, struct fb_info *info) { - if (regno >= video_cmap_len) - return 1; + if (con != currcon) + return; - *red = palette[regno].red; - *green = palette[regno].green; - *blue = palette[regno].blue; - *transp = 0; - return 0; + if (fb_display[con].cmap.len) + fb_set_cmap (&fb_display[con].cmap, 1, sis_setcolreg, info); + else + fb_set_cmap (fb_default_cmap (video_cmap_len), 1, + sis_setcolreg, info); } -/* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ -static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, - unsigned transp, struct fb_info *fb_info) -{ - - if (regno >= video_cmap_len) - return 1; - - palette[regno].red = red; - palette[regno].green = green; - palette[regno].blue = blue; +/* --------------- Chip-dependent Routines --------------------------- */ - switch (ivideo.video_bpp) { -#ifdef FBCON_HAS_CFB8 - case 8: - vgawb(DAC_ADR, regno); - vgawb(DAC_DATA, red >> 10); - vgawb(DAC_DATA, green >> 10); - vgawb(DAC_DATA, blue >> 10); - if(uDispType & MASK_DISPTYPE_DISP2) - { - /* VB connected */ - vgawb(DAC2_ADR, regno); - vgawb(DAC2_DATA, red >> 8); - vgawb(DAC2_DATA, green >> 8); - vgawb(DAC2_DATA, blue >> 8); - } +#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */ +static int sisfb_get_dram_size_300 (void) +{ + struct pci_dev *pdev = NULL; + int pdev_valid = 0; + u8 pci_data, reg; + u16 nbridge_id; + switch (ivideo.chip) { + case SIS_540: + nbridge_id = PCI_DEVICE_ID_SI_540; break; -#endif -#ifdef FBCON_HAS_CFB16 - case 15: - case 16: - fbcon_cmap.cfb16[regno] = - ((red & 0xf800)) | - ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + case SIS_630: + nbridge_id = PCI_DEVICE_ID_SI_630; break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - red >>= 8; - green >>= 8; - blue >>= 8; - fbcon_cmap.cfb24[regno] = - (red << 16) | (green << 8) | (blue); + case SIS_730: + nbridge_id = PCI_DEVICE_ID_SI_730; break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - red >>= 8; - green >>= 8; - blue >>= 8; - fbcon_cmap.cfb32[regno] = - (red << 16) | (green << 8) | (blue); + default: + nbridge_id = 0; break; -#endif } - return 0; -} -static void do_install_cmap(int con, struct fb_info *info) -{ - if (con != currcon) - return; + if (nbridge_id == 0) { + vgawb (SEQ_ADR, IND_SIS_DRAM_SIZE); + ivideo.video_size = + ((unsigned + int) ((vgarb (SEQ_DATA) & SIS_DRAM_SIZE_MASK) + 1) << 20); + } else { + pci_for_each_dev (pdev) { + if ((pdev->vendor == PCI_VENDOR_ID_SI) + && (pdev->device == nbridge_id)) { + //&& (pdev->device == PCI_DEVICE_ID_SI_630)) { + pci_read_config_byte (pdev, IND_BRI_DRAM_STATUS, + &pci_data); + pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; + ivideo.video_size = + (unsigned int) (1 << (pci_data + 21)); + pdev_valid = 1; - if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info); - else - fb_set_cmap(fb_default_cmap(video_cmap_len), 1, - sis_setcolreg, info); + reg = SIS_DATA_BUS_64 << 6; + vgawb (SEQ_ADR, IND_SIS_DRAM_SIZE); + switch (pci_data) { + case BRI_DRAM_SIZE_2MB: + reg |= SIS_DRAM_SIZE_2MB; + break; + case BRI_DRAM_SIZE_4MB: + reg |= SIS_DRAM_SIZE_4MB; + break; + case BRI_DRAM_SIZE_8MB: + reg |= SIS_DRAM_SIZE_8MB; + break; + case BRI_DRAM_SIZE_16MB: + reg |= SIS_DRAM_SIZE_16MB; + break; + case BRI_DRAM_SIZE_32MB: + reg |= SIS_DRAM_SIZE_32MB; + break; + case BRI_DRAM_SIZE_64MB: + reg |= SIS_DRAM_SIZE_64MB; + break; + } + vgawb (SEQ_DATA, reg); + break; + } + } + + if (!pdev_valid) + return -1; + } + + return 0; } -static int do_set_var(struct fb_var_screeninfo *var, int isactive, - struct fb_info *info) +static void sisfb_detect_VB_connect_300(void) { - unsigned int htotal = - var->left_margin + var->xres + var->right_margin + - var->hsync_len; - unsigned int vtotal = - var->upper_margin + var->yres + var->lower_margin + - var->vsync_len; - double drate = 0, hrate = 0; - int found_mode = 0; - int old_mode; + u8 sr16, sr17, cr32, temp; - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) - vtotal <<= 1; - else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) - vtotal <<= 2; - else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) - var->yres <<= 1; + vgawb (SEQ_ADR, IND_SIS_SCRATCH_REG_17); + sr17 = vgarb (SEQ_DATA); + vgawb (CRTC_ADR, IND_SIS_SCRATCH_REG_CR32); + cr32 = vgarb (CRTC_DATA); + ivideo.TV_plug = ivideo.TV_type = 0; + if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) { + if ((sr17 & 0x01) && !sisfb_crt1off) + sisfb_crt1off = 0; + else { + if (sr17 & 0x0E) + sisfb_crt1off = 1; + else + sisfb_crt1off = 0; + } - if (!htotal || !vtotal) { - DPRINTK("Invalid 'var' Information!\n"); - return 1; - } + if (sr17 & 0x08) + ivideo.disp_state = DISPTYPE_CRT2; + else if (sr17 & 0x02) + ivideo.disp_state = DISPTYPE_LCD; + else if (sr17 & 0x04) { + ivideo.disp_state = DISPTYPE_TV; + if (sr17 & 0x20) + ivideo.TV_plug = TVPLUG_SVIDEO; + else if (sr17 & 0x10) + ivideo.TV_plug = TVPLUG_COMPOSITE; - drate = 1E12 / var->pixclock; - hrate = drate / htotal; - ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5); + vgawb (SEQ_ADR, IND_SIS_SCRATCH_REG_16); + sr16 = vgarb (SEQ_DATA); + if (sr16 & 0x20) + ivideo.TV_type = TVMODE_PAL; + else + ivideo.TV_type = TVMODE_NTSC; + } else + ivideo.disp_state = 0; + } else { + if ((cr32 & SIS_CRT1) && !sisfb_crt1off) + sisfb_crt1off = 0; + else { + if (cr32 & 0x5F) + sisfb_crt1off = 1; + else + sisfb_crt1off = 0; + } - old_mode = mode_idx; - mode_idx = 0; + if (cr32 & SIS_VB_CRT2) + ivideo.disp_state = DISPTYPE_CRT2; + else if (cr32 & SIS_VB_LCD) + ivideo.disp_state = DISPTYPE_LCD; + else if (cr32 & SIS_VB_TV) { + ivideo.disp_state = DISPTYPE_TV; + if (cr32 & SIS_VB_HIVISION) { + ivideo.TV_type = TVMODE_HIVISION; + ivideo.TV_plug = TVPLUG_SVIDEO; + } else if (cr32 & SIS_VB_SVIDEO) + ivideo.TV_plug = TVPLUG_SVIDEO; + else if (cr32 & SIS_VB_COMPOSITE) + ivideo.TV_plug = TVPLUG_COMPOSITE; + else if (cr32 & SIS_VB_SCART) + ivideo.TV_plug = TVPLUG_SCART; - while ((sisbios_mode[mode_idx].mode_no != 0) - && (sisbios_mode[mode_idx].xres <= var->xres)) { - if ((sisbios_mode[mode_idx].xres == var->xres) - && (sisbios_mode[mode_idx].yres == var->yres) - && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) { - mode_no = sisbios_mode[mode_idx].mode_no; - found_mode = 1; - break; - } - mode_idx++; + if (ivideo.TV_type == 0) { + // Eden Chen + //temp = *((u8 *)(sishw_ext.VirtualRomBase+0x52)); + //if (temp&0x40) { + // temp=*((u8 *)(sishw_ext.VirtualRomBase+0x53)); + //} else { + vgawb (SEQ_ADR, IND_SIS_POWER_ON_TRAP); + temp = vgarb (SEQ_DATA); + //} + // ~Eden Chen + if (temp & 0x01) + ivideo.TV_type = TVMODE_PAL; + else + ivideo.TV_type = TVMODE_NTSC; + } + } else + ivideo.disp_state = 0; } +} - if(found_mode) - { - switch(uDispType & MASK_DISPTYPE_DISP2) - { - case MASK_DISPTYPE_LCD: - switch(HwExt.usLCDType) - { - case LCD1024: - if(var->xres > 1024) - found_mode = 0; - break; - case LCD1280: - if(var->xres > 1280) - found_mode = 0; - break; - case LCD2048: - if(var->xres > 2048) - found_mode = 0; +static void sisfb_get_VB_type_300 (void) +{ + u8 reg; + + if (ivideo.chip != SIS_300) { + if (!sisfb_has_VB_300 ()) { + vgawb (CRTC_ADR, IND_SIS_SCRATCH_REG_CR37); + reg = vgarb (CRTC_DATA); + + switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) { + case SIS_EXTERNAL_CHIP_SIS301: + ivideo.hasVB = HASVB_301; break; - case LCD1920: - if(var->xres > 1920) - found_mode = 0; + case SIS_EXTERNAL_CHIP_LVDS: + ivideo.hasVB = HASVB_LVDS; break; - case LCD1600: - if(var->xres > 1600) - found_mode = 0; + case SIS_EXTERNAL_CHIP_TRUMPION: + ivideo.hasVB = HASVB_TRUMPION; break; - case LCD800: - if(var->xres > 800) - found_mode = 0; + case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL: + ivideo.hasVB = HASVB_LVDS_CHRONTEL; break; - case LCD640: - if(var->xres > 640) - found_mode = 0; + case SIS_EXTERNAL_CHIP_CHRONTEL: + ivideo.hasVB = HASVB_CHRONTEL; break; default: - found_mode = 0; - } - if(var->xres == 720) /* mode only for TV */ - found_mode = 0; - break; - case MASK_DISPTYPE_TV: - switch(var->xres) - { - case 800: - case 640: break; - case 720: - if(ivideo.TV_type == TVMODE_NTSC) - { - if(sisbios_mode[mode_idx].yres != 480) - found_mode = 0; - } - else if(ivideo.TV_type == TVMODE_PAL) - { - if(sisbios_mode[mode_idx].yres != 576) - found_mode = 0; + } + } + } else { + sisfb_has_VB_300 (); + } + + //sishw_ext.hasVB = ivideo.hasVB; +} + +static int sisfb_has_VB_300 (void) +{ + // Eden Chen + //u8 sr38, sr39, vb_chipid; + u8 vb_chipid; + + //vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP); + //sr38 = vgarb(SEQ_DATA); + //vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP2); + //sr39 = vgarb(SEQ_DATA); + vgawb (VB_PART4_ADR, 0x0); + vb_chipid = vgarb (VB_PART4_DATA); + + switch (vb_chipid) { + case 0x01: + ivideo.hasVB = HASVB_301; + break; + case 0x02: + ivideo.hasVB = HASVB_302; + break; + case 0x03: + ivideo.hasVB = HASVB_303; + break; + default: + ivideo.hasVB = HASVB_NONE; + return FALSE; + } + return TRUE; +} + +#endif /* CONFIG_FB_SIS_300 */ + +#ifdef CONFIG_FB_SIS_315 /* for SiS 315H/315 */ +static int sisfb_get_dram_size_315 (void) +{ +#ifdef LINUXBIOS + struct pci_dev *pdev = NULL; + int pdev_valid = 0; + u8 pci_data; +#endif + u8 reg = 0; + + if (ivideo.chip == SIS_550) { +#ifdef LINUXBIOS + pci_for_each_dev (pdev) { + if ((pdev->vendor == PCI_VENDOR_ID_SI) + && (pdev->device == PCI_DEVICE_ID_SI_550)) { + pci_read_config_byte (pdev, IND_BRI_DRAM_STATUS, + &pci_data); + pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; + ivideo.video_size = + (unsigned int) (1 << (pci_data + 21)); + pdev_valid = 1; + + vgawb (SEQ_ADR, IND_SIS_DRAM_SIZE); + reg = vgarb (SEQ_DATA) & 0xC0; + + switch (pci_data) { + //case BRI_DRAM_SIZE_2MB: + // reg |= (SIS315_DRAM_SIZE_2MB << 4); break; + case BRI_DRAM_SIZE_4MB: + reg |= SIS550_DRAM_SIZE_4MB; + break; + case BRI_DRAM_SIZE_8MB: + reg |= SIS550_DRAM_SIZE_8MB; + break; + case BRI_DRAM_SIZE_16MB: + reg |= SIS550_DRAM_SIZE_16MB; + break; + case BRI_DRAM_SIZE_32MB: + reg |= SIS550_DRAM_SIZE_32MB; + break; + case BRI_DRAM_SIZE_64MB: + reg |= SIS550_DRAM_SIZE_64MB; + break; + /* case BRI_DRAM_SIZE_128MB: + reg |= (SIS315_DRAM_SIZE_128MB << 4); break; */ } + + /* TODO : set Dual channel and bus width bits here */ + + vgawb (SEQ_DATA, reg); break; - default: - /* illegal mode */ - found_mode = 0; } + } + + if (!pdev_valid) + return -1; +#else + vgawb (SEQ_ADR, IND_SIS_DRAM_SIZE); + reg = vgarb (SEQ_DATA); + switch (reg & SIS550_DRAM_SIZE_MASK) { + case SIS550_DRAM_SIZE_4MB: + ivideo.video_size = 0x400000; + break; + case SIS550_DRAM_SIZE_8MB: + ivideo.video_size = 0x800000; + break; + case SIS550_DRAM_SIZE_16MB: + ivideo.video_size = 0x1000000; + break; + case SIS550_DRAM_SIZE_24MB: + ivideo.video_size = 0x1800000; + break; + case SIS550_DRAM_SIZE_32MB: + ivideo.video_size = 0x2000000; + break; + case SIS550_DRAM_SIZE_64MB: + ivideo.video_size = 0x4000000; + break; + case SIS550_DRAM_SIZE_96MB: + ivideo.video_size = 0x6000000; + break; + case SIS550_DRAM_SIZE_128MB: + ivideo.video_size = 0x8000000; + break; + case SIS550_DRAM_SIZE_256MB: + ivideo.video_size = 0x10000000; + break; + default: + return -1; + } +#endif + return 0; + } else { + vgawb (SEQ_ADR, IND_SIS_DRAM_SIZE); + reg = vgarb (SEQ_DATA); + switch ((reg & SIS315_DRAM_SIZE_MASK) >> 4) { + case SIS315_DRAM_SIZE_2MB: + ivideo.video_size = 0x200000; + break; + case SIS315_DRAM_SIZE_4MB: + ivideo.video_size = 0x400000; + break; + case SIS315_DRAM_SIZE_8MB: + ivideo.video_size = 0x800000; + break; + case SIS315_DRAM_SIZE_16MB: + ivideo.video_size = 0x1000000; break; + case SIS315_DRAM_SIZE_32MB: + ivideo.video_size = 0x2000000; + break; + case SIS315_DRAM_SIZE_64MB: + ivideo.video_size = 0x4000000; + break; + case SIS315_DRAM_SIZE_128MB: + ivideo.video_size = 0x8000000; + break; + default: + return -1; + } + } + + reg &= SIS315_DUAL_CHANNEL_MASK; + reg >>= 2; + switch (reg) { + case SIS315_SINGLE_CHANNEL_2_RANK: + ivideo.video_size <<= 1; + break; + case SIS315_DUAL_CHANNEL_1_RANK: + ivideo.video_size <<= 1; + break; + } + + return 0; +} + +static void sisfb_detect_VB_connect_315 (void) +{ + u8 cr32, temp; + + vgawb (CRTC_ADR, IND_SIS_SCRATCH_REG_CR32); + cr32 = vgarb (CRTC_DATA); + + ivideo.TV_plug = ivideo.TV_type = 0; + if ((cr32 & SIS_CRT1) && !sisfb_crt1off) + sisfb_crt1off = 0; + else { + if (cr32 & 0x5F) + sisfb_crt1off = 1; + else + sisfb_crt1off = 0; + } + + if (cr32 & SIS_VB_CRT2) + ivideo.disp_state = DISPTYPE_CRT2; + else if (cr32 & SIS_VB_LCD) + ivideo.disp_state = DISPTYPE_LCD; + else if (cr32 & SIS_VB_TV) { + ivideo.disp_state = DISPTYPE_TV; + + if (cr32 & SIS_VB_HIVISION) { + ivideo.TV_type = TVMODE_HIVISION; + ivideo.TV_plug = TVPLUG_SVIDEO; + } else if (cr32 & SIS_VB_SVIDEO) + ivideo.TV_plug = TVPLUG_SVIDEO; + else if (cr32 & SIS_VB_COMPOSITE) + ivideo.TV_plug = TVPLUG_COMPOSITE; + else if (cr32 & SIS_VB_SCART) + ivideo.TV_plug = TVPLUG_SCART; + + if (ivideo.TV_type == 0) { + vgawb (SEQ_ADR, IND_SIS_POWER_ON_TRAP); + temp = vgarb (SEQ_DATA); + + if (temp & 0x01) + ivideo.TV_type = TVMODE_PAL; + else + ivideo.TV_type = TVMODE_NTSC; } + } else + ivideo.disp_state = 0; +} + +static void sisfb_get_VB_type_315 (void) +{ + u8 vb_chipid; + + vgawb (VB_PART4_ADR, 0x0); + vb_chipid = vgarb (VB_PART4_DATA); + + switch (vb_chipid) { + case 0x01: + ivideo.hasVB = HASVB_301; + break; + case 0x02: + ivideo.hasVB = HASVB_302; + break; + case 0x03: + ivideo.hasVB = HASVB_303; + break; + default: + ivideo.hasVB = HASVB_NONE; } + // Eden Chen + //sishw_ext.hasVB = ivideo.hasVB; + // ~Eden Chen +} +#endif /* CONFIG_FB_SIS_315 */ + +/* --------------------- Heap Routines ------------------------------- */ + +static int sisfb_heap_init (void) +{ + SIS_OH *poh; + u8 temp = 0; +#ifdef CONFIG_FB_SIS_315 + int agp_enabled = 1; + u32 agp_size; + unsigned long *cmdq_baseport = 0; + unsigned long *read_port = 0; + unsigned long *write_port = 0; + SIS_CMDTYPE cmd_type; +#ifndef AGPOFF + agp_kern_info *agp_info; + agp_memory *agp; + u32 agp_phys; +#endif +#endif + /*karl:10/01/2001 */ + if (!sisfb_mem) { - if (!found_mode) { - printk("sisfb does not support mode %dx%d-%d\n", var->xres, - var->yres, var->bits_per_pixel); - mode_idx = old_mode; - return 1; + if (ivideo.video_size > 0x800000) + sisfb_heap_start = + (unsigned long) ivideo.video_vbase + 0x800000; + else + sisfb_heap_start = + (unsigned long) ivideo.video_vbase + 0x400000; + } else + sisfb_heap_start = + (unsigned long) (ivideo.video_vbase + sisfb_mem * 0x100000); + + sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size; + sisfb_heap_size = sisfb_heap_end - sisfb_heap_start; + +#ifdef CONFIG_FB_SIS_315 + + cmdq_baseport = + (unsigned long *) (ivideo.mmio_vbase + MMIO_QUEUE_PHYBASE); + write_port = + (unsigned long *) (ivideo.mmio_vbase + MMIO_QUEUE_WRITEPORT); + read_port = (unsigned long *) (ivideo.mmio_vbase + MMIO_QUEUE_READPORT); + + DPRINTK ("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, + read_port, write_port); + + agp_size = COMMAND_QUEUE_AREA_SIZE; + +#ifndef AGPOFF + + agp_info = vmalloc (sizeof (agp_kern_info)); + memset ((void *) agp_info, 0x00, sizeof (agp_kern_info)); + agp_copy_info (agp_info); + + agp_backend_acquire (); + + agp = + agp_allocate_memory (COMMAND_QUEUE_AREA_SIZE / PAGE_SIZE, + AGP_NORMAL_MEMORY); + if (agp == NULL) { + DPRINTK ("Allocate AGP buffer failed.\n"); + agp_enabled = 0; + } else { + if (agp_bind_memory (agp, agp->pg_start) != 0) { + DPRINTK ("AGP : can not bind memory\n"); + agp_enabled = 0; + } else { + agp_enable (0); + } } - if (search_refresh_rate(ivideo.refresh_rate) == 0) { - /* not supported rate */ - rate_idx = sisbios_mode[mode_idx].rate_idx; - ivideo.refresh_rate = 60; - } +#else + agp_enabled = 0; +#endif + if (agp_enabled) + cmd_type = AGP_CMD_QUEUE; + else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE) + cmd_type = VM_CMD_QUEUE; + else + cmd_type = MMIO_CMD; - if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) { - pre_setmode(); + switch (agp_size) { + case 0x80000: + temp = SIS_CMD_QUEUE_SIZE_512k; + break; + case 0x100000: + temp = SIS_CMD_QUEUE_SIZE_1M; + break; + case 0x200000: + temp = SIS_CMD_QUEUE_SIZE_2M; + break; + case 0x400000: + temp = SIS_CMD_QUEUE_SIZE_4M; + break; + } - if (SiSSetMode(&HwExt, mode_no)) { - DPRINTK("sisfb: set mode[0x%x]: failed\n", - mode_no); - return 1; - } + switch (cmd_type) { + case AGP_CMD_QUEUE: +#ifndef AGPOFF + DPRINTK ("AGP buffer base:0x%lx, offset:0x%x, size is %dK\n", + agp_info->aper_base, agp->physical, agp_size / 1024); - post_setmode(); + agp_phys = agp_info->aper_base + agp->physical; - printk(KERN_DEBUG "Current Mode: %dx%dx%d-%d \n", sisbios_mode[mode_idx].xres, - sisbios_mode[mode_idx].yres, sisbios_mode[mode_idx].bpp, ivideo.refresh_rate); + vgawb (CRTC_ADR, IND_SIS_AGP_IO_PAD); + vgawb (CRTC_DATA, 0); + vgawb (CRTC_DATA, SIS_AGP_2X); - ivideo.video_bpp = sisbios_mode[mode_idx].bpp; - ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres; - ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres; - ivideo.org_x = ivideo.org_y = 0; - video_linelength = - ivideo.video_width * (ivideo.video_bpp >> 3); + vgawb (SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD); + vgawb (SEQ_DATA, COMMAND_QUEUE_THRESHOLD); - DPRINTK("Current Mode: %dx%d-%d line_length=%d\n", - ivideo.video_width, ivideo.video_height, - ivideo.video_bpp, video_linelength); - } + vgawb (SEQ_ADR, IND_SIS_CMDQUEUE_SET); + vgawb (SEQ_DATA, SIS_CMD_QUEUE_RESET); - return 0; -} + *write_port = *read_port; -/* ---------------------- Draw Funtions ----------------------------- */ + temp |= SIS_AGP_CMDQUEUE_ENABLE; + vgawb (SEQ_ADR, IND_SIS_CMDQUEUE_SET); + vgawb (SEQ_DATA, temp); -static void sis_get_glyph(struct GlyInfo *gly) -{ - struct display *p = &fb_display[currcon]; - u16 c; - u8 *cdat; - int widthb; - u8 *gbuf = gly->gmask; - int size; + *cmdq_baseport = agp_phys; + sisfb_caps |= AGP_CMD_QUEUE_CAP; +#endif + break; - gly->fontheight = fontheight(p); - gly->fontwidth = fontwidth(p); - widthb = (fontwidth(p) + 7) / 8; + case VM_CMD_QUEUE: + sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE; + sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE; - c = gly->ch & p->charmask; - if (fontwidth(p) <= 8) - cdat = p->fontdata + c * fontheight(p); - else - cdat = p->fontdata + (c * fontheight(p) << 1); + vgawb (SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD); + vgawb (SEQ_DATA, COMMAND_QUEUE_THRESHOLD); - size = fontheight(p) * widthb; - memcpy(gbuf, cdat, size); - gly->ngmask = size; -} + vgawb (SEQ_ADR, IND_SIS_CMDQUEUE_SET); + vgawb (SEQ_DATA, SIS_CMD_QUEUE_RESET); + *write_port = *read_port; -/* ---------------------- HEAP Routines ----------------------------- */ + temp |= SIS_VRAM_CMDQUEUE_ENABLE; + vgawb (SEQ_ADR, IND_SIS_CMDQUEUE_SET); + vgawb (SEQ_DATA, temp); -/* - * Heap Initialization - */ + *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE; -static int sisfb_heap_init(void) -{ - struct OH *poh; - u8 jTemp, tq_state; + sisfb_caps |= VM_CMD_QUEUE_CAP; - if(ivideo.video_size > 0x800000) - /* video ram is large than 8M */ - heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M; - else - heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M; + DPRINTK ("VM Cmd Queue offset = 0x%lx, size is %dK\n", + *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE / 1024); + break; + default: + vgawb (SEQ_ADR, IND_SIS_CMDQUEUE_SET); + vgawb (SEQ_DATA, SIS_MMIO_CMD_ENABLE); + break; + } - heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size; - heap_size = heap_end - heap_start; +#endif +#ifdef CONFIG_FB_SIS_300 + if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) { + unsigned int tqueue_pos; + u8 tq_state; - /* Setting for Turbo Queue */ - if (heap_size >= TURBO_QUEUE_AREA_SIZE) { tqueue_pos = - (ivideo.video_size - - TURBO_QUEUE_AREA_SIZE) / (64 * 1024); - jTemp = (u8) (tqueue_pos & 0xff); - vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET); - tq_state = vgarb(SEQ_DATA); + (ivideo.video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024); + temp = (u8) (tqueue_pos & 0xff); + vgawb (SEQ_ADR, IND_SIS_TURBOQUEUE_SET); + tq_state = vgarb (SEQ_DATA); tq_state |= 0xf0; tq_state &= 0xfc; tq_state |= (u8) (tqueue_pos >> 8); - vgawb(SEQ_DATA, tq_state); - vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR); - vgawb(SEQ_DATA, jTemp); - - caps |= TURBO_QUEUE_CAP; - - heap_end -= TURBO_QUEUE_AREA_SIZE; - heap_size -= TURBO_QUEUE_AREA_SIZE; + vgawb (SEQ_DATA, tq_state); + vgawb (SEQ_ADR, IND_SIS_TURBOQUEUE_ADR); + vgawb (SEQ_DATA, temp); + + sisfb_caps |= TURBO_QUEUE_CAP; + + sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE; + sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE; + DPRINTK ("Turbo Queue: start at 0x%lx, size is %dK\n", + sisfb_heap_end, TURBO_QUEUE_AREA_SIZE / 1024); } +#endif - /* Setting for HW cursor(4K) */ - if (heap_size >= HW_CURSOR_AREA_SIZE) { - heap_end -= HW_CURSOR_AREA_SIZE; - heap_size -= HW_CURSOR_AREA_SIZE; - hwcursor_vbase = heap_end; + if (sisfb_heap_size >= HW_CURSOR_AREA_SIZE) { + sisfb_heap_end -= HW_CURSOR_AREA_SIZE; + sisfb_heap_size -= HW_CURSOR_AREA_SIZE; + sisfb_hwcursor_vbase = sisfb_heap_end; - caps |= HW_CURSOR_CAP; + sisfb_caps |= HW_CURSOR_CAP; + + DPRINTK ("Hardware Cursor: start at 0x%lx, size is %dK\n", + sisfb_heap_end, HW_CURSOR_AREA_SIZE / 1024); } - heap.pohaChain = NULL; - heap.pohFreeList = NULL; + sisfb_heap.poha_chain = NULL; + sisfb_heap.poh_freelist = NULL; - poh = poh_new_node(); + poh = sisfb_poh_new_node (); if (poh == NULL) return 1; - /* The first node describles the entire heap size */ - poh->pohNext = &heap.ohFree; - poh->pohPrev = &heap.ohFree; - poh->ulSize = heap_end - heap_start + 1; - poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase; - - DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n", - (char *) heap_start, (char *) heap_end, - (unsigned int) poh->ulSize / 1024); - - DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n", - (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024); - - /* The second node in our free list sentinel */ - heap.ohFree.pohNext = poh; - heap.ohFree.pohPrev = poh; - heap.ohFree.ulSize = 0; - heap.ulMaxFreeSize = poh->ulSize; - - /* Initialize the discardable list */ - heap.ohUsed.pohNext = &heap.ohUsed; - heap.ohUsed.pohPrev = &heap.ohUsed; - heap.ohUsed.ulSize = SENTINEL; + poh->poh_next = &sisfb_heap.oh_free; + poh->poh_prev = &sisfb_heap.oh_free; + poh->size = sisfb_heap_end - sisfb_heap_start + 1; + poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase; + + DPRINTK ("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n", + (char *) sisfb_heap_start, (char *) sisfb_heap_end, + (unsigned int) poh->size / 1024); + + DPRINTK ("sisfb:First Node offset:0x%x, size:%dk\n", + (unsigned int) poh->offset, (unsigned int) poh->size / 1024); + + sisfb_heap.oh_free.poh_next = poh; + sisfb_heap.oh_free.poh_prev = poh; + sisfb_heap.oh_free.size = 0; + sisfb_heap.max_freesize = poh->size; + + sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used; + sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used; + sisfb_heap.oh_used.size = SENTINEL; return 0; } -/* - * Allocates a basic memory unit in which we'll pack our data structures. - */ - -static struct OH *poh_new_node(void) +static SIS_OH *sisfb_poh_new_node (void) { int i; unsigned long cOhs; - struct OHALLOC *poha; - struct OH *poh; + SIS_OHALLOC *poha; + SIS_OH *poh; - if (heap.pohFreeList == NULL) { - poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL); - if (!poha) - return NULL; + if (sisfb_heap.poh_freelist == NULL) { + poha = kmalloc (OH_ALLOC_SIZE, GFP_KERNEL); - poha->pohaNext = heap.pohaChain; - heap.pohaChain = poha; + poha->poha_next = sisfb_heap.poha_chain; + sisfb_heap.poha_chain = poha; cOhs = (OH_ALLOC_SIZE - - sizeof(struct OHALLOC)) / sizeof(struct OH) + 1; + sizeof (SIS_OHALLOC)) / sizeof (SIS_OH) + 1; poh = &poha->aoh[0]; for (i = cOhs - 1; i != 0; i--) { - poh->pohNext = poh + 1; + poh->poh_next = poh + 1; poh = poh + 1; } - poh->pohNext = NULL; - heap.pohFreeList = &poha->aoh[0]; + poh->poh_next = NULL; + sisfb_heap.poh_freelist = &poha->aoh[0]; } - poh = heap.pohFreeList; - heap.pohFreeList = poh->pohNext; + poh = sisfb_heap.poh_freelist; + sisfb_heap.poh_freelist = poh->poh_next; return (poh); } -/* - * Allocates space, return NULL when failed - */ - -static struct OH *poh_allocate(unsigned long size) +static SIS_OH *sisfb_poh_allocate (unsigned long size) { - struct OH *pohThis; - struct OH *pohRoot; + SIS_OH *pohThis; + SIS_OH *pohRoot; int bAllocated = 0; - if (size > heap.ulMaxFreeSize) { - DPRINTK("sisfb: Can't allocate %dk size on offscreen\n", - (unsigned int) size / 1024); + if (size > sisfb_heap.max_freesize) { + DPRINTK ("sisfb: Can't allocate %dk size on offscreen\n", + (unsigned int) size / 1024); return (NULL); } - pohThis = heap.ohFree.pohNext; + pohThis = sisfb_heap.oh_free.poh_next; - while (pohThis != &heap.ohFree) { - if (size <= pohThis->ulSize) { + while (pohThis != &sisfb_heap.oh_free) { + if (size <= pohThis->size) { bAllocated = 1; break; } - pohThis = pohThis->pohNext; + pohThis = pohThis->poh_next; } if (!bAllocated) { - DPRINTK("sisfb: Can't allocate %dk size on offscreen\n", - (unsigned int) size / 1024); + DPRINTK ("sisfb: Can't allocate %dk size on offscreen\n", + (unsigned int) size / 1024); return (NULL); } - if (size == pohThis->ulSize) { + if (size == pohThis->size) { pohRoot = pohThis; - delete_node(pohThis); + sisfb_delete_node (pohThis); } else { - pohRoot = poh_new_node(); + pohRoot = sisfb_poh_new_node (); if (pohRoot == NULL) { return (NULL); } - pohRoot->ulOffset = pohThis->ulOffset; - pohRoot->ulSize = size; + pohRoot->offset = pohThis->offset; + pohRoot->size = size; - pohThis->ulOffset += size; - pohThis->ulSize -= size; + pohThis->offset += size; + pohThis->size -= size; } - heap.ulMaxFreeSize -= size; + sisfb_heap.max_freesize -= size; - pohThis = &heap.ohUsed; - insert_node(pohThis, pohRoot); + pohThis = &sisfb_heap.oh_used; + sisfb_insert_node (pohThis, pohRoot); return (pohRoot); } -/* - * To remove a node from a list. - */ - -static void delete_node(struct OH *poh) +static void sisfb_delete_node (SIS_OH * poh) { - struct OH *pohPrev; - struct OH *pohNext; + SIS_OH *poh_prev; + SIS_OH *poh_next; + poh_prev = poh->poh_prev; + poh_next = poh->poh_next; - pohPrev = poh->pohPrev; - pohNext = poh->pohNext; - - pohPrev->pohNext = pohNext; - pohNext->pohPrev = pohPrev; + poh_prev->poh_next = poh_next; + poh_next->poh_prev = poh_prev; return; } -/* - * To insert a node into a list. - */ - -static void insert_node(struct OH *pohList, struct OH *poh) +static void sisfb_insert_node (SIS_OH * pohList, SIS_OH * poh) { - struct OH *pohTemp; + SIS_OH *pohTemp; - pohTemp = pohList->pohNext; + pohTemp = pohList->poh_next; - pohList->pohNext = poh; - pohTemp->pohPrev = poh; + pohList->poh_next = poh; + pohTemp->poh_prev = poh; - poh->pohPrev = pohList; - poh->pohNext = pohTemp; + poh->poh_prev = pohList; + poh->poh_next = pohTemp; } -/* - * Frees an off-screen heap allocation. - */ - -static struct OH *poh_free(unsigned long base) +static SIS_OH *sisfb_poh_free (unsigned long base) { - struct OH *pohThis; - struct OH *pohFreed; - struct OH *pohPrev; - struct OH *pohNext; + SIS_OH *pohThis; + SIS_OH *poh_freed; + SIS_OH *poh_prev; + SIS_OH *poh_next; unsigned long ulUpper; unsigned long ulLower; int foundNode = 0; - pohFreed = heap.ohUsed.pohNext; + poh_freed = sisfb_heap.oh_used.poh_next; - while (pohFreed != &heap.ohUsed) { - if (pohFreed->ulOffset == base) { + while (poh_freed != &sisfb_heap.oh_used) { + if (poh_freed->offset == base) { foundNode = 1; break; } - pohFreed = pohFreed->pohNext; + poh_freed = poh_freed->poh_next; } if (!foundNode) return (NULL); - heap.ulMaxFreeSize += pohFreed->ulSize; + sisfb_heap.max_freesize += poh_freed->size; - pohPrev = pohNext = NULL; - ulUpper = pohFreed->ulOffset + pohFreed->ulSize; - ulLower = pohFreed->ulOffset; + poh_prev = poh_next = NULL; + ulUpper = poh_freed->offset + poh_freed->size; + ulLower = poh_freed->offset; - pohThis = heap.ohFree.pohNext; + pohThis = sisfb_heap.oh_free.poh_next; - while (pohThis != &heap.ohFree) { - if (pohThis->ulOffset == ulUpper) { - pohNext = pohThis; + while (pohThis != &sisfb_heap.oh_free) { + if (pohThis->offset == ulUpper) { + poh_next = pohThis; + } else if ((pohThis->offset + pohThis->size) == ulLower) { + poh_prev = pohThis; } - else if ((pohThis->ulOffset + pohThis->ulSize) == - ulLower) { - pohPrev = pohThis; - } - pohThis = pohThis->pohNext; + pohThis = pohThis->poh_next; } - delete_node(pohFreed); + sisfb_delete_node (poh_freed); - if (pohPrev && pohNext) { - pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize); - delete_node(pohNext); - free_node(pohFreed); - free_node(pohNext); - return (pohPrev); + if (poh_prev && poh_next) { + poh_prev->size += (poh_freed->size + poh_next->size); + sisfb_delete_node (poh_next); + sisfb_free_node (poh_freed); + sisfb_free_node (poh_next); + return (poh_prev); } - if (pohPrev) { - pohPrev->ulSize += pohFreed->ulSize; - free_node(pohFreed); - return (pohPrev); + if (poh_prev) { + poh_prev->size += poh_freed->size; + sisfb_free_node (poh_freed); + return (poh_prev); } - if (pohNext) { - pohNext->ulSize += pohFreed->ulSize; - pohNext->ulOffset = pohFreed->ulOffset; - free_node(pohFreed); - return (pohNext); + if (poh_next) { + poh_next->size += poh_freed->size; + poh_next->offset = poh_freed->offset; + sisfb_free_node (poh_freed); + return (poh_next); } - insert_node(&heap.ohFree, pohFreed); + sisfb_insert_node (&sisfb_heap.oh_free, poh_freed); - return (pohFreed); + return (poh_freed); } -/* - * Frees our basic data structure allocation unit by adding it to a free - * list. - */ - -static void free_node(struct OH *poh) +static void sisfb_free_node (SIS_OH * poh) { if (poh == NULL) { return; } - poh->pohNext = heap.pohFreeList; - heap.pohFreeList = poh; + poh->poh_next = sisfb_heap.poh_freelist; + sisfb_heap.poh_freelist = poh; return; } -void sis_malloc(struct sis_memreq *req) +void sis_malloc (struct sis_memreq *req) { - struct OH *poh; + SIS_OH *poh; - poh = poh_allocate(req->size); + poh = sisfb_poh_allocate (req->size); if (poh == NULL) { req->offset = 0; req->size = 0; - DPRINTK("sisfb: VMEM Allocation Failed\n"); + DPRINTK ("sisfb: VMEM Allocation Failed\n"); } else { - DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n", - (char *) (poh->ulOffset + - (unsigned long) ivideo.video_vbase)); + DPRINTK ("sisfb: VMEM Allocation Successed : 0x%p\n", + (char *) (poh->offset + + (unsigned long) ivideo.video_vbase)); - req->offset = poh->ulOffset; - req->size = poh->ulSize; + req->offset = poh->offset; + req->size = poh->size; } } -void sis_free(unsigned long base) +void sis_free (unsigned long base) { - struct OH *poh; + SIS_OH *poh; - poh = poh_free(base); + poh = sisfb_poh_free (base); if (poh == NULL) { - DPRINTK("sisfb: poh_free() failed at base 0x%x\n", - (unsigned int) base); + DPRINTK ("sisfb: sisfb_poh_free() failed at base 0x%x\n", + (unsigned int) base); } } -void sis_dispinfo(struct ap_data *rec) +/* ------------------ SetMode Routines ------------------------------- */ + +static void sisfb_pre_setmode (void) { - rec->minfo.bpp = ivideo.video_bpp; - rec->minfo.xres = ivideo.video_width; - rec->minfo.yres = ivideo.video_height; - rec->minfo.v_xres = ivideo.video_vwidth; - rec->minfo.v_yres = ivideo.video_vheight; - rec->minfo.org_x = ivideo.org_x; - rec->minfo.org_y = ivideo.org_y; - rec->minfo.vrate = ivideo.refresh_rate; - rec->iobase = ivideo.vga_base - 0x30; - rec->mem_size = ivideo.video_size; - rec->disp_state = ivideo.disp_state; - switch(HwExt.jChipID) - { - case SIS_Glamour: - rec->chip = SiS_300; - break; - case SIS_Trojan: - if((HwExt.revision_id & 0xf0) == 0x30) - rec->chip = SiS_630S; - else - rec->chip = SiS_630; - break; - case SIS_Spartan: - rec->chip = SiS_540; - break; - case SIS_730: - rec->chip = SiS_730; + u8 cr30 = 0, cr31 = 0; + + vgawb (CRTC_ADR, 0x31); + cr31 = vgarb (CRTC_DATA) & ~0x60; + + switch (ivideo.disp_state & DISPTYPE_DISP2) { + case DISPTYPE_CRT2: + cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= SIS_DRIVER_MODE; + break; + case DISPTYPE_LCD: + cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= SIS_DRIVER_MODE; + break; + case DISPTYPE_TV: + if (ivideo.TV_type == TVMODE_HIVISION) + cr30 = + (SIS_VB_OUTPUT_HIVISION | + SIS_SIMULTANEOUS_VIEW_ENABLE); + else if (ivideo.TV_plug == TVPLUG_SVIDEO) + cr30 = + (SIS_VB_OUTPUT_SVIDEO | + SIS_SIMULTANEOUS_VIEW_ENABLE); + else if (ivideo.TV_plug == TVPLUG_COMPOSITE) + cr30 = + (SIS_VB_OUTPUT_COMPOSITE | + SIS_SIMULTANEOUS_VIEW_ENABLE); + else if (ivideo.TV_plug == TVPLUG_SCART) + cr30 = + (SIS_VB_OUTPUT_SCART | + SIS_SIMULTANEOUS_VIEW_ENABLE); + cr31 |= SIS_DRIVER_MODE; + + /*karl */ + if (sisfb_tvmode == 1) + cr31 |= 0x1; + if (sisfb_tvmode == 2) + cr31 &= ~0x1; + break; default: - rec->chip = SiS_UNKNOWN; - break; + cr30 = 0x00; + cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE); } -} - - -/* ---------------------- SetMode Routines -------------------------- */ -void SetReg1(u16 port, u16 index, u16 data) -{ - outb((u8) (index & 0xff), port); - port++; - outb((u8) (data & 0xff), port); + vgawb (CRTC_ADR, IND_SIS_SCRATCH_REG_CR30); + vgawb (CRTC_DATA, cr30); + vgawb (CRTC_ADR, IND_SIS_SCRATCH_REG_CR31); + vgawb (CRTC_DATA, cr31); + vgawb (CRTC_ADR, IND_SIS_SCRATCH_REG_CR33); + vgawb (CRTC_DATA, sisfb_rate_idx & 0x0F); } -void SetReg3(u16 port, u16 data) +static void sisfb_post_setmode (void) { - outb((u8) (data & 0xff), port); -} + u8 reg; -void SetReg4(u16 port, unsigned long data) -{ - outl((u32) (data & 0xffffffff), port); -} + vgawb (CRTC_ADR, 0x17); + reg = vgarb (CRTC_DATA); -u8 GetReg1(u16 port, u16 index) -{ - u8 data; + if ((ivideo.hasVB == HASVB_LVDS) + || (ivideo.hasVB == HASVB_LVDS_CHRONTEL)) if (ivideo.video_bpp == 8) + sisfb_crt1off = 0; - outb((u8) (index & 0xff), port); - port += 1; - data = inb(port); - return (data); -} + if (sisfb_crt1off) + reg &= ~0x80; + else + reg |= 0x80; + vgawb (CRTC_DATA, reg); -u8 GetReg2(u16 port) -{ - u8 data; + vgawb (SEQ_ADR, IND_SIS_RAMDAC_CONTROL); + reg = vgarb (SEQ_DATA); + reg &= ~0x04; + vgawb (SEQ_DATA, reg); + + if ((ivideo.disp_state & DISPTYPE_TV) && (ivideo.hasVB == HASVB_301)) { + /*karl */ + vgawb (VB_PART4_ADR, 0x01); + reg = vgarb (VB_PART4_DATA); + + if ((reg != 0xB1) && (reg != 0xB0)) { /*301B Revision ID */ + // Eden Chen + switch (ivideo.video_width) { + case 320: + filter_tb = + (ivideo.TV_type == TVMODE_NTSC) ? 4 : 12; + break; + case 640: + filter_tb = + (ivideo.TV_type == TVMODE_NTSC) ? 5 : 13; + break; + case 720: + filter_tb = + (ivideo.TV_type == TVMODE_NTSC) ? 6 : 14; + break; + case 800: + filter_tb = + (ivideo.TV_type == TVMODE_NTSC) ? 7 : 15; + break; + default: + filter = -1; + break; + } + // ~Eden Chen - data = inb(port); + // Eden Chen + //vgawb(VB_PART1_ADR, 0x24); + vgawb (VB_PART1_ADR, IND_SIS_CRT2_WRITE_ENABLE); + // ~Eden Chen + vgawb (VB_PART1_DATA, 0x1); + + // Eden Chen for Debug + // ~Eden Chen + + if (ivideo.TV_type == TVMODE_NTSC) { + vgawb (VB_PART2_ADR, 0x3A); + reg = vgarb (VB_PART2_DATA); + reg &= 0x1F; + vgawb (VB_PART2_DATA, reg); + + if (ivideo.TV_plug == TVPLUG_SVIDEO) { + vgawb (VB_PART2_ADR, 0x30); + reg = vgarb (VB_PART2_DATA); + reg &= 0xDF; + vgawb (VB_PART2_DATA, reg); + } else if (ivideo.TV_plug == TVPLUG_COMPOSITE) { + vgawb (VB_PART2_ADR, 0x30); + reg = vgarb (VB_PART2_DATA); + reg |= 0x20; + vgawb (VB_PART2_DATA, reg); + + switch (ivideo.video_width) { + case 640: + vgawb (VB_PART2_ADR, 0x35); + vgawb (VB_PART2_DATA, 0xEB); + vgawb (VB_PART2_ADR, 0x36); + vgawb (VB_PART2_DATA, 0x04); + vgawb (VB_PART2_ADR, 0x37); + vgawb (VB_PART2_DATA, 0x25); + vgawb (VB_PART2_ADR, 0x38); + vgawb (VB_PART2_DATA, 0x18); + break; + case 720: + vgawb (VB_PART2_ADR, 0x35); + vgawb (VB_PART2_DATA, 0xEE); + vgawb (VB_PART2_ADR, 0x36); + vgawb (VB_PART2_DATA, 0x0C); + vgawb (VB_PART2_ADR, 0x37); + vgawb (VB_PART2_DATA, 0x22); + vgawb (VB_PART2_ADR, 0x38); + vgawb (VB_PART2_DATA, 0x08); + break; + case 800: + vgawb (VB_PART2_ADR, 0x35); + vgawb (VB_PART2_DATA, 0xEB); + vgawb (VB_PART2_ADR, 0x36); + vgawb (VB_PART2_DATA, 0x15); + vgawb (VB_PART2_ADR, 0x37); + vgawb (VB_PART2_DATA, 0x25); + vgawb (VB_PART2_ADR, 0x38); + vgawb (VB_PART2_DATA, 0xF6); + break; + } + } + } else if (ivideo.TV_type == TVMODE_PAL) { + vgawb (VB_PART2_ADR, 0x3A); + reg = vgarb (VB_PART2_DATA); + reg &= 0x1F; + vgawb (VB_PART2_DATA, reg); + + if (ivideo.TV_plug == TVPLUG_SVIDEO) { + vgawb (VB_PART2_ADR, 0x30); + reg = vgarb (VB_PART2_DATA); + reg &= 0xDF; + vgawb (VB_PART2_DATA, reg); + } else if (ivideo.TV_plug == TVPLUG_COMPOSITE) { + vgawb (VB_PART2_ADR, 0x30); + reg = vgarb (VB_PART2_DATA); + reg |= 0x20; + vgawb (VB_PART2_DATA, reg); + + switch (ivideo.video_width) { + case 640: + vgawb (VB_PART2_ADR, 0x35); + vgawb (VB_PART2_DATA, 0xF1); + vgawb (VB_PART2_ADR, 0x36); + vgawb (VB_PART2_DATA, 0xF7); + vgawb (VB_PART2_ADR, 0x37); + vgawb (VB_PART2_DATA, 0x1F); + vgawb (VB_PART2_ADR, 0x38); + vgawb (VB_PART2_DATA, 0x32); + break; + case 720: + vgawb (VB_PART2_ADR, 0x35); + vgawb (VB_PART2_DATA, 0xF3); + vgawb (VB_PART2_ADR, 0x36); + vgawb (VB_PART2_DATA, 0x00); + vgawb (VB_PART2_ADR, 0x37); + vgawb (VB_PART2_DATA, 0x1D); + vgawb (VB_PART2_ADR, 0x38); + vgawb (VB_PART2_DATA, 0x20); + break; + case 800: + vgawb (VB_PART2_ADR, 0x35); + vgawb (VB_PART2_DATA, 0xFC); + vgawb (VB_PART2_ADR, 0x36); + vgawb (VB_PART2_DATA, 0xFB); + vgawb (VB_PART2_ADR, 0x37); + vgawb (VB_PART2_DATA, 0x14); + vgawb (VB_PART2_ADR, 0x38); + vgawb (VB_PART2_DATA, 0x2A); + break; + } + } + } + // Eden + if ((filter >= 0) && (filter <= 7)) { + DPRINTK + ("FilterTable[%d]-%d: %02x %02x %02x %02x\n", + filter_tb, filter, + sis_TV_filter[filter_tb].filter[filter][0], + sis_TV_filter[filter_tb].filter[filter][1], + sis_TV_filter[filter_tb].filter[filter][2], + sis_TV_filter[filter_tb].filter[filter][3] + ); + vgawb (VB_PART2_ADR, 0x35); + vgawb (VB_PART2_DATA, + sis_TV_filter[filter_tb]. + filter[filter][0]); + vgawb (VB_PART2_ADR, 0x36); + vgawb (VB_PART2_DATA, + sis_TV_filter[filter_tb]. + filter[filter][1]); + vgawb (VB_PART2_ADR, 0x37); + vgawb (VB_PART2_DATA, + sis_TV_filter[filter_tb]. + filter[filter][2]); + vgawb (VB_PART2_ADR, 0x38); + vgawb (VB_PART2_DATA, + sis_TV_filter[filter_tb]. + filter[filter][3]); + } + // ~Eden + } + } - return (data); } -u32 GetReg3(u16 port) +static void sisfb_crtc_to_var (struct fb_var_screeninfo *var) { - u32 data; - - data = inl(port); - return (data); -} + u16 VRE, VBE, VRS, VBS, VDE, VT; + u16 HRE, HBE, HRS, HBS, HDE, HT; + u8 sr_data, cr_data, cr_data2, cr_data3, mr_data; + int A, B, C, D, E, F, temp; + double hrate, drate; -void ClearDAC(u16 port) -{ - int i,j; + vgawb (SEQ_ADR, IND_SIS_COLOR_MODE); + sr_data = vgarb (SEQ_DATA); - vgawb(DAC_ADR, 0x00); - for(i=0; i<256; i++) - for(j=0; j<3; j++) - vgawb(DAC_DATA, 0); -} + if (sr_data & SIS_INTERLACED_MODE) + var->vmode = FB_VMODE_INTERLACED; + else + var->vmode = FB_VMODE_NONINTERLACED; -void ClearBuffer(PHW_DEVICE_EXTENSION pHwExt) -{ - memset((char *) ivideo.video_vbase, 0, - video_linelength * ivideo.video_height); -} + switch ((sr_data & 0x1C) >> 2) { + case SIS_8BPP_COLOR_MODE: + var->bits_per_pixel = 8; + break; + case SIS_16BPP_COLOR_MODE: + var->bits_per_pixel = 16; + break; + case SIS_32BPP_COLOR_MODE: + var->bits_per_pixel = 32; + break; + } -static void pre_setmode(void) -{ - unsigned char uCR30=0, uCR31=0; + switch (var->bits_per_pixel) { + case 8: + var->red.length = 6; + var->green.length = 6; + var->blue.length = 6; + video_cmap_len = 256; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + video_cmap_len = 16; - switch(uDispType & MASK_DISPTYPE_DISP2) - { - case MASK_DISPTYPE_CRT2: - uCR30 = 0x41; - uCR31 = 0x40; - break; - case MASK_DISPTYPE_LCD: - uCR30 = 0x21; - uCR31 = 0x40; - break; - case MASK_DISPTYPE_TV: - if(ivideo.TV_type == TVMODE_HIVISION) - uCR30 = 0x81; - else if(ivideo.TV_plug == TVPLUG_SVIDEO) - uCR30 = 0x09; - else if(ivideo.TV_plug == TVPLUG_COMPOSITE) - uCR30 = 0x05; - else if(ivideo.TV_plug == TVPLUG_SCART) - uCR30 = 0x11; - uCR31 = 0x40; /* CR31[0] will be set in setmode() */ break; - default: - uCR30 = 0x00; - uCR31 = 0x60; + case 24: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + video_cmap_len = 16; + break; + case 32: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + video_cmap_len = 16; + break; } - vgawb(CRTC_ADR, 0x30); - vgawb(CRTC_DATA, uCR30); - vgawb(CRTC_ADR, 0x31); - vgawb(CRTC_DATA, uCR31); - vgawb(CRTC_ADR, 0x33); - vgawb(CRTC_DATA, rate_idx & 0x0f); -} + vgawb (SEQ_ADR, 0xA); + sr_data = vgarb (SEQ_DATA); -static void post_setmode(void) -{ - u8 uTemp; + vgawb (CRTC_ADR, 0x6); + cr_data = vgarb (CRTC_DATA); + vgawb (CRTC_ADR, 0x7); + cr_data2 = vgarb (CRTC_DATA); + VT = + (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) | + ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) << 10); + A = VT + 2; - vgawb(CRTC_ADR, 0x17); - uTemp = vgarb(CRTC_DATA); + vgawb (CRTC_ADR, 0x12); + cr_data = vgarb (CRTC_DATA); + VDE = + (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) | + ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9); + E = VDE + 1; - if(crt1off) /* turn off CRT1 */ - uTemp &= ~0x80; - else /* turn on CRT1 */ - uTemp |= 0x80; - vgawb(CRTC_DATA, uTemp); + vgawb (CRTC_ADR, 0x10); + cr_data = vgarb (CRTC_DATA); + VRS = + (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) | + ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7); + F = VRS + 1 - E; - /* disable 24-bit palette RAM and Gamma correction */ - vgawb(SEQ_ADR, 0x07); - uTemp = vgarb(SEQ_DATA); - uTemp &= ~0x04; - vgawb(SEQ_DATA, uTemp); -} + vgawb (CRTC_ADR, 0x15); + cr_data = vgarb (CRTC_DATA); + vgawb (CRTC_ADR, 0x9); + cr_data3 = vgarb (CRTC_DATA); + VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) | + ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8); + + vgawb (CRTC_ADR, 0x16); + cr_data = vgarb (CRTC_DATA); + VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4); + temp = VBE - ((E - 1) & 511); + B = (temp > 0) ? temp : (temp + 512); -static void search_mode(const char *name) -{ - int i = 0; + vgawb (CRTC_ADR, 0x11); + cr_data = vgarb (CRTC_DATA); + VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1); + temp = VRE - ((E + F - 1) & 31); + C = (temp > 0) ? temp : (temp + 32); - if (name == NULL) - return; + D = B - F - C; - while (sisbios_mode[i].mode_no != 0) { - if (!strcmp(name, sisbios_mode[i].name)) { - mode_idx = i; - break; - } - i++; - } + var->yres = var->yres_virtual = E; + var->upper_margin = D; + var->lower_margin = F; + var->vsync_len = C; - if (mode_idx < 0) - DPRINTK("Invalid user mode : %s\n", name); -} + vgawb (SEQ_ADR, 0xb); + sr_data = vgarb (SEQ_DATA); -static u8 search_refresh_rate(unsigned int rate) -{ - u16 xres, yres; - int i = 0; + vgawb (CRTC_ADR, 0x0); + cr_data = vgarb (CRTC_DATA); + HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8); + A = HT + 5; - xres = sisbios_mode[mode_idx].xres; - yres = sisbios_mode[mode_idx].yres; + vgawb (CRTC_ADR, 0x1); + cr_data = vgarb (CRTC_DATA); + HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6); + E = HDE + 1; - while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) { - if ((vrate[i].xres == xres) && (vrate[i].yres == yres) - && (vrate[i].refresh == rate)) { - rate_idx = vrate[i].idx; - return rate_idx; - } - i++; - } + vgawb (CRTC_ADR, 0x4); + cr_data = vgarb (CRTC_DATA); + HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2); + F = HRS - E - 3; - DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres, - yres); + vgawb (CRTC_ADR, 0x2); + cr_data = vgarb (CRTC_DATA); + HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4); + + vgawb (SEQ_ADR, 0xc); + sr_data = vgarb (SEQ_DATA); + vgawb (CRTC_ADR, 0x3); + cr_data = vgarb (CRTC_DATA); + vgawb (CRTC_ADR, 0x5); + cr_data2 = vgarb (CRTC_DATA); + HBE = + (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) | + ((u16) (sr_data & 0x03) << 6); + HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3); - return 0; -} + temp = HBE - ((E - 1) & 255); + B = (temp > 0) ? temp : (temp + 256); -/* ------------------ Public Routines ------------------------------- */ + temp = HRE - ((E + F + 3) & 63); + C = (temp > 0) ? temp : (temp + 64); -/* - * Get the Fixed Part of the Display - */ + D = B - F - C; -static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info) -{ - DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con); + var->xres = var->xres_virtual = E * 8; + var->left_margin = D * 8; + var->right_margin = F * 8; + var->hsync_len = C * 8; - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, fb_info.modename); + var->activate = FB_ACTIVATE_NOW; - fix->smem_start = ivideo.video_base; - if(ivideo.video_size > 0x800000) - fix->smem_len = RESERVED_MEM_SIZE_8M; /* reserved for Xserver */ + var->sync = 0; + + mr_data = vgarb (0x1C); + if (mr_data & 0x80) + var->sync &= ~FB_SYNC_VERT_HIGH_ACT; + else + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + if (mr_data & 0x40) + var->sync &= ~FB_SYNC_HOR_HIGH_ACT; else - fix->smem_len = RESERVED_MEM_SIZE_4M; /* reserved for Xserver */ + var->sync |= FB_SYNC_HOR_HIGH_ACT; + + VT += 2; + VT <<= 1; + HT = (HT + 5) * 8; + + hrate = (double) ivideo.refresh_rate * (double) VT / 2; + drate = hrate * HT; + var->pixclock = (u32) (1E12 / drate); +} + +/* ------------------ Public Routines -------------------------------- */ + +static int sisfb_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *info) +{ + memset (fix, 0, sizeof (struct fb_fix_screeninfo)); + strcpy (fix->id, fb_info.modename); + + fix->smem_start = ivideo.video_base; + + /*karl:10/01/2001 */ + if (!sisfb_mem) { + if (ivideo.video_size > 0x800000) + fix->smem_len = 0x800000; + else + fix->smem_len = 0x400000; + } else + fix->smem_len = sisfb_mem * 0x100000; fix->type = video_type; fix->type_aux = 0; @@ -1502,135 +2007,110 @@ fix->ywrapstep = 0; fix->line_length = video_linelength; fix->mmio_start = ivideo.mmio_base; - fix->mmio_len = MMIO_SIZE; + fix->mmio_len = sisfb_mmio_size; fix->accel = FB_ACCEL_SIS_GLAMOUR; fix->reserved[0] = ivideo.video_size & 0xFFFF; fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF; - fix->reserved[2] = caps; /* capabilities */ + fix->reserved[2] = sisfb_caps; return 0; -} - -/* - * Get the User Defined Part of the Display - */ -static int sisfb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) -{ - DPRINTK("sisfb: sisfb_get_var:[%d]\n", con); +} +static int sisfb_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *info) +{ if (con == -1) - memcpy(var, &default_var, sizeof(struct fb_var_screeninfo)); + memcpy (var, &default_var, sizeof (struct fb_var_screeninfo)); else *var = fb_display[con].var; + return 0; } -/* - * Set the User Defined Part of the Display - */ - -static int sisfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) +static int sisfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info) { int err; unsigned int cols, rows; fb_display[con].var.activate = FB_ACTIVATE_NOW; - /* Set mode */ - if (do_set_var(var, con == currcon, info)) { - crtc_to_var(var); /* return current mode to user */ + if (sisfb_do_set_var (var, con == currcon, info)) { + sisfb_crtc_to_var (var); return -EINVAL; } - /* get actual setting value */ - crtc_to_var(var); + sisfb_crtc_to_var (var); - /* update display of current console */ - sisfb_set_disp(con, var); + sisfb_set_disp (con, var); if (info->changevar) (*info->changevar) (con); - if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) + if ((err = fb_alloc_cmap (&fb_display[con].cmap, 0, 0))) return err; - do_install_cmap(con, info); + sisfb_do_install_cmap (con, info); - /* inform console to update struct display */ - cols = sisbios_mode[mode_idx].cols; - rows = sisbios_mode[mode_idx].rows; - vc_resize_con(rows, cols, fb_display[con].conp->vc_num); + cols = sisbios_mode[sisfb_mode_idx].cols; + rows = sisbios_mode[sisfb_mode_idx].rows; + vc_resize_con (rows, cols, fb_display[con].conp->vc_num); return 0; -} +} -/* - * Get the Colormap - */ - -static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) +static int sisfb_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con); - if (con == currcon) - return fb_get_cmap(cmap, kspc, sis_getcolreg, info); - else if (fb_display[con].cmap.len) /* non default colormap? */ - fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + return fb_get_cmap (cmap, kspc, sis_getcolreg, info); + else if (fb_display[con].cmap.len) + fb_copy_cmap (&fb_display[con].cmap, cmap, kspc ? 0 : 2); else - fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2); + fb_copy_cmap (fb_default_cmap (video_cmap_len), cmap, + kspc ? 0 : 2); + return 0; } -/* - * Set the Colormap - */ - -static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) +static int sisfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { int err; - if (!fb_display[con].cmap.len) { /* no colormap allocated */ - err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0); + if (!fb_display[con].cmap.len) { + err = fb_alloc_cmap (&fb_display[con].cmap, video_cmap_len, 0); if (err) return err; } - if (con == currcon) /* current console */ - return fb_set_cmap(cmap, kspc, sis_setcolreg, info); + if (con == currcon) + return fb_set_cmap (cmap, kspc, sis_setcolreg, info); else - fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); + fb_copy_cmap (cmap, &fb_display[con].cmap, kspc ? 0 : 1); return 0; } -static int sisfb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con, - struct fb_info *info) +static int sisfb_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, struct fb_info *info) { switch (cmd) { case FBIO_ALLOC: - if(!capable(CAP_SYS_RAWIO)) + if (!capable (CAP_SYS_RAWIO)) return -EPERM; - sis_malloc((struct sis_memreq *) arg); + sis_malloc ((struct sis_memreq *) arg); break; case FBIO_FREE: - if(!capable(CAP_SYS_RAWIO)) + if (!capable (CAP_SYS_RAWIO)) return -EPERM; - sis_free(*(unsigned long *) arg); + sis_free (*(unsigned long *) arg); break; case FBIOGET_GLYPH: - sis_get_glyph((struct GlyInfo *) arg); + sis_get_glyph ((SIS_GLYINFO *) arg); break; case FBIOGET_HWCINFO: { unsigned long *hwc_offset = (unsigned long *) arg; - if (caps & HW_CURSOR_CAP) - *hwc_offset = hwcursor_vbase - + if (sisfb_caps & HW_CURSOR_CAP) + *hwc_offset = sisfb_hwcursor_vbase - (unsigned long) ivideo.video_vbase; else *hwc_offset = 0; @@ -1638,32 +2118,31 @@ break; } case FBIOPUT_MODEINFO: - { - struct mode_info *x = (struct mode_info *)arg; + { + struct mode_info *x = (struct mode_info *) arg; + + ivideo.video_bpp = x->bpp; + ivideo.video_width = x->xres; + ivideo.video_height = x->yres; + ivideo.video_vwidth = x->v_xres; + ivideo.video_vheight = x->v_yres; + ivideo.org_x = x->org_x; + ivideo.org_y = x->org_y; + ivideo.refresh_rate = x->vrate; - /* Set Mode Parameters by XServer */ - ivideo.video_bpp = x->bpp; - ivideo.video_width = x->xres; - ivideo.video_height = x->yres; - ivideo.video_vwidth = x->v_xres; - ivideo.video_vheight = x->v_yres; - ivideo.org_x = x->org_x; - ivideo.org_y = x->org_y; - ivideo.refresh_rate = x->vrate; - break; } case FBIOGET_DISPINFO: - sis_dispinfo((struct ap_data *)arg); + sis_dispinfo ((struct ap_data *) arg); break; default: return -EINVAL; } return 0; + } -static int sisfb_mmap(struct fb_info *info, struct file *file, - struct vm_area_struct *vma) +static int sisfb_mmap (struct fb_info *info, struct file *file, struct vm_area_struct *vma) { struct fb_var_screeninfo var; unsigned long start; @@ -1674,18 +2153,16 @@ return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; - /* frame buffer memory */ start = (unsigned long) ivideo.video_base; - len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size); + len = PAGE_ALIGN ((start & ~PAGE_MASK) + ivideo.video_size); if (off >= len) { - /* memory mapped io */ off -= len; - sisfb_get_var(&var, currcon, info); + sisfb_get_var (&var, currcon, info); if (var.accel_flags) return -EINVAL; start = (unsigned long) ivideo.mmio_base; - len = PAGE_ALIGN((start & ~PAGE_MASK) + MMIO_SIZE); + len = PAGE_ALIGN ((start & ~PAGE_MASK) + sisfb_mmio_size); } start &= PAGE_MASK; @@ -1694,617 +2171,599 @@ off += start; vma->vm_pgoff = off >> PAGE_SHIFT; -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) if (boot_cpu_data.x86 > 3) - pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; + pgprot_val (vma->vm_page_prot) |= _PAGE_PCD; #endif - if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, - vma->vm_page_prot)) + if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0; + } static struct fb_ops sisfb_ops = { - owner: THIS_MODULE, - fb_get_fix: sisfb_get_fix, - fb_get_var: sisfb_get_var, - fb_set_var: sisfb_set_var, - fb_get_cmap: sisfb_get_cmap, - fb_set_cmap: sisfb_set_cmap, - fb_ioctl: sisfb_ioctl, - fb_mmap: sisfb_mmap, + owner:THIS_MODULE, + fb_get_fix:sisfb_get_fix, + fb_get_var:sisfb_get_var, + fb_set_var:sisfb_set_var, + fb_get_cmap:sisfb_get_cmap, + fb_set_cmap:sisfb_set_cmap, + fb_ioctl:sisfb_ioctl, + fb_mmap:sisfb_mmap, }; -int sisfb_setup(char *options) -{ - char *this_opt; - - fb_info.fontname[0] = '\0'; - ivideo.refresh_rate = 0; - - if (!options || !*options) - return 0; - - while (this_opt = strsep(&options, ",")) { - if (!*this_opt) - continue; - - if (!strcmp(this_opt, "inverse")) { - inverse = 1; - fb_invert_cmaps(); - } else if (!strncmp(this_opt, "font:", 5)) { - strcpy(fb_info.fontname, this_opt + 5); - } else if (!strncmp(this_opt, "mode:", 5)) { - search_mode(this_opt + 5); - } else if (!strncmp(this_opt, "vrate:", 6)) { - ivideo.refresh_rate = - simple_strtoul(this_opt + 6, NULL, 0); - } else if (!strncmp(this_opt, "off", 3)) { - sisfb_off = 1; - } else if (!strncmp(this_opt, "crt1off", 7)) { - crt1off = 1; - } else - DPRINTK("invalid parameter %s\n", this_opt); - } - return 0; -} +/* ------------ Interface to the low level console driver -------------*/ -static int sisfb_update_var(int con, struct fb_info *info) +static int sisfb_update_var (int con, struct fb_info *info) { return 0; } -/* - * Switch Console (called by fbcon.c) - */ - -static int sisfb_switch(int con, struct fb_info *info) +static int sisfb_switch (int con, struct fb_info *info) { int cols, rows; - DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con); - - /* update colormap of current console */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info); + fb_get_cmap (&fb_display[currcon].cmap, 1, sis_getcolreg, info); fb_display[con].var.activate = FB_ACTIVATE_NOW; - /* same mode, needn't change mode actually */ - - if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo))) - { + if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof (struct fb_var_screeninfo))) { currcon = con; return 1; } currcon = con; - do_set_var(&fb_display[con].var, 1, info); + sisfb_do_set_var (&fb_display[con].var, 1, info); - sisfb_set_disp(con, &fb_display[con].var); + sisfb_set_disp (con, &fb_display[con].var); - /* Install new colormap */ - do_install_cmap(con, info); + sisfb_do_install_cmap (con, info); - cols = sisbios_mode[mode_idx].cols; - rows = sisbios_mode[mode_idx].rows; - vc_resize_con(rows, cols, fb_display[con].conp->vc_num); + cols = sisbios_mode[sisfb_mode_idx].cols; + rows = sisbios_mode[sisfb_mode_idx].rows; + vc_resize_con (rows, cols, fb_display[con].conp->vc_num); - sisfb_update_var(con, info); + sisfb_update_var (con, info); return 1; } -/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ - -static void sisfb_blank(int blank, struct fb_info *info) +static void sisfb_blank (int blank, struct fb_info *info) { - u8 CRData; + u8 reg; - vgawb(CRTC_ADR, 0x17); - CRData = vgarb(CRTC_DATA); + vgawb (CRTC_ADR, 0x17); + reg = vgarb (CRTC_DATA); - if (blank > 0) /* turn off CRT1 */ - CRData &= 0x7f; - else /* turn on CRT1 */ - CRData |= 0x80; + if (blank > 0) + reg &= 0x7f; + else + reg |= 0x80; - vgawb(CRTC_ADR, 0x17); - vgawb(CRTC_DATA, CRData); + vgawb (CRTC_ADR, 0x17); + vgawb (CRTC_DATA, reg); } -int has_VB(void) +int sisfb_setup (char *options) { - u8 uSR38, uSR39, uVBChipID; - - vgawb(SEQ_ADR, 0x38); - uSR38 = vgarb(SEQ_DATA); - vgawb(SEQ_ADR, 0x39); - uSR39 = vgarb(SEQ_DATA); - vgawb(IND_SIS_CRT2_PORT_14, 0x0); - uVBChipID = vgarb(IND_SIS_CRT2_PORT_14+1); + char *this_opt; - if ( - ( (HwExt.jChipID == SIS_Glamour) && (uSR38 & 0x20) ) /* 300 */ - || - ( (HwExt.jChipID >= SIS_Trojan ) && (uSR38 & 0x20) && (!(uSR39 & 0x80)) ) /* 630/540 */ - || - ( (HwExt.jChipID == SIS_Trojan ) && ((HwExt.revision_id & 0xf0) == 0x30) && (uVBChipID == 1) ) /* 630s */ - || - ( (HwExt.jChipID == SIS_730) && (uVBChipID == 1) ) /* 730 */ - ) - { - ivideo.hasVB = HASVB_301; - return TRUE; - } - else - { - ivideo.hasVB = HASVB_NONE; - return FALSE; - } -} + fb_info.fontname[0] = '\0'; + ivideo.refresh_rate = 0; -void sis_get301info(void) -{ - u8 uCRData; - unsigned long disp_state=0; + if (!options || !*options) + return 0; - if (HwExt.jChipID >= SIS_Trojan) - { - if (!has_VB()) - { - vgawb(CRTC_ADR, 0x37); - uCRData = vgarb(CRTC_DATA); + for (this_opt = strtok (options, ","); this_opt; + this_opt = strtok (NULL, ",")) { + if (!*this_opt) + continue; - switch((uCRData >> 1) & 0x07) - { - case 2: - ivideo.hasVB = HASVB_LVDS; - break; - case 4: - ivideo.hasVB = HASVB_LVDS_CHRONTEL; - break; - case 3: - ivideo.hasVB = HASVB_TRUMPION; - break; - default: - break; - } + if (!strcmp (this_opt, "inverse")) { + sisfb_inverse = 1; + fb_invert_cmaps (); + } else if (!strncmp (this_opt, "font:", 5)) { + strcpy (fb_info.fontname, this_opt + 5); + } else if (!strncmp (this_opt, "mode:", 5)) { + sisfb_search_mode (this_opt + 5); + } else if (!strncmp (this_opt, "vrate:", 6)) { + ivideo.refresh_rate = + simple_strtoul (this_opt + 6, NULL, 0); + } else if (!strncmp (this_opt, "off", 3)) { + sisfb_off = 1; + } else if (!strncmp (this_opt, "crt1off", 7)) { + sisfb_crt1off = 1; + } else if (!strncmp (this_opt, "filter:", 7)) { + filter = (int) simple_strtoul (this_opt + 7, NULL, 0); + } + /*karl */ + else if (!strncmp (this_opt, "tvmode:", 7)) { + if (!strncmp (this_opt + 7, "pal", 3)) + sisfb_tvmode = 1; + if (!strncmp (this_opt + 7, "ntsc", 4)) + sisfb_tvmode = 2; } - } - else - { - has_VB(); - } + /*karl:10/01/2001 */ + else if (!strncmp (this_opt, "mem:", 4)) { - vgawb(CRTC_ADR, 0x32); - uCRData = vgarb(CRTC_DATA); - - switch(uDispType) - { - case MASK_DISPTYPE_CRT2: - disp_state = DISPTYPE_CRT2; - break; - case MASK_DISPTYPE_LCD: - disp_state = DISPTYPE_LCD; - break; - case MASK_DISPTYPE_TV: - disp_state = DISPTYPE_TV; - break; - } + sisfb_mem = simple_strtoul (this_opt + 4, NULL, 0); - if(disp_state & 0x7) - { - if(crt1off) - disp_state |= DISPMODE_SINGLE; - else - disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1); + } else + DPRINTK ("invalid parameter %s\n", this_opt); } - else - disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1; - - ivideo.disp_state = disp_state; + return 0; } - -int __init sisfb_init(void) +int __init sisfb_init (void) { struct pci_dev *pdev = NULL; struct board *b; int pdev_valid = 0; - unsigned char jTemp; - u8 uSRData, uCRData; + //unsigned long rom_vbase; + u32 reg32; + u16 reg16; + u8 reg; + int nRes; - outb(0x77, 0x80); + outb (0x77, 0x80); if (sisfb_off) return -ENXIO; - pci_for_each_dev(pdev) { - for (b = dev_list; b->vendor; b++) - { + pci_for_each_dev (pdev) + { + for (b = sisdev_list; b->vendor; b++) { if ((b->vendor == pdev->vendor) - && (b->device == pdev->device)) - { + && (b->device == pdev->device)) { pdev_valid = 1; - strcpy(fb_info.modename, b->name); + strcpy (fb_info.modename, b->name); ivideo.chip_id = pdev->device; - pci_read_config_byte(pdev, PCI_REVISION_ID, &HwExt.revision_id); + pci_read_config_byte (pdev, PCI_REVISION_ID, + &ivideo.revision_id); + pci_read_config_word (pdev, PCI_COMMAND, ®16); + // Eden Chen + //sishw_ext.uRevisionID = ivideo.revision_id; + sishw_ext.jChipRevision = ivideo.revision_id; + // ~Eden Chen + sisvga_enabled = reg16 & 0x1; break; } } - + if (pdev_valid) break; } - + if (!pdev_valid) return -1; - - switch(ivideo.chip_id) - { + + // Eden Chen + switch (ivideo.chip_id) { case PCI_DEVICE_ID_SI_300: - HwExt.jChipID = SIS_Glamour; + ivideo.chip = SIS_300; + sisvga_engine = SIS_300_VGA; break; case PCI_DEVICE_ID_SI_630_VGA: - HwExt.jChipID = SIS_Trojan; + { + sisfb_set_reg4 (0xCF8, 0x80000000); + reg32 = sisfb_get_reg3 (0xCFC); + if (reg32 == 0x07301039) { + ivideo.chip = SIS_730; + strcpy (fb_info.modename, "SIS 730"); + } else + ivideo.chip = SIS_630; + + sisvga_engine = SIS_300_VGA; break; + } case PCI_DEVICE_ID_SI_540_VGA: - HwExt.jChipID = SIS_Spartan; + ivideo.chip = SIS_540; + sisvga_engine = SIS_300_VGA; break; - case PCI_DEVICE_ID_SI_730_VGA: - HwExt.jChipID = SIS_730; + case PCI_DEVICE_ID_SI_315H: + ivideo.chip = SIS_315H; + sisvga_engine = SIS_315_VGA; + break; + case PCI_DEVICE_ID_SI_315: + ivideo.chip = SIS_315; + sisvga_engine = SIS_315_VGA; + break; + case PCI_DEVICE_ID_SI_315PRO: + ivideo.chip = SIS_315PRO; + sisvga_engine = SIS_315_VGA; + break; + case PCI_DEVICE_ID_SI_550_VGA: + ivideo.chip = SIS_550; + sisvga_engine = SIS_315_VGA; break; } - ivideo.video_base = pci_resource_start(pdev, 0); - ivideo.mmio_base = pci_resource_start(pdev, 1); - ivideo.vga_base = pci_resource_start(pdev, 2) + 0x30; - - HwExt.IOAddress = (unsigned short)ivideo.vga_base; - rom_base = 0x000C0000; + // Eden Chen + //sishw_ext.jChipID = ivideo.chip; + sishw_ext.jChipType = ivideo.chip; + // for Debug + if ((sishw_ext.jChipType == SIS_315PRO) + || (sishw_ext.jChipType == SIS_315)) + sishw_ext.jChipType = SIS_315H; + // ~Eden Chen + + DPRINTK ("%s is used as %s device(VGA Engine %d).\n", + fb_info.modename, sisvga_enabled ? "primary" : "secondary", + sisvga_engine); + + ivideo.video_base = pci_resource_start (pdev, 0); + ivideo.mmio_base = pci_resource_start (pdev, 1); + // Eden Chen + //sishw_ext.IOAddress = (unsigned short) ivideo.vga_base + // = pci_resource_start(pdev, 2) + 0x30; + sishw_ext.ulIOAddress = (unsigned short) ivideo.vga_base = pci_resource_start (pdev, 2) + 0x30; + // ~Eden Chen + + sisfb_mmio_size = pci_resource_len (pdev, 1); + + if (!sisvga_enabled) + if (pci_enable_device (pdev)) + return -EIO; + + vgawb (SEQ_ADR, IND_SIS_PASSWORD); + vgawb (SEQ_DATA, SIS_PASSWORD); - MMIO_SIZE = pci_resource_len(pdev, 1); +#ifdef LINUXBIOS +#ifdef CONFIG_FB_SIS_300 + if (sisvga_engine == SIS_300_VGA) + { + vgawb (SEQ_ADR, 0x28); + vgawb (SEQ_DATA, 0x37); -#ifdef NOBIOS - if (pci_enable_device(pdev)) - return -EIO; - /* Image file instead of VGA-bios */ - HwExt.VirtualRomBase = rom_vbase = (unsigned long) RomData; -#else -#ifdef CONFIG_FB_SIS_LINUXBIOS - if (pci_enable_device(pdev)) - return -EIO; - HwExt.VirtualRomBase = rom_vbase = 0; -#else - request_region(rom_base, 32, "sisfb"); - HwExt.VirtualRomBase = rom_vbase - = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN); -#endif -#endif - /* set passwd */ - vgawb(SEQ_ADR, IND_SIS_PASSWORD); - vgawb(SEQ_DATA, SIS_PASSWORD); - - /* Enable MMIO & PCI linear address */ - vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET); - jTemp = vgarb(SEQ_DATA); - jTemp |= SIS_PCI_ADDR_ENABLE; - jTemp |= SIS_MEM_MAP_IO_ENABLE; - vgawb(SEQ_DATA, jTemp); - -#ifdef CONFIG_FB_SIS_LINUXBIOS - pdev_valid = 0; - pci_for_each_dev(pdev) { - u8 uPCIData=0; + vgawb (SEQ_ADR, 0x29); + vgawb (SEQ_DATA, 0x61); - if ((pdev->vendor == PCI_VENDOR_ID_SI) && (pdev->device==0x630)) - { - pci_read_config_byte(pdev, 0x63, &uPCIData); - uPCIData = (uPCIData & 0x70) >> 4; - ivideo.video_size = (unsigned int)(1 << (uPCIData+21)); - pdev_valid = 1; - break; - } + vgawb (SEQ_ADR, IND_SIS_SCRATCH_REG_1A); + reg = vgarb (SEQ_DATA); + reg |= SIS_SCRATCH_REG_1A_MASK; + vgawb (SEQ_DATA, reg); } - - if (!pdev_valid) - return -1; -#else - vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE); - ivideo.video_size = ((unsigned int) ((vgarb(SEQ_DATA) & 0x3f) + 1) << 20); #endif +#ifdef CONFIG_FB_SIS_315 + if (ivideo.chip == SIS_550) { + vgawb (SEQ_ADR, 0x28); + vgawb (SEQ_DATA, 0x5A); + + vgawb (SEQ_ADR, 0x29); + vgawb (SEQ_DATA, 0x64); + vgawb (CRTC_ADR, 0x3A); + vgawb (CRTC_DATA, 0x00); + } +#endif +#endif - /* get CRT2 connection state */ - vgawb(SEQ_ADR, 0x17); - uSRData = vgarb(SEQ_DATA); - vgawb(CRTC_ADR, 0x32); - uCRData = vgarb(CRTC_DATA); - - ivideo.TV_plug = ivideo.TV_type = 0; - if((uSRData&0x0F) && (HwExt.jChipID>=SIS_Trojan)) - { - /* CRT1 connect detection */ - if((uSRData & 0x01) && !crt1off) - crt1off = 0; - else - { - if(uSRData&0x0E) /* DISP2 connected */ - crt1off = 1; - else - crt1off = 0; - } - - /* detection priority : CRT2 > LCD > TV */ - if(uSRData & 0x08 ) - uDispType = MASK_DISPTYPE_CRT2; - else if(uSRData & 0x02) - uDispType = MASK_DISPTYPE_LCD; - else if(uSRData & 0x04) - { - if(uSRData & 0x80) - { - ivideo.TV_type = TVMODE_HIVISION; - ivideo.TV_plug = TVPLUG_SVIDEO; - } - else if(uSRData & 0x20) - ivideo.TV_plug = TVPLUG_SVIDEO; - else if(uSRData & 0x10) - ivideo.TV_plug = TVPLUG_COMPOSITE; - else if(uSRData & 0x40) - ivideo.TV_plug = TVPLUG_SCART; - - if(ivideo.TV_type == 0) - { - u8 uSR16; - vgawb(SEQ_ADR, 0x16); - uSR16 = vgarb(SEQ_DATA); - if(uSR16 & 0x20) - ivideo.TV_type = TVMODE_PAL; - else - ivideo.TV_type = TVMODE_NTSC; - } - - uDispType = MASK_DISPTYPE_TV; + if (sisvga_engine == SIS_315_VGA) { + switch (ivideo.chip) { + case SIS_315H: + case SIS_315: + sishw_ext.bIntegratedMMEnabled = TRUE; + break; + case SIS_550: + // Eden Chen + //vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A); + //reg = vgarb(SEQ_DATA); + //if (reg & SIS_SCRATCH_REG_1A_MASK) + // sishw_ext.bIntegratedMMEnabled = TRUE; + //else + // sishw_ext.bIntegratedMMEnabled = FALSE; + //for Debug + sishw_ext.bIntegratedMMEnabled = TRUE; + // ~Eden Chen + break; + default: + break; } - } - else - { - if((uCRData & 0x20) && !crt1off) - crt1off = 0; - else - { - if(uCRData&0x5F) /* DISP2 connected */ - crt1off = 1; + } else if (sisvga_engine == SIS_300_VGA) { + if (ivideo.chip == SIS_300) { + sishw_ext.bIntegratedMMEnabled = TRUE; + } else { + vgawb (SEQ_ADR, IND_SIS_SCRATCH_REG_1A); + reg = vgarb (SEQ_DATA); + if (reg & SIS_SCRATCH_REG_1A_MASK) + sishw_ext.bIntegratedMMEnabled = TRUE; else - crt1off = 0; + sishw_ext.bIntegratedMMEnabled = FALSE; } + } + // Eden Chen + sishw_ext.pDevice = NULL; + sishw_ext.pjVirtualRomBase = NULL; + sishw_ext.pjCustomizedROMImage = NULL; + sishw_ext.bSkipDramSizing = 0; + sishw_ext.pQueryVGAConfigSpace = &sisfb_query_VGA_config_space; + sishw_ext.pQueryNorthBridgeSpace = &sisfb_query_north_bridge_space; + strcpy (sishw_ext.szVBIOSVer, "0.84"); + + sishw_ext.pSR = vmalloc (sizeof (SIS_DSReg) * SR_BUFFER_SIZE); + if (sishw_ext.pSR == NULL) + printk (KERN_DEBUG "Allocated SRReg space fail.\n"); + sishw_ext.pSR[0].jIdx = sishw_ext.pSR[0].jVal = 0xFF; + + sishw_ext.pCR = vmalloc (sizeof (SIS_DSReg) * CR_BUFFER_SIZE); + if (sishw_ext.pCR == NULL) + printk (KERN_DEBUG "Allocated CRReg space fail.\n"); + sishw_ext.pCR[0].jIdx = sishw_ext.pCR[0].jVal = 0xFF; + // ~Eden Chen + + #ifdef CONFIG_FB_SIS_300 + if (sisvga_engine == SIS_300_VGA) { + if (!sisvga_enabled) { + // Eden Chen + sishw_ext.pjVideoMemoryAddress = ioremap (ivideo.video_base, 0x2000000); + //SiSInit300(&sishw_ext); + SiSInit (&sishw_ext); + vgawb (SEQ_ADR, IND_SIS_PASSWORD); + vgawb (SEQ_DATA, SIS_PASSWORD); + // ~Eden Chen + } +#ifdef LINUXBIOS + else { + // Eden Chen + sishw_ext.pjVideoMemoryAddress + = ioremap (ivideo.video_base, 0x2000000); + //SiSInit300(&sishw_ext); + SiSInit (&sishw_ext); + vgawb (SEQ_ADR, IND_SIS_PASSWORD); + vgawb (SEQ_DATA, SIS_PASSWORD); + // ~Eden Chen + } + vgawb (SEQ_ADR, 0x7); + reg = vgarb (SEQ_DATA); + reg |= 0x10; + vgawb (SEQ_DATA, reg); +#endif + sisfb_get_dram_size_300 (); + } +#endif - if(uCRData & 0x10) - uDispType = MASK_DISPTYPE_CRT2; - else if(uCRData & 0x08) - uDispType = MASK_DISPTYPE_LCD; - else if(uCRData & 0x47) - { - uDispType = MASK_DISPTYPE_TV; - - if(uCRData & 0x40) - { - ivideo.TV_type = TVMODE_HIVISION; - ivideo.TV_plug = TVPLUG_SVIDEO; - } - else if(uCRData & 0x02) - ivideo.TV_plug = TVPLUG_SVIDEO; - else if(uCRData & 0x01) - ivideo.TV_plug = TVPLUG_COMPOSITE; - else if(uCRData & 0x04) - ivideo.TV_plug = TVPLUG_SCART; + #ifdef CONFIG_FB_SIS_315 + if (sisvga_engine == SIS_315_VGA) { + if (!sisvga_enabled) { + /* Mapping Max FB Size for 315 Init */ + // Eden Chen + //sishw_ext.VirtualVideoMemoryAddress + sishw_ext.pjVideoMemoryAddress = ioremap (ivideo.video_base, 0x8000000); + //SiSInit310(&sishw_ext); + SiSInit (&sishw_ext); + + vgawb (SEQ_ADR, IND_SIS_PASSWORD); + vgawb (SEQ_DATA, SIS_PASSWORD); + + sishw_ext.bSkipDramSizing = TRUE; + vgawb (SEQ_ADR, 0x13); + sishw_ext.pSR[0].jIdx = 0x13; + sishw_ext.pSR[0].jVal = vgarb (SEQ_DATA); + vgawb (SEQ_ADR, 0x14); + sishw_ext.pSR[1].jIdx = 0x14; + sishw_ext.pSR[1].jVal = vgarb (SEQ_DATA); + sishw_ext.pSR[2].jIdx = 0xFF; + sishw_ext.pSR[2].jVal = 0xFF; + // Eden Chen + } +#ifdef LINUXBIOS + else { + sishw_ext.pjVideoMemoryAddress = ioremap (ivideo.video_base, 0x8000000); + SiSInit (&sishw_ext); + vgawb (SEQ_ADR, IND_SIS_PASSWORD); + vgawb (SEQ_DATA, SIS_PASSWORD); + + sishw_ext.bSkipDramSizing = TRUE; + vgawb (SEQ_ADR, 0x13); + sishw_ext.pSR[0].jIdx = 0x13; + sishw_ext.pSR[0].jVal = vgarb (SEQ_DATA); + vgawb (SEQ_ADR, 0x14); + sishw_ext.pSR[1].jIdx = 0x14; + sishw_ext.pSR[1].jVal = vgarb (SEQ_DATA); + sishw_ext.pSR[2].jIdx = 0xFF; + sishw_ext.pSR[2].jVal = 0xFF; + } +#endif + sisfb_get_dram_size_315 (); + } +#endif + //Eden Chen + vgawb (SEQ_ADR, IND_SIS_PCI_ADDRESS_SET); + reg = vgarb (SEQ_DATA); + reg |= SIS_PCI_ADDR_ENABLE; + reg |= SIS_MEM_MAP_IO_ENABLE; + vgawb (SEQ_DATA, reg); + + vgawb (SEQ_ADR, IND_SIS_MODULE_ENABLE); + reg = vgarb (SEQ_DATA); + reg |= SIS_ENABLE_2D; + vgawb (SEQ_DATA, reg); + //~Eden Chen + + // Eden Chen + sishw_ext.ulVideoMemorySize = ivideo.video_size; + // ~Eden Chen + if (!request_mem_region (ivideo.video_base, ivideo.video_size, "sisfb FB")) { + printk (KERN_ERR "sisfb: cannot reserve frame buffer memory\n"); + return -ENODEV; + } - if(ivideo.TV_type == 0) - { - u8 uTemp; - uTemp = *((u8 *)(HwExt.VirtualRomBase+0x52)); - if(uTemp&0x40) - { - uTemp=*((u8 *)(HwExt.VirtualRomBase+0x53)); - } - else - { - vgawb(SEQ_ADR, 0x38); - uTemp = vgarb(SEQ_DATA); - } - if(uTemp & 0x01) - ivideo.TV_type = TVMODE_PAL; - else - ivideo.TV_type = TVMODE_NTSC; - } + if (!request_mem_region (ivideo.mmio_base, sisfb_mmio_size, "sisfb MMIO")) { + printk (KERN_ERR "sisfb: cannot reserve MMIO region\n"); + release_mem_region (ivideo.video_base, ivideo.video_size); + return -ENODEV; + } + // Eden Chen + //sishw_ext.VirtualVideoMemoryAddress = ivideo.video_vbase + sishw_ext.pjVideoMemoryAddress = ivideo.video_vbase = ioremap (ivideo.video_base, ivideo.video_size); + // Eden Chen + ivideo.mmio_vbase = ioremap (ivideo.mmio_base, sisfb_mmio_size); + + printk (KERN_INFO + "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + ivideo.video_base, ivideo.video_vbase, ivideo.video_size / 1024); + + printk (KERN_INFO + "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n", + ivideo.mmio_base, ivideo.mmio_vbase, sisfb_mmio_size / 1024); + + #ifdef CONFIG_FB_SIS_300 + if (sisvga_engine == SIS_300_VGA) { + sisfb_get_VB_type_300 (); + if (ivideo.hasVB != HASVB_NONE) { + sisfb_detect_VB_connect_300 (); } } +#endif - if(uDispType == MASK_DISPTYPE_LCD) // LCD conntected - { - // TODO: set LCDType by EDID - HwExt.usLCDType = LCD1024; +#ifdef CONFIG_FB_SIS_315 + if (sisvga_engine == SIS_315_VGA) { + sisfb_get_VB_type_315 (); + if (ivideo.hasVB != HASVB_NONE) { + sisfb_detect_VB_connect_315 (); + } } +#endif - if (HwExt.jChipID >= SIS_Trojan) - { - vgawb(SEQ_ADR, 0x1A); - uSRData = vgarb(SEQ_DATA); - if (uSRData & 0x10) - HwExt.bIntegratedMMEnabled = TRUE; + // Eden Chen +sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN; +sishw_ext.usExternalChip = 0; + + switch (ivideo.hasVB) { + case HASVB_301: + /*karl */ + vgawb (VB_PART4_ADR, 0x01); + reg = vgarb (VB_PART4_DATA); + if ((reg != 0xB1) && (reg != 0xB0)) + sishw_ext.ujVBChipID = VB_CHIP_301; else - HwExt.bIntegratedMMEnabled = FALSE; + sishw_ext.ujVBChipID = VB_CHIP_301B; + break; + case HASVB_302: + sishw_ext.ujVBChipID = VB_CHIP_302; + break; + case HASVB_303: + sishw_ext.ujVBChipID = VB_CHIP_303; + break; + case HASVB_LVDS: + sishw_ext.usExternalChip = 0x1; + break; + case HASVB_TRUMPION: + sishw_ext.usExternalChip = 0x2; + break; + case HASVB_CHRONTEL: + sishw_ext.usExternalChip = 0x4; + break; + case HASVB_LVDS_CHRONTEL: + sishw_ext.usExternalChip = 0x5; + break; + default: + break; } - if(mode_idx >= 0) /* mode found */ - { - /* Filtering mode for VB */ - switch(uDispType & MASK_DISPTYPE_DISP2) - { - case MASK_DISPTYPE_LCD: - switch(HwExt.usLCDType) - { - case LCD1024: - if(sisbios_mode[mode_idx].xres > 1024) - mode_idx = -1; - break; - case LCD1280: - if(sisbios_mode[mode_idx].xres > 1280) - mode_idx = -1; - break; - case LCD2048: - if(sisbios_mode[mode_idx].xres > 2048) - mode_idx = -1; - break; - case LCD1920: - if(sisbios_mode[mode_idx].xres > 1920) - mode_idx = -1; - break; - case LCD1600: - if(sisbios_mode[mode_idx].xres > 1600) - mode_idx = -1; - break; - case LCD800: - if(sisbios_mode[mode_idx].xres > 800) - mode_idx = -1; - break; - case LCD640: - if(sisbios_mode[mode_idx].xres > 640) - mode_idx = -1; - break; - default: - mode_idx = -1; - } + // ~Eden Chen - if(sisbios_mode[mode_idx].xres == 720) /* only for TV */ - mode_idx = -1; + if (ivideo.disp_state & DISPTYPE_DISP2) { + if (sisfb_crt1off) + ivideo.disp_state |= DISPMODE_SINGLE; + else + ivideo.disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1); + } else + ivideo.disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1; + + if (ivideo.disp_state & DISPTYPE_LCD) { + vgawb (CRTC_ADR, IND_SIS_LCD_PANEL); + reg = vgarb (CRTC_DATA); + // Eden Chen + switch (reg) { + case SIS_LCD_PANEL_800X600: + sishw_ext.ulCRT2LCDType = LCD_800x600; break; - case MASK_DISPTYPE_TV: - switch(sisbios_mode[mode_idx].xres) - { - case 800: - case 640: - break; - case 720: - if(ivideo.TV_type == TVMODE_NTSC) - { - if(sisbios_mode[mode_idx].yres != 480) - mode_idx = -1; - } - else if(ivideo.TV_type == TVMODE_PAL) - { - if(sisbios_mode[mode_idx].yres != 576) - mode_idx = -1; - } - break; - default: - /* illegal mode */ - mode_idx = -1; - } + case SIS_LCD_PANEL_1024X768: + sishw_ext.ulCRT2LCDType = LCD_1024x768; + break; + case SIS_LCD_PANEL_1280X1024: + sishw_ext.ulCRT2LCDType = LCD_1280x1024; + break; + case SIS_LCD_PANEL_640X480: + sishw_ext.ulCRT2LCDType = LCD_640x480; + break; + case SIS_LCD_PANEL_1280X960: + sishw_ext.ulCRT2LCDType = LCD_1280x960; + break; + default: + sishw_ext.ulCRT2LCDType = LCD_1024x768; break; } - } + // ~Eden Chen + } + + if (sisfb_mode_idx >= 0) + sisfb_validate_mode (); - if (mode_idx < 0) - { - switch(uDispType & MASK_DISPTYPE_DISP2) - { - case MASK_DISPTYPE_LCD: - mode_idx = DEFAULT_LCDMODE; + if (sisfb_mode_idx < 0) { + switch (ivideo.disp_state & DISPTYPE_DISP2) { + case DISPTYPE_LCD: + sisfb_mode_idx = DEFAULT_LCDMODE; break; - case MASK_DISPTYPE_TV: - mode_idx = DEFAULT_TVMODE; + case DISPTYPE_TV: + sisfb_mode_idx = DEFAULT_TVMODE; break; default: - mode_idx = DEFAULT_MODE; + sisfb_mode_idx = DEFAULT_MODE; + break; } } - -#ifdef CONFIG_FB_SIS_LINUXBIOS - mode_idx = DEFAULT_MODE; - rate_idx = sisbios_mode[mode_idx].rate_idx; - /* set to default refresh rate 60MHz */ - ivideo.refresh_rate = 60; -#endif - - mode_no = sisbios_mode[mode_idx].mode_no; - + + sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no; + if (ivideo.refresh_rate != 0) - search_refresh_rate(ivideo.refresh_rate); + sisfb_search_refresh_rate (ivideo.refresh_rate); - if (rate_idx == 0) { - rate_idx = sisbios_mode[mode_idx].rate_idx; - /* set to default refresh rate 60MHz */ + if (sisfb_rate_idx == 0) { + sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx; ivideo.refresh_rate = 60; } - ivideo.video_bpp = sisbios_mode[mode_idx].bpp; - ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres; - ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres; + ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp; + ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres; + ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres; ivideo.org_x = ivideo.org_y = 0; video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3); - printk(KERN_DEBUG "FB base: 0x%lx, size: 0x%dK\n", - ivideo.video_base, (unsigned int)ivideo.video_size/1024); - printk(KERN_DEBUG "MMIO base: 0x%lx, size: 0x%dK\n", - ivideo.mmio_base, (unsigned int)MMIO_SIZE/1024); - - - if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) - { - printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n"); - return -ENODEV; - } - - if (!request_mem_region(ivideo.mmio_base, MMIO_SIZE, "sisfb MMIO")) - { - printk(KERN_ERR "sisfb: cannot reserve MMIO region\n"); - release_mem_region(ivideo.video_base, ivideo.video_size); - return -ENODEV; - } - - HwExt.VirtualVideoMemoryAddress = ivideo.video_vbase - = ioremap(ivideo.video_base, ivideo.video_size); - ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE); - -#ifdef NOBIOS - SiSInit300(&HwExt); -#else -#ifdef CONFIG_FB_SIS_LINUXBIOS - SiSInit300(&HwExt); -#endif -#endif - printk(KERN_INFO - "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - ivideo.video_base, ivideo.video_vbase, - ivideo.video_size / 1024); - printk(KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n", - ivideo.video_width, ivideo.video_height, ivideo.video_bpp, - video_linelength); - - /* enable 2D engine */ - vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE); - jTemp = vgarb(SEQ_DATA); - jTemp |= SIS_2D_ENABLE; - vgawb(SEQ_DATA, jTemp); + printk (KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n", + ivideo.video_width, ivideo.video_height, ivideo.video_bpp, + video_linelength); + + // Eden Chen + // Check interface correction For Debug + DPRINTK ("VM Adr=0x%p\n", sishw_ext.pjVideoMemoryAddress); + DPRINTK ("VM Size=%ldK\n", sishw_ext.ulVideoMemorySize / 1024); + DPRINTK ("IO Adr=0x%lx\n", sishw_ext.ulIOAddress); + DPRINTK ("Chip=%d\n", sishw_ext.jChipType); + DPRINTK ("ChipRevision=%d\n", sishw_ext.jChipRevision); + DPRINTK ("VBChip=%d\n", sishw_ext.ujVBChipID); + DPRINTK ("ExtVB=%d\n", sishw_ext.usExternalChip); + DPRINTK ("LCD=%ld\n", sishw_ext.ulCRT2LCDType); + DPRINTK ("bIntegratedMMEnabled=%d\n", sishw_ext.bIntegratedMMEnabled); + // ~Eden Chen - pre_setmode(); + sisfb_pre_setmode (); - if (SiSSetMode(&HwExt, mode_no)) { - DPRINTK("sisfb: set mode[0x%x]: failed\n", mode_no); + if (SiSSetMode (&sishw_ext, sisfb_mode_no) == 0) { + DPRINTK ("set mode[0x%x]: failed\n", sisfb_mode_no); return -1; } + vgawb (SEQ_ADR, IND_SIS_PASSWORD); + vgawb (SEQ_DATA, SIS_PASSWORD); + // Eden Chen - post_setmode(); - - /* Get VB functions */ - sis_get301info(); + sisfb_post_setmode (); - crtc_to_var(&default_var); + sisfb_crtc_to_var (&default_var); fb_info.changevar = NULL; fb_info.node = -1; @@ -2315,20 +2774,22 @@ fb_info.blank = &sisfb_blank; fb_info.flags = FBINFO_FLAG_DEFAULT; - sisfb_set_disp(-1, &default_var); + sisfb_set_disp (-1, &default_var); - if (sisfb_heap_init()) { - DPRINTK("sisfb: Failed to enable offscreen heap\n"); + if (sisfb_heap_init ()) { + DPRINTK ("sisfb: Failed to enable offscreen heap\n"); } + + /*H.C. */ + nRes = mtrr_add ((unsigned int) ivideo.video_base, (unsigned int) ivideo.video_size, MTRR_TYPE_WRCOMB, 1); + vc_resize_con (1, 1, 0); - /* to avoid the inversed bgcolor bug of the initial state */ - vc_resize_con(1, 1, 0); - - if (register_framebuffer(&fb_info) < 0) + if (register_framebuffer (&fb_info) < 0) return -EINVAL; - printk(KERN_INFO "fb%d: %s frame buffer device\n", - GET_FB_IDX(fb_info.node), fb_info.modename); + printk (KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n", + GET_FB_IDX (fb_info.node), fb_info.modename, VER_MAJOR, VER_MINOR, + VER_LEVEL); return 0; } @@ -2339,35 +2800,36 @@ static unsigned int rate = 0; static unsigned int crt1 = 1; -MODULE_PARM(mode, "s"); -MODULE_PARM(rate, "i"); -MODULE_PARM(crt1, "i"); /* default: CRT1 enable */ +MODULE_PARM (mode, "s"); +MODULE_PARM (rate, "i"); +MODULE_PARM (crt1, "i"); +MODULE_PARM (filter, "i"); -int init_module(void) +int init_module (void) { if (mode) - search_mode(mode); + sisfb_search_mode (mode); ivideo.refresh_rate = rate; - if(crt1 == 0) - crt1off = 1; + if (crt1 == 0) + sisfb_crt1off = 1; else - crt1off = 0; - - sisfb_init(); + sisfb_crt1off = 0; + + sisfb_init (); return 0; } -void cleanup_module(void) +void cleanup_module (void) { - unregister_framebuffer(&fb_info); + unregister_framebuffer (&fb_info); } -#endif /* MODULE */ - +#endif -EXPORT_SYMBOL(sis_malloc); -EXPORT_SYMBOL(sis_free); +EXPORT_SYMBOL (sis_malloc); +EXPORT_SYMBOL (sis_free); +EXPORT_SYMBOL (sis_dispinfo); -EXPORT_SYMBOL(ivideo); +EXPORT_SYMBOL (ivideo); diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/sis_main.h linux/drivers/video/sis/sis_main.h --- v2.4.14/linux/drivers/video/sis/sis_main.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/sis_main.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,693 @@ +#ifndef _SISFB_MAIN +#define _SISFB_MAIN + +/* ------------------- Constant Definitions ------------------------- */ + +#undef LINUXBIOS /* turn on when use LINUXBIOS */ +#define AGPOFF /* default is turn off AGP */ + +#define VER_MAJOR 1 +#define VER_MINOR 3 +#define VER_LEVEL 9 + +#define DEFAULT_MODE 0 +#define DEFAULT_LCDMODE 9 +#define DEFAULT_TVMODE 9 + +#define MAX_ROM_SCAN 0x10000 + +#define TURBO_QUEUE_CAP 0x80 +#define HW_CURSOR_CAP 0x40 +#define AGP_CMD_QUEUE_CAP 0x80 +#define VM_CMD_QUEUE_CAP 0x20 + +/* For 300 series */ +#ifdef CONFIG_FB_SIS_300 +#define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */ +#define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */ +#endif + +/* For 315 series */ +#ifdef CONFIG_FB_SIS_315 +#define COMMAND_QUEUE_AREA_SIZE 0x80000 /* 512K */ +#define HW_CURSOR_AREA_SIZE 0x4000 /* 16K */ +#define COMMAND_QUEUE_THRESHOLD 0x1F +#endif + +#define OH_ALLOC_SIZE 4000 +#define SENTINEL 0x7fffffff + +#define SEQ_ADR 0x14 +#define SEQ_DATA 0x15 +#define DAC_ADR 0x18 +#define DAC_DATA 0x19 +#define CRTC_ADR 0x24 +#define CRTC_DATA 0x25 +#define DAC2_ADR (0x16-0x30) +#define DAC2_DATA (0x17-0x30) +#define VB_PART1_ADR (0x04-0x30) +#define VB_PART1_DATA (0x05-0x30) +#define VB_PART2_ADR (0x10-0x30) +#define VB_PART2_DATA (0x11-0x30) +#define VB_PART3_ADR (0x12-0x30) +#define VB_PART3_DATA (0x13-0x30) +#define VB_PART4_ADR (0x14-0x30) +#define VB_PART4_DATA (0x15-0x30) + +#define IND_SIS_PASSWORD 0x05 /* SRs */ +#define IND_SIS_COLOR_MODE 0x06 +#define IND_SIS_RAMDAC_CONTROL 0x07 +#define IND_SIS_DRAM_SIZE 0x14 +#define IND_SIS_SCRATCH_REG_16 0x16 +#define IND_SIS_SCRATCH_REG_17 0x17 +#define IND_SIS_SCRATCH_REG_1A 0x1A +#define IND_SIS_MODULE_ENABLE 0x1E +#define IND_SIS_PCI_ADDRESS_SET 0x20 +#define IND_SIS_TURBOQUEUE_ADR 0x26 +#define IND_SIS_TURBOQUEUE_SET 0x27 +#define IND_SIS_POWER_ON_TRAP 0x38 +#define IND_SIS_POWER_ON_TRAP2 0x39 +#define IND_SIS_CMDQUEUE_SET 0x26 +#define IND_SIS_CMDQUEUE_THRESHOLD 0x27 + +#define IND_SIS_SCRATCH_REG_CR30 0x30 /* CRs */ +#define IND_SIS_SCRATCH_REG_CR31 0x31 +#define IND_SIS_SCRATCH_REG_CR32 0x32 +#define IND_SIS_SCRATCH_REG_CR33 0x33 +#define IND_SIS_LCD_PANEL 0x36 +#define IND_SIS_SCRATCH_REG_CR37 0x37 +#define IND_SIS_AGP_IO_PAD 0x48 + +#define IND_BRI_DRAM_STATUS 0x63 + +#define MMIO_QUEUE_PHYBASE 0x85C0 +#define MMIO_QUEUE_WRITEPORT 0x85C4 +#define MMIO_QUEUE_READPORT 0x85C8 + +// Eden Chen +#ifdef CONFIG_FB_SIS_300 +#define IND_SIS_CRT2_WRITE_ENABLE 0x24 +#endif +#ifdef CONFIG_FB_SIS_315 +#define IND_SIS_CRT2_WRITE_ENABLE 0x2F +#endif +// ~Eden Chen + +#define SIS_PASSWORD 0x86 /* SR05 */ +#define SIS_INTERLACED_MODE 0x20 /* SR06 */ +#define SIS_8BPP_COLOR_MODE 0x0 +#define SIS_15BPP_COLOR_MODE 0x1 +#define SIS_16BPP_COLOR_MODE 0x2 +#define SIS_32BPP_COLOR_MODE 0x4 +#define SIS_DRAM_SIZE_MASK 0x3F /* SR14 */ +#define SIS_DRAM_SIZE_1MB 0x00 +#define SIS_DRAM_SIZE_2MB 0x01 +#define SIS_DRAM_SIZE_4MB 0x03 +#define SIS_DRAM_SIZE_8MB 0x07 +#define SIS_DRAM_SIZE_16MB 0x0F +#define SIS_DRAM_SIZE_32MB 0x1F +#define SIS_DRAM_SIZE_64MB 0x3F +#define SIS_DATA_BUS_MASK 0xC0 +#define SIS_DATA_BUS_32 0x00 +#define SIS_DATA_BUS_64 0x01 +#define SIS_DATA_BUS_128 0x02 +#define SIS315_DRAM_SIZE_MASK 0xF0 /* 315 SR14 */ +#define SIS315_DRAM_SIZE_2MB 0x01 +#define SIS315_DRAM_SIZE_4MB 0x02 +#define SIS315_DRAM_SIZE_8MB 0x03 +#define SIS315_DRAM_SIZE_16MB 0x04 +#define SIS315_DRAM_SIZE_32MB 0x05 +#define SIS315_DRAM_SIZE_64MB 0x06 +#define SIS315_DRAM_SIZE_128MB 0x07 +#define SIS315_DATA_BUS_MASK 0x02 +#define SIS315_DATA_BUS_64 0x00 +#define SIS315_DATA_BUS_128 0x01 +#define SIS315_DUAL_CHANNEL_MASK 0x0C +#define SIS315_SINGLE_CHANNEL_1_RANK 0x0 +#define SIS315_SINGLE_CHANNEL_2_RANK 0x1 +#define SIS315_DUAL_CHANNEL_1_RANK 0x3 +#define SIS550_DRAM_SIZE_MASK 0x3F /* 550 SR14 */ +#define SIS550_DRAM_SIZE_4MB 0x00 +#define SIS550_DRAM_SIZE_8MB 0x01 +#define SIS550_DRAM_SIZE_16MB 0x03 +#define SIS550_DRAM_SIZE_24MB 0x05 +#define SIS550_DRAM_SIZE_32MB 0x07 +#define SIS550_DRAM_SIZE_64MB 0x0F +#define SIS550_DRAM_SIZE_96MB 0x17 +#define SIS550_DRAM_SIZE_128MB 0x1F +#define SIS550_DRAM_SIZE_256MB 0x3F + +#define SIS_SCRATCH_REG_1A_MASK 0x10 +#define SIS_ENABLE_2D 0x40 /* SR1E */ +#define SIS_MEM_MAP_IO_ENABLE 0x01 /* SR20 */ +#define SIS_PCI_ADDR_ENABLE 0x80 +#define SIS_AGP_CMDQUEUE_ENABLE 0x80 /* 315 SR26 */ +#define SIS_VRAM_CMDQUEUE_ENABLE 0x40 +#define SIS_MMIO_CMD_ENABLE 0x20 +#define SIS_CMD_QUEUE_SIZE_512k 0x00 +#define SIS_CMD_QUEUE_SIZE_1M 0x04 +#define SIS_CMD_QUEUE_SIZE_2M 0x08 +#define SIS_CMD_QUEUE_SIZE_4M 0x0C +#define SIS_CMD_QUEUE_RESET 0x01 +#define SIS_SIMULTANEOUS_VIEW_ENABLE 0x01 /* CR30 */ +#define SIS_MODE_SELECT_CRT2 0x02 +#define SIS_VB_OUTPUT_COMPOSITE 0x04 +#define SIS_VB_OUTPUT_SVIDEO 0x08 +#define SIS_VB_OUTPUT_SCART 0x10 +#define SIS_VB_OUTPUT_LCD 0x20 +#define SIS_VB_OUTPUT_CRT2 0x40 +#define SIS_VB_OUTPUT_HIVISION 0x80 +#define SIS_VB_OUTPUT_DISABLE 0x20 /* CR31 */ +#define SIS_DRIVER_MODE 0x40 +#define SIS_VB_COMPOSITE 0x01 /* CR32 */ +#define SIS_VB_SVIDEO 0x02 +#define SIS_VB_SCART 0x04 +#define SIS_VB_LCD 0x08 +#define SIS_VB_CRT2 0x10 +#define SIS_CRT1 0x20 +#define SIS_VB_HIVISION 0x40 +#define SIS_VB_DVI 0x80 +#define SIS_VB_TV (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | SIS_VB_SCART | SIS_VB_HIVISION) +#define SIS_LCD_PANEL_800X600 0x1 /* CR36 */ +#define SIS_LCD_PANEL_1024X768 0x2 +#define SIS_LCD_PANEL_1280X1024 0x3 +#define SIS_LCD_PANEL_1280X960 0x4 +#define SIS_LCD_PANEL_640X480 0x5 +#define SIS_EXTERNAL_CHIP_MASK 0x0E /* CR37 */ +#define SIS_EXTERNAL_CHIP_SIS301 0x01 +#define SIS_EXTERNAL_CHIP_LVDS 0x02 +#define SIS_EXTERNAL_CHIP_TRUMPION 0x03 +#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL 0x04 +#define SIS_EXTERNAL_CHIP_CHRONTEL 0x05 +#define SIS_AGP_2X 0x20 /* CR48 */ + +#define BRI_DRAM_SIZE_MASK 0x70 /* PCI bridge */ +#define BRI_DRAM_SIZE_2MB 0x00 +#define BRI_DRAM_SIZE_4MB 0x01 +#define BRI_DRAM_SIZE_8MB 0x02 +#define BRI_DRAM_SIZE_16MB 0x03 +#define BRI_DRAM_SIZE_32MB 0x04 +#define BRI_DRAM_SIZE_64MB 0x05 + +// Eden Chen +#define HW_DEVICE_EXTENSION SIS_HW_DEVICE_INFO +#define PHW_DEVICE_EXTENSION PSIS_HW_DEVICE_INFO + +#define SR_BUFFER_SIZE 5 +#define CR_BUFFER_SIZE 5 +// ~Eden Chen + +/* ------------------- Global Variables ----------------------------- */ + +/* Fbcon variables */ +static struct fb_info fb_info; +static struct display disp; +static int video_type = FB_TYPE_PACKED_PIXELS; +static int video_linelength; +static int video_cmap_len; +static struct display_switch sisfb_sw; +static struct fb_var_screeninfo default_var = { + 0, 0, 0, 0, + 0, 0, + 0, + 0, + {0, 8, 0}, + {0, 8, 0}, + {0, 8, 0}, + {0, 0, 0}, + 0, + FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + FB_VMODE_NONINTERLACED, + {0, 0, 0, 0, 0, 0} +}; + +static struct { + u16 blue, green, red, pad; +} palette[256]; +static union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB24 + u32 cfb24[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif +} fbcon_cmap; + +/* display status */ +static int sisfb_off = 0; +static int sisfb_crt1off = 0; +static int sisfb_inverse = 0; +static int sisvga_enabled = 0; +static int currcon = 0; +/*karl*/ +static int sisfb_tvmode = 0; +static int sisfb_mem = 0; + +static enum _VGA_ENGINE { + UNKNOWN_VGA = 0, + SIS_300_VGA, + SIS_315_VGA, +} sisvga_engine = UNKNOWN_VGA; + +/* mode-related variables */ +int sisfb_mode_idx = -1; +u8 sisfb_mode_no = 0; +u8 sisfb_rate_idx = 0; + +/* data for sis components*/ +struct video_info ivideo; + +// Eden Chen +HW_DEVICE_EXTENSION sishw_ext = { + NULL, NULL, NULL, NULL, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, + {0, 0, 0, 0} +}; +// ~Eden Chen + +/* card parameters */ +static unsigned long sisfb_mmio_size = 0; +static u8 sisfb_caps = 0; + +typedef enum _SIS_CMDTYPE { + MMIO_CMD = 0, + AGP_CMD_QUEUE, + VM_CMD_QUEUE, +} SIS_CMDTYPE; + +/* Supported SiS Chips list */ +static struct board { + u16 vendor, device; + const char *name; +} sisdev_list[] = { + { + PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, { + PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"}, { + PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"}, { + PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H, "SIS 315H"}, { + PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315, "SIS 315"}, { + PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO, "SIS 315Pro"}, { + PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, "SIS 550"}, { + 0, 0, NULL} +}; + +/* mode table */ +static const struct _sisbios_mode { + char name[15]; + u8 mode_no; + u16 xres; + u16 yres; + u16 bpp; + u16 rate_idx; + u16 cols; + u16 rows; +} sisbios_mode[] = { + { + "640x480x8", 0x2E, 640, 480, 8, 1, 80, 30}, { + "640x480x16", 0x44, 640, 480, 16, 1, 80, 30}, { + "640x480x32", 0x62, 640, 480, 32, 1, 80, 30}, { + "720x480x8", 0x31, 720, 480, 8, 1, 90, 30}, { + "720x480x16", 0x33, 720, 480, 16, 1, 90, 30}, { + "720x480x32", 0x35, 720, 480, 32, 1, 90, 30}, { + "720x576x8", 0x32, 720, 576, 8, 1, 90, 36}, { + "720x576x16", 0x34, 720, 576, 16, 1, 90, 36}, { + "720x576x32", 0x36, 720, 576, 32, 1, 90, 36}, { + "800x600x8", 0x30, 800, 600, 8, 2, 100, 37}, { + "800x600x16", 0x47, 800, 600, 16, 2, 100, 37}, { + "800x600x32", 0x63, 800, 600, 32, 2, 100, 37}, { + "1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48}, { + "1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48}, { + "1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48}, { + "1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64}, { + "1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64}, { + "1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64}, { + "1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75}, { + "1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75}, { + "1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75}, { + "1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75}, { + "1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75}, { + "1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75}, { + "\0", 0x00, 0, 0, 0, 0, 0, 0} +}; + +static struct _sis_vrate { + u16 idx; + u16 xres; + u16 yres; + u16 refresh; +} sisfb_vrate[] = { + { + 1, 640, 480, 60}, { + 2, 640, 480, 72}, { + 3, 640, 480, 75}, { + 4, 640, 480, 85}, { + 5, 640, 480, 100}, { + 6, 640, 480, 120}, { + 7, 640, 480, 160}, { + 8, 640, 480, 200}, { + 1, 720, 480, 60}, { + 1, 720, 576, 50}, { + 1, 800, 600, 56}, { + 2, 800, 600, 60}, { + 3, 800, 600, 72}, { + 4, 800, 600, 75}, { + 5, 800, 600, 85}, { + 6, 800, 600, 100}, { + 7, 800, 600, 120}, { + 8, 800, 600, 160}, { + 1, 1024, 768, 43}, { + 2, 1024, 768, 60}, { + 3, 1024, 768, 70}, { + 4, 1024, 768, 75}, { + 5, 1024, 768, 85}, { + 6, 1024, 768, 100}, { + 7, 1024, 768, 120}, { + 1, 1280, 1024, 43}, { + 2, 1280, 1024, 60}, { + 3, 1280, 1024, 75}, { + 4, 1280, 1024, 85}, { + 1, 1600, 1200, 60}, { + 2, 1600, 1200, 65}, { + 3, 1600, 1200, 70}, { + 4, 1600, 1200, 75}, { + 5, 1600, 1200, 85}, { + 1, 1920, 1440, 60}, { + 0, 0, 0, 0} +}; + +/* Offscreen layout */ +typedef struct _SIS_GLYINFO { + unsigned char ch; + int fontwidth; + int fontheight; + u8 gmask[72]; + int ngmask; +} SIS_GLYINFO; + +typedef struct _SIS_OH { + struct _SIS_OH *poh_next; + struct _SIS_OH *poh_prev; + unsigned long offset; + unsigned long size; +} SIS_OH; + +typedef struct _SIS_OHALLOC { + struct _SIS_OHALLOC *poha_next; + SIS_OH aoh[1]; +} SIS_OHALLOC; + +typedef struct _SIS_HEAP { + SIS_OH oh_free; + SIS_OH oh_used; + SIS_OH *poh_freelist; + SIS_OHALLOC *poha_chain; + unsigned long max_freesize; +} SIS_HEAP; + +static unsigned long sisfb_hwcursor_vbase; + +static unsigned long sisfb_heap_start; +static unsigned long sisfb_heap_end; +static unsigned long sisfb_heap_size; +static SIS_HEAP sisfb_heap; + +// Eden Chen +static struct _sis_TV_filter { + u8 filter[9][4]; +} sis_TV_filter[] = { + { { { + 0x00, 0x00, 0x00, 0x40}, /* NTSCFilter_0 */ + { + 0x00, 0xE0, 0x10, 0x60}, { + 0x00, 0xEE, 0x10, 0x44}, { + 0x00, 0xF4, 0x10, 0x38}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xFC, 0xFB, 0x14, 0x2A}, { + 0x00, 0x00, 0x10, 0x20}, { + 0x00, 0x04, 0x10, 0x18}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* NTSCFilter_1 */ + { + 0x00, 0xE0, 0x10, 0x60}, { + 0x00, 0xEE, 0x10, 0x44}, { + 0x00, 0xF4, 0x10, 0x38}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xFC, 0xFB, 0x14, 0x2A}, { + 0x00, 0x00, 0x10, 0x20}, { + 0x00, 0x04, 0x10, 0x18}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* NTSCFilter_2 */ + { + 0xF5, 0xEE, 0x1B, 0x44}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xEB, 0x04, 0x25, 0x18}, { + 0xF1, 0x05, 0x1F, 0x16}, { + 0xF6, 0x06, 0x1A, 0x14}, { + 0xFA, 0x06, 0x16, 0x14}, { + 0x00, 0x04, 0x10, 0x18}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* NTSCFilter_3 */ + { + 0xF1, 0x04, 0x1F, 0x18}, { + 0xEE, 0x0D, 0x22, 0x06}, { + 0xF7, 0x06, 0x19, 0x14}, { + 0xF4, 0x0B, 0x1C, 0x0A}, { + 0xFA, 0x07, 0x16, 0x12}, { + 0xF9, 0x0A, 0x17, 0x0C}, { + 0x00, 0x07, 0x10, 0x12}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* NTSCFilter_4 */ + { + 0x00, 0xE0, 0x10, 0x60}, { + 0x00, 0xEE, 0x10, 0x44}, { + 0x00, 0xF4, 0x10, 0x38}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xFC, 0xFB, 0x14, 0x2A}, { + 0x00, 0x00, 0x10, 0x20}, { + 0x00, 0x04, 0x10, 0x18}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* NTSCFilter_5 */ + { + 0xF5, 0xEE, 0x1B, 0x44}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xEB, 0x04, 0x25, 0x18}, { + 0xF1, 0x05, 0x1F, 0x16}, { + 0xF6, 0x06, 0x1A, 0x14}, { + 0xFA, 0x06, 0x16, 0x14}, { + 0x00, 0x04, 0x10, 0x18}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* NTSCFilter_6 */ + { + 0xEB, 0x04, 0x25, 0x18}, { + 0xE7, 0x0E, 0x29, 0x04}, { + 0xEE, 0x0C, 0x22, 0x08}, { + 0xF6, 0x0B, 0x1A, 0x0A}, { + 0xF9, 0x0A, 0x17, 0x0C}, { + 0xFC, 0x0A, 0x14, 0x0C}, { + 0x00, 0x08, 0x10, 0x10}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* NTSCFilter_7 */ + { + 0xEC, 0x02, 0x24, 0x1C}, { + 0xF2, 0x04, 0x1E, 0x18}, { + 0xEB, 0x15, 0x25, 0xF6}, { + 0xF4, 0x10, 0x1C, 0x00}, { + 0xF8, 0x0F, 0x18, 0x02}, { + 0x00, 0x04, 0x10, 0x18}, { + 0x01, 0x06, 0x0F, 0x14}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* PALFilter_0 */ + { + 0x00, 0xE0, 0x10, 0x60}, { + 0x00, 0xEE, 0x10, 0x44}, { + 0x00, 0xF4, 0x10, 0x38}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xFC, 0xFB, 0x14, 0x2A}, { + 0x00, 0x00, 0x10, 0x20}, { + 0x00, 0x04, 0x10, 0x18}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* PALFilter_1 */ + { + 0x00, 0xE0, 0x10, 0x60}, { + 0x00, 0xEE, 0x10, 0x44}, { + 0x00, 0xF4, 0x10, 0x38}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xFC, 0xFB, 0x14, 0x2A}, { + 0x00, 0x00, 0x10, 0x20}, { + 0x00, 0x04, 0x10, 0x18}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* PALFilter_2 */ + { + 0xF5, 0xEE, 0x1B, 0x44}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xF1, 0xF7, 0x01, 0x32}, { + 0xF5, 0xFB, 0x1B, 0x2A}, { + 0xF9, 0xFF, 0x17, 0x22}, { + 0xFB, 0x01, 0x15, 0x1E}, { + 0x00, 0x04, 0x10, 0x18}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* PALFilter_3 */ + { + 0xF5, 0xFB, 0x1B, 0x2A}, { + 0xEE, 0xFE, 0x22, 0x24}, { + 0xF3, 0x00, 0x1D, 0x20}, { + 0xF9, 0x03, 0x17, 0x1A}, { + 0xFB, 0x02, 0x14, 0x1E}, { + 0xFB, 0x04, 0x15, 0x18}, { + 0x00, 0x06, 0x10, 0x14}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* PALFilter_4 */ + { + 0x00, 0xE0, 0x10, 0x60}, { + 0x00, 0xEE, 0x10, 0x44}, { + 0x00, 0xF4, 0x10, 0x38}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xFC, 0xFB, 0x14, 0x2A}, { + 0x00, 0x00, 0x10, 0x20}, { + 0x00, 0x04, 0x10, 0x18}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* PALFilter_5 */ + { + 0xF5, 0xEE, 0x1B, 0x44}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xF1, 0xF7, 0x1F, 0x32}, { + 0xF5, 0xFB, 0x1B, 0x2A}, { + 0xF9, 0xFF, 0x17, 0x22}, { + 0xFB, 0x01, 0x15, 0x1E}, { + 0x00, 0x04, 0x10, 0x18}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* PALFilter_6 */ + { + 0xF5, 0xEE, 0x1B, 0x2A}, { + 0xEE, 0xFE, 0x22, 0x24}, { + 0xF3, 0x00, 0x1D, 0x20}, { + 0xF9, 0x03, 0x17, 0x1A}, { + 0xFB, 0x02, 0x14, 0x1E}, { + 0xFB, 0x04, 0x15, 0x18}, { + 0x00, 0x06, 0x10, 0x14}, { + 0xFF, 0xFF, 0xFF, 0xFF}}}, { { { + 0x00, 0x00, 0x00, 0x40}, /* PALFilter_7 */ + { + 0xF5, 0xEE, 0x1B, 0x44}, { + 0xF8, 0xF4, 0x18, 0x38}, { + 0xFC, 0xFB, 0x14, 0x2A}, { + 0xEB, 0x05, 0x25, 0x16}, { + 0xF1, 0x05, 0x1F, 0x16}, { + 0xFA, 0x07, 0x16, 0x12}, { + 0x00, 0x07, 0x10, 0x12}, { + 0xFF, 0xFF, 0xFF, 0xFF}}} +}; + +static int filter = -1; +static unsigned char filter_tb; +//~Eden Chen + +/* ---------------------- Routine Prototype ------------------------- */ + +/* Interface used by the world */ +int sisfb_setup (char *options); +static int sisfb_get_fix (struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int sisfb_get_var (struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int sisfb_set_var (struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int sisfb_get_cmap (struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int sisfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int sisfb_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info); + +/* Interface to the low level console driver */ +int sisfb_init (void); +static int sisfb_update_var (int con, struct fb_info *info); +static int sisfb_switch (int con, struct fb_info *info); +static void sisfb_blank (int blank, struct fb_info *info); + +/* hardware access routines */ +void sisfb_set_reg1 (u16 port, u16 index, u16 data); +void sisfb_set_reg3 (u16 port, u16 data); +void sisfb_set_reg4 (u16 port, unsigned long data); +u8 sisfb_get_reg1 (u16 port, u16 index); +u8 sisfb_get_reg2 (u16 port); +u32 sisfb_get_reg3 (u16 port); +// Eden Chen +//void sisfb_clear_DAC(u16 port); +//void sisfb_clear_buffer(PHW_DEVICE_EXTENSION psishw_ext); +// ~Eden Chen + +/* Internal routines */ +static void sisfb_search_mode (const char *name); +static void sisfb_validate_mode (void); +static u8 sisfb_search_refresh_rate (unsigned int rate); +static int sis_getcolreg (unsigned regno, unsigned *red, unsigned *green, + unsigned *blue, unsigned *transp, + struct fb_info *fb_info); +static int sis_setcolreg (unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *fb_info); +static int sisfb_do_set_var (struct fb_var_screeninfo *var, int isactive, + struct fb_info *info); +static void sisfb_set_disp (int con, struct fb_var_screeninfo *var); +static void sisfb_do_install_cmap (int con, struct fb_info *info); + +/* Chip-dependent Routines */ +#ifdef CONFIG_FB_SIS_300 +static int sisfb_get_dram_size_300 (void); +//extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension); +static void sisfb_detect_VB_connect_300 (void); +static void sisfb_get_VB_type_300 (void); +static int sisfb_has_VB_300 (void); +//extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT ModeNo); +#endif +#ifdef CONFIG_FB_SIS_315 +static int sisfb_get_dram_size_315 (void); +//extern BOOLEAN SiSInit310(PHW_DEVICE_EXTENSION HwDeviceExtension); +static void sisfb_detect_VB_connect_315 (void); +static void sisfb_get_VB_type_315 (void); +//extern BOOLEAN SiSSetMode310(PHW_DEVICE_EXTENSION HwDeviceExtension, USHORT ModeNo); +#endif + +/* SetMode routines */ + +// Eden Chen +extern BOOLEAN SiSSetMode (PSIS_HW_DEVICE_INFO HwDeviceExtension, + USHORT ModeNo); +extern BOOLEAN SiSInit (PSIS_HW_DEVICE_INFO HwDeviceExtension); +// ~Eden Chen + +static void sisfb_pre_setmode (void); +static void sisfb_post_setmode (void); +static void sisfb_crtc_to_var (struct fb_var_screeninfo *var); + +/* Export functions */ +static void sis_get_glyph (SIS_GLYINFO * gly); +void sis_dispinfo (struct ap_data *rec); +void sis_malloc (struct sis_memreq *req); +void sis_free (unsigned long base); + +/* heap routines */ +static int sisfb_heap_init (void); +static SIS_OH *sisfb_poh_new_node (void); +static SIS_OH *sisfb_poh_allocate (unsigned long size); +static void sisfb_delete_node (SIS_OH * poh); +static void sisfb_insert_node (SIS_OH * pohList, SIS_OH * poh); +static SIS_OH *sisfb_poh_free (unsigned long base); +static void sisfb_free_node (SIS_OH * poh); + +/* routines to access PCI configuration space */ +BOOLEAN sisfb_query_VGA_config_space (PSIS_HW_DEVICE_INFO psishw_ext, + unsigned long offset, unsigned long set, + unsigned long *value); +BOOLEAN sisfb_query_north_bridge_space (PSIS_HW_DEVICE_INFO psishw_ext, + unsigned long offset, unsigned long set, + unsigned long *value); + +#endif diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/vgatypes.h linux/drivers/video/sis/vgatypes.h --- v2.4.14/linux/drivers/video/sis/vgatypes.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/vgatypes.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,275 @@ +#ifndef _VGATYPES_ +#define _VGATYPES_ + +#ifndef TC +#define far +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CHAR +typedef char CHAR; +#endif + +#ifndef SHORT +typedef short SHORT; +#endif + +#ifndef LONG +typedef long LONG; +#endif + +#ifndef UCHAR +typedef unsigned char UCHAR; +#endif + +#ifndef USHORT +typedef unsigned short USHORT; +#endif + +#ifndef ULONG +typedef unsigned long ULONG; +#endif + +#ifndef PUCHAR +typedef UCHAR far *PUCHAR; +#endif + +#ifndef PUSHORT +typedef USHORT far *PUSHORT; +#endif + +#ifndef PULONG +typedef ULONG far *PULONG; +#endif + +#ifndef PVOID +typedef void far *PVOID; +#endif +#ifndef VOID +typedef void VOID; +#endif + +#ifndef BOOLEAN +typedef UCHAR BOOLEAN; +#endif + +#ifndef WINCE_HEADER +#ifndef bool +typedef UCHAR bool; +#endif +#endif /* WINCE_HEADER */ + +#ifndef VBIOS_VER_MAX_LENGTH +#define VBIOS_VER_MAX_LENGTH 4 +#endif + +#ifndef WIN2000 +#ifndef SIS_VB_CHIP_TYPE +typedef enum _SIS_VB_CHIP_TYPE { + VB_CHIP_Legacy = 0, + VB_CHIP_301, + VB_CHIP_301B, + VB_CHIP_301BLCD, + VB_CHIP_301BTV, + VB_CHIP_302, + VB_CHIP_302B, + VB_CHIP_302BLCD, + VB_CHIP_302BTV, + VB_CHIP_303, + VB_CHIP_UNKNOWN, /* other video bridge or no video bridge */ + MAX_VB_CHIP +} SIS_VB_CHIP_TYPE; +#endif +#endif + +#ifndef WIN2000 +#ifndef SIS_LCD_TYPE +typedef enum _SIS_LCD_TYPE { + LCD_INVALID = 0, + LCD_800x600, + LCD_1024x768, + LCD_1280x1024, + LCD_1280x960, + LCD_640x480, + LCD_1600x1200, + LCD_1920x1440, + LCD_2048x1536, + LCD_UNKNOWN +} SIS_LCD_TYPE; +#endif +#endif + +#ifndef WIN2000 /* mark by Paul ,Move definition to sisv.h */ +#ifndef PSIS_DSReg +typedef struct _SIS_DSReg { + UCHAR jIdx; + UCHAR jVal; +} SIS_DSReg, *PSIS_DSReg; +#endif + +#ifndef SIS_HW_DEVICE_INFO + +typedef struct _SIS_HW_DEVICE_INFO SIS_HW_DEVICE_INFO, *PSIS_HW_DEVICE_INFO; + +typedef BOOLEAN (*PSIS_QUERYSPACE) (PSIS_HW_DEVICE_INFO, ULONG, ULONG, ULONG *); + +struct _SIS_HW_DEVICE_INFO { + PVOID pDevice; /* The pointer to the physical device data structure + in each OS or NULL for unused. */ + UCHAR *pjVirtualRomBase; /* Only for NT, NULL for WinCE & Linux. */ + /* base virtual address of VBIOS ROM Space */ + /* or base virtual address of ROM image file. */ + /* if NULL, then read from pjROMImage; */ + /* Note:ROM image file is the file of VBIOS ROM */ + + UCHAR *pjCustomizedROMImage; /* base virtual address of ROM image file. */ + /* wincE:ROM image file is the file for OEM */ + /* customized table */ + /* Linux: not used */ + /* NT : not used */ + /* Note : pjCustomizedROMImage=NULL if no ROM image file */ + + UCHAR *pjVideoMemoryAddress; /* base virtual memory address */ + /* of Linear VGA memory */ + + ULONG ulVideoMemorySize; /* size, in bytes, of the memory on the board */ + ULONG ulIOAddress; /* base I/O address of VGA ports (0x3B0) */ + UCHAR jChipType; /* Used to Identify SiS Graphics Chip */ + /* defined in the data structure type */ + /* "SIS_CHIP_TYPE" */ + + UCHAR jChipRevision; /* Used to Identify SiS Graphics Chip Revision */ + UCHAR ujVBChipID; /* the ID of video bridge */ + /* defined in the data structure type */ + /* "SIS_VB_CHIP_TYPE" */ + + USHORT usExternalChip; /* NO VB or other video bridge(not */ + /* SiS video bridge) */ + /* if ujVBChipID = VB_CHIP_UNKNOWN, */ + /* then bit0=1 : LVDS,bit1=1 : trumpion, */ + /* bit2=1 : CH7005 & no video bridge if */ + /* usExternalChip = 0. */ + /* Note: CR37[3:1]: */ + /* 001:SiS 301 */ + /* 010:LVDS */ + /* 011:Trumpion LVDS Scaling Chip */ + /* 100:LVDS(LCD-out)+Chrontel 7005 */ + /* 101:Single Chrontel 7005 */ + + ULONG ulCRT2LCDType; /* defined in the data structure type */ + /* "SIS_LCD_TYPE" */ + + BOOLEAN bIntegratedMMEnabled; /* supporting integration MM enable */ + + BOOLEAN bSkipDramSizing; /* True: Skip video memory sizing. */ + PSIS_DSReg pSR; /* restore SR registers in initial function. */ + /* end data :(idx, val) = (FF, FF). */ + /* Note : restore SR registers if */ + /* bSkipDramSizing = TRUE */ + + PSIS_DSReg pCR; /* restore CR registers in initial function. */ + /* end data :(idx, val) = (FF, FF) */ + /* Note : restore cR registers if */ + /* bSkipDramSizing = TRUE */ + + PSIS_QUERYSPACE pQueryVGAConfigSpace; /* Get/Set VGA Configuration */ + /* space */ + + PSIS_QUERYSPACE pQueryNorthBridgeSpace; /* Get/Set North Bridge */ + /* space */ + + UCHAR szVBIOSVer[VBIOS_VER_MAX_LENGTH]; + +}; +#endif +#endif /*~ mark by Paul ,Move definition to sisv.h */ + +#ifndef WIN2000 +#ifndef WINCE_HEADER +#ifndef BUS_DATA_TYPE +typedef enum _BUS_DATA_TYPE { + ConfigurationSpaceUndefined = -1, + Cmos, + EisaConfiguration, + Pos, + CbusConfiguration, + PCIConfiguration, + VMEConfiguration, + NuBusConfiguration, + PCMCIAConfiguration, + MPIConfiguration, + MPSAConfiguration, + PNPISAConfiguration, + MaximumBusDataType +} BUS_DATA_TYPE, *PBUS_DATA_TYPE; +#endif +#endif /* WINCE_HEADER */ + +#ifndef PCI_TYPE0_ADDRESSES +#define PCI_TYPE0_ADDRESSES 6 +#endif + +#ifndef PCI_TYPE1_ADDRESSES +#define PCI_TYPE1_ADDRESSES 2 +#endif + +#ifndef WINCE_HEADER +#ifndef PCI_COMMON_CONFIG +typedef struct _PCI_COMMON_CONFIG { + USHORT VendorID; /* (ro) */ + USHORT DeviceID; /* (ro) */ + USHORT Command; /* Device control */ + USHORT Status; + UCHAR RevisionID; /* (ro) */ + UCHAR ProgIf; /* (ro) */ + UCHAR SubClass; /* (ro) */ + UCHAR BaseClass; /* (ro) */ + UCHAR CacheLineSize; /* (ro+) */ + UCHAR LatencyTimer; /* (ro+) */ + UCHAR HeaderType; /* (ro) */ + UCHAR BIST; /* Built in self test */ + + union { + struct _PCI_HEADER_TYPE_0 { + ULONG BaseAddresses[PCI_TYPE0_ADDRESSES]; + ULONG CIS; + USHORT SubVendorID; + USHORT SubSystemID; + ULONG ROMBaseAddress; + ULONG Reserved2[2]; + + UCHAR InterruptLine; /* */ + UCHAR InterruptPin; /* (ro) */ + UCHAR MinimumGrant; /* (ro) */ + UCHAR MaximumLatency; /* (ro) */ + } type0; + + } u; + + UCHAR DeviceSpecific[192]; + +} PCI_COMMON_CONFIG, *PPCI_COMMON_CONFIG; +#endif +#endif /* WINCE_HEADER */ + +#ifndef FIELD_OFFSET +#define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field)) +#endif + +#ifndef PCI_COMMON_HDR_LENGTH +#define PCI_COMMON_HDR_LENGTH (FIELD_OFFSET (PCI_COMMON_CONFIG, DeviceSpecific)) +#endif +#endif + +#endif diff -u --recursive --new-file v2.4.14/linux/drivers/video/sis/vstruct.h linux/drivers/video/sis/vstruct.h --- v2.4.14/linux/drivers/video/sis/vstruct.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/sis/vstruct.h Fri Nov 9 14:11:14 2001 @@ -0,0 +1,324 @@ +#ifdef _INIT_ +#define EXTERN +#else +#define EXTERN extern +#endif /* _INIT_ */ + +typedef struct _SiS_PanelDelayTblStruct { + UCHAR timer[2]; +} SiS_PanelDelayTblStruct; + +typedef struct _SiS_LCDDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS_LCDDataStruct; + +typedef struct _SiS_TVDataStruct { + USHORT RVBHCMAX; + USHORT RVBHCFACT; + USHORT VGAHT; + USHORT VGAVT; + USHORT TVHDE; + USHORT TVVDE; + USHORT RVBHRS; + UCHAR FlickerMode; + USHORT HALFRVBHRS; + UCHAR RY1COE; + UCHAR RY2COE; + UCHAR RY3COE; + UCHAR RY4COE; +} SiS_TVDataStruct; + +typedef struct _SiS_LVDSDataStruct { + USHORT VGAHT; + USHORT VGAVT; + USHORT LCDHT; + USHORT LCDVT; +} SiS_LVDSDataStruct; + +typedef struct _SiS_LVDSDesStruct { + USHORT LCDHDES; + USHORT LCDVDES; +} SiS_LVDSDesStruct; + +typedef struct _SiS_LVDSCRT1DataStruct { + UCHAR CR[15]; +} SiS_LVDSCRT1DataStruct; + +/*add for LCDA*/ +typedef struct _SiS_LCDACRT1DataStruct { + UCHAR CR[17]; +} SiS_LCDACRT1DataStruct; + +typedef struct _SiS_CHTVRegDataStruct { + UCHAR Reg[5]; +} SiS_CHTVRegDataStruct; + +typedef struct _SiS_StStruct { + UCHAR St_ModeID; + USHORT St_ModeFlag; + UCHAR St_StTableIndex; + UCHAR St_CRT2CRTC; + UCHAR St_ResInfo; + UCHAR VB_StTVFlickerIndex; + UCHAR VB_StTVEdgeIndex; + UCHAR VB_StTVYFilterIndex; +} SiS_StStruct; + +typedef struct _SiS_VBModeStruct { + UCHAR ModeID; + UCHAR VB_TVDelayIndex; + UCHAR VB_TVFlickerIndex; + UCHAR VB_TVPhaseIndex; + UCHAR VB_TVYFilterIndex; + UCHAR VB_LCDDelayIndex; + UCHAR _VB_LCDHIndex; + UCHAR _VB_LCDVIndex; +} SiS_VBModeStruct; + +typedef struct _SiS_StandTableStruct { + UCHAR CRT_COLS; + UCHAR ROWS; + UCHAR CHAR_HEIGHT; + USHORT CRT_LEN; + UCHAR SR[4]; + UCHAR MISC; + UCHAR CRTC[0x19]; + UCHAR ATTR[0x14]; + UCHAR GRC[9]; +} SiS_StandTableStruct; + +typedef struct _SiS_ExtStruct { + UCHAR Ext_ModeID; + USHORT Ext_ModeFlag; + USHORT Ext_ModeInfo; + USHORT Ext_Point; + USHORT Ext_VESAID; + UCHAR Ext_VESAMEMSize; + UCHAR Ext_RESINFO; + UCHAR VB_ExtTVFlickerIndex; + UCHAR VB_ExtTVEdgeIndex; + UCHAR VB_ExtTVYFilterIndex; + UCHAR REFindex; +} SiS_ExtStruct; + +typedef struct _SiS_Ext2Struct { + USHORT Ext_InfoFlag; + UCHAR Ext_CRT1CRTC; + UCHAR Ext_CRTVCLK; + UCHAR Ext_CRT2CRTC; + UCHAR ModeID; + USHORT XRes; + USHORT YRes; + USHORT ROM_OFFSET; +} SiS_Ext2Struct; + +typedef struct _SiS_CRT1TableStruct { + UCHAR CR[17]; +} SiS_CRT1TableStruct; + +typedef struct _SiS_MCLKDataStruct { + UCHAR SR28, SR29, SR2A; + USHORT CLOCK; +} SiS_MCLKDataStruct; + +typedef struct _SiS_ECLKDataStruct { + UCHAR SR2E, SR2F, SR30; + USHORT CLOCK; +} SiS_ECLKDataStruct; + +typedef struct _SiS_VCLKDataStruct { + UCHAR SR2B, SR2C; + USHORT CLOCK; +} SiS_VCLKDataStruct; + +typedef struct _SiS_VBVCLKDataStruct { + UCHAR Part4_A, Part4_B; + USHORT CLOCK; +} SiS_VBVCLKDataStruct; + +typedef struct _SiS_StResInfoStruct { + USHORT HTotal; + USHORT VTotal; +} SiS_StResInfoStruct; + +typedef struct _SiS_ModeResInfoStruct { + USHORT HTotal; + USHORT VTotal; + UCHAR XChar; + UCHAR YChar; +} SiS_ModeResInfoStruct; + +EXTERN SiS_StStruct *SiS_SModeIDTable; +EXTERN SiS_StandTableStruct *SiS_StandTable; +EXTERN SiS_ExtStruct *SiS_EModeIDTable; +EXTERN SiS_Ext2Struct *SiS_RefIndex; +EXTERN SiS_VBModeStruct *SiS_VBModeIDTable; +EXTERN SiS_CRT1TableStruct *SiS_CRT1Table; +EXTERN SiS_MCLKDataStruct *SiS_MCLKData; +EXTERN SiS_ECLKDataStruct *SiS_ECLKData; +EXTERN SiS_VCLKDataStruct *SiS_VCLKData; +EXTERN SiS_VBVCLKDataStruct *SiS_VBVCLKData; +EXTERN SiS_StResInfoStruct *SiS_StResInfo; +EXTERN SiS_ModeResInfoStruct *SiS_ModeResInfo; +EXTERN UCHAR *SiS_ScreenOffset; + +EXTERN UCHAR *pSiS_OutputSelect; +EXTERN UCHAR *pSiS_SoftSetting; +EXTERN UCHAR *pSiS_SR07; + +typedef UCHAR DRAM4Type[4]; +EXTERN DRAM4Type *SiS_SR15; /* pointer : point to array */ +EXTERN DRAM4Type *SiS_CR40; /* pointer : point to array */ +EXTERN UCHAR *SiS_CR49; +EXTERN UCHAR *SiS_SR25; + +EXTERN UCHAR *pSiS_SR1F; +EXTERN UCHAR *pSiS_SR21; +EXTERN UCHAR *pSiS_SR22; +EXTERN UCHAR *pSiS_SR23; +EXTERN UCHAR *pSiS_SR24; +EXTERN UCHAR *pSiS_SR31; +EXTERN UCHAR *pSiS_SR32; +EXTERN UCHAR *pSiS_SR33; +EXTERN UCHAR *pSiS_CRT2Data_1_2; +EXTERN UCHAR *pSiS_CRT2Data_4_D; +EXTERN UCHAR *pSiS_CRT2Data_4_E; +EXTERN UCHAR *pSiS_CRT2Data_4_10; +EXTERN USHORT *pSiS_RGBSenseData; +EXTERN USHORT *pSiS_VideoSenseData; +EXTERN USHORT *pSiS_YCSenseData; +EXTERN USHORT *pSiS_RGBSenseData2; /*301b */ +EXTERN USHORT *pSiS_VideoSenseData2; +EXTERN USHORT *pSiS_YCSenseData2; + +EXTERN UCHAR *SiS_NTSCPhase; +EXTERN UCHAR *SiS_PALPhase; +EXTERN UCHAR *SiS_NTSCPhase2; +EXTERN UCHAR *SiS_PALPhase2; +EXTERN UCHAR *SiS_PALMPhase; +EXTERN UCHAR *SiS_PALNPhase; +EXTERN SiS_LCDDataStruct *SiS_StLCD1024x768Data; +EXTERN SiS_LCDDataStruct *SiS_ExtLCD1024x768Data; +EXTERN SiS_LCDDataStruct *SiS_St2LCD1024x768Data; +EXTERN SiS_LCDDataStruct *SiS_StLCD1280x1024Data; +EXTERN SiS_LCDDataStruct *SiS_ExtLCD1280x1024Data; +EXTERN SiS_LCDDataStruct *SiS_St2LCD1280x1024Data; +EXTERN SiS_LCDDataStruct *SiS_NoScaleData; +EXTERN SiS_LCDDataStruct *SiS_LCD1280x960Data; +EXTERN SiS_TVDataStruct *SiS_StPALData; +EXTERN SiS_TVDataStruct *SiS_ExtPALData; +EXTERN SiS_TVDataStruct *SiS_StNTSCData; +EXTERN SiS_TVDataStruct *SiS_ExtNTSCData; +EXTERN SiS_TVDataStruct *SiS_St1HiTVData; +EXTERN SiS_TVDataStruct *SiS_St2HiTVData; +EXTERN SiS_TVDataStruct *SiS_ExtHiTVData; +EXTERN UCHAR *SiS_NTSCTiming; +EXTERN UCHAR *SiS_PALTiming; +EXTERN UCHAR *SiS_HiTVExtTiming; +EXTERN UCHAR *SiS_HiTVSt1Timing; +EXTERN UCHAR *SiS_HiTVSt2Timing; +EXTERN UCHAR *SiS_HiTVTextTiming; +EXTERN UCHAR *SiS_HiTVGroup3Data; +EXTERN UCHAR *SiS_HiTVGroup3Simu; +EXTERN UCHAR *SiS_HiTVGroup3Text; + +EXTERN SiS_PanelDelayTblStruct *SiS_PanelDelayTbl; +EXTERN SiS_LVDSDataStruct *SiS_LVDS800x600Data_1; +EXTERN SiS_LVDSDataStruct *SiS_LVDS800x600Data_2; +EXTERN SiS_LVDSDataStruct *SiS_LVDS1024x768Data_1; +EXTERN SiS_LVDSDataStruct *SiS_LVDS1024x768Data_2; +EXTERN SiS_LVDSDataStruct *SiS_LVDS1280x1024Data_1; +EXTERN SiS_LVDSDataStruct *SiS_LVDS1280x1024Data_2; +EXTERN SiS_LVDSDataStruct *SiS_LVDS640x480Data_1; +EXTERN SiS_LVDSDataStruct *SiS_CHTVUNTSCData; +EXTERN SiS_LVDSDataStruct *SiS_CHTVONTSCData; +EXTERN SiS_LVDSDataStruct *SiS_CHTVUPALData; +EXTERN SiS_LVDSDataStruct *SiS_CHTVOPALData; +EXTERN SiS_LVDSDesStruct *SiS_PanelType00_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType01_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType02_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType03_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType04_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType05_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType06_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType07_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType08_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType09_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0a_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0b_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0c_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0d_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0e_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0f_1; +EXTERN SiS_LVDSDesStruct *SiS_PanelType00_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType01_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType02_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType03_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType04_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType05_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType06_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType07_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType08_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType09_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0a_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0b_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0c_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0d_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0e_2; +EXTERN SiS_LVDSDesStruct *SiS_PanelType0f_2; +/*301b*/ +EXTERN SiS_LVDSDesStruct *LVDS1024x768Des_1; +EXTERN SiS_LVDSDesStruct *LVDS1280x1024Des_1; +EXTERN SiS_LVDSDesStruct *LVDS1280x960Des_1; +EXTERN SiS_LVDSDesStruct *LVDS1024x768Des_2; +EXTERN SiS_LVDSDesStruct *LVDS1280x1024Des_2; +EXTERN SiS_LVDSDesStruct *LVDS1280x960Des_2; +/*end 301b*/ +EXTERN SiS_LVDSDesStruct *SiS_CHTVUNTSCDesData; +EXTERN SiS_LVDSDesStruct *SiS_CHTVONTSCDesData; +EXTERN SiS_LVDSDesStruct *SiS_CHTVUPALDesData; +EXTERN SiS_LVDSDesStruct *SiS_CHTVOPALDesData; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_1; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_1; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_1; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_1_H; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_1_H; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_1_H; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_2; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_2; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_2; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_2_H; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_2_H; +EXTERN SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_2_H; +EXTERN SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1UNTSC; +EXTERN SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1ONTSC; +EXTERN SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1UPAL; +EXTERN SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1OPAL; +/*add for LCDA*/ +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT1800x600_1; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT11024x768_1; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT11280x1024_1; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT1800x600_1_H; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT11024x768_1_H; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT11280x1024_1_H; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT1800x600_2; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT11024x768_2; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT11280x1024_2; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT1800x600_2_H; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT11024x768_2_H; +EXTERN SiS_LCDACRT1DataStruct *SiS_LCDACRT11280x1024_2_H; +/*end 301b*/ + +EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_UNTSC; +EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_ONTSC; +EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_UPAL; +EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_OPAL; +EXTERN UCHAR *SiS_CHTVVCLKUNTSC; +EXTERN UCHAR *SiS_CHTVVCLKONTSC; +EXTERN UCHAR *SiS_CHTVVCLKUPAL; +EXTERN UCHAR *SiS_CHTVVCLKOPAL; diff -u --recursive --new-file v2.4.14/linux/fs/Config.in linux/fs/Config.in --- v2.4.14/linux/fs/Config.in Mon Nov 5 15:55:33 2001 +++ linux/fs/Config.in Fri Nov 9 14:25:04 2001 @@ -10,6 +10,7 @@ dep_tristate 'Reiserfs support' CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL dep_mbool ' Have reiserfs do extra internal checking' CONFIG_REISERFS_CHECK $CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL +dep_mbool ' Stats in /proc/fs/reiserfs' CONFIG_REISERFS_PROC_INFO $CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL dep_tristate 'ADFS file system support' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL dep_mbool ' ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW $CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL @@ -19,6 +20,13 @@ dep_tristate 'Apple Macintosh file system support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL + +tristate 'Ext3 journalling file system support (EXPERIMENTAL)' CONFIG_EXT3_FS +# CONFIG_JBD could be its own option (even modular), but until there are +# other users than ext3, we will simply make it be the same as CONFIG_EXT3_FS +# dep_tristate ' Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS +define_bool CONFIG_JBD $CONFIG_EXT3_FS +dep_mbool ' JBD (ext3) debugging support' CONFIG_JBD_DEBUG $CONFIG_JBD # msdos file systems tristate 'DOS FAT fs support' CONFIG_FAT_FS diff -u --recursive --new-file v2.4.14/linux/fs/Makefile linux/fs/Makefile --- v2.4.14/linux/fs/Makefile Mon Nov 5 15:55:33 2001 +++ linux/fs/Makefile Fri Nov 9 14:25:04 2001 @@ -7,7 +7,7 @@ O_TARGET := fs.o -export-objs := filesystems.o open.o dcache.o +export-objs := filesystems.o open.o dcache.o buffer.o mod-subdirs := nls obj-y := open.o read_write.o devices.o file_table.o buffer.o \ @@ -26,6 +26,8 @@ subdir-y += partitions # Do not add any filesystems before this line +subdir-$(CONFIG_EXT3_FS) += ext3 # Before ext2 so root fs can be ext3 +subdir-$(CONFIG_JBD) += jbd subdir-$(CONFIG_EXT2_FS) += ext2 subdir-$(CONFIG_ZLIB_FS_INFLATE) += inflate_fs subdir-$(CONFIG_CRAMFS) += cramfs diff -u --recursive --new-file v2.4.14/linux/fs/autofs4/inode.c linux/fs/autofs4/inode.c --- v2.4.14/linux/fs/autofs4/inode.c Fri Feb 9 11:29:44 2001 +++ linux/fs/autofs4/inode.c Fri Nov 9 14:11:14 2001 @@ -315,8 +315,10 @@ inode->i_nlink = 2; inode->i_op = &autofs4_dir_inode_operations; inode->i_fop = &autofs4_dir_operations; - } else if (S_ISLNK(inf->mode)) + } else if (S_ISLNK(inf->mode)) { + inode->i_size = inf->size; inode->i_op = &autofs4_symlink_inode_operations; + } return inode; } diff -u --recursive --new-file v2.4.14/linux/fs/buffer.c linux/fs/buffer.c --- v2.4.14/linux/fs/buffer.c Mon Nov 5 15:55:33 2001 +++ linux/fs/buffer.c Fri Nov 9 14:25:04 2001 @@ -45,6 +45,7 @@ #include <linux/quotaops.h> #include <linux/iobuf.h> #include <linux/highmem.h> +#include <linux/module.h> #include <linux/completion.h> #include <asm/uaccess.h> @@ -613,8 +614,12 @@ information that was supposed to be just stored on the physical layer by the user. - Thus invalidate_buffers in general usage is not allwowed to trash dirty - buffers. For example ioctl(FLSBLKBUF) expects dirty data to be preserved. + Thus invalidate_buffers in general usage is not allwowed to trash + dirty buffers. For example ioctl(FLSBLKBUF) expects dirty data to + be preserved. These buffers are simply skipped. + + We also skip buffers which are still in use. For example this can + happen if a userspace program is reading the block device. NOTE: In the case where the user removed a removable-media-disk even if there's still dirty data not synced on disk (due a bug in the device driver @@ -1090,6 +1095,12 @@ } } +void set_buffer_flushtime(struct buffer_head *bh) +{ + bh->b_flushtime = jiffies + bdf_prm.b_un.age_buffer; +} +EXPORT_SYMBOL(set_buffer_flushtime); + /* * A buffer may need to be moved from one buffer list to another * (e.g. in case it is not shared any more). Handle this. @@ -1165,7 +1176,7 @@ /* * Note: the caller should wake up the buffer_wait list if needed. */ -static __inline__ void __put_unused_buffer_head(struct buffer_head * bh) +static void __put_unused_buffer_head(struct buffer_head * bh) { if (bh->b_inode) BUG(); @@ -1182,12 +1193,20 @@ } } +void put_unused_buffer_head(struct buffer_head *bh) +{ + spin_lock(&unused_list_lock); + __put_unused_buffer_head(bh); + spin_unlock(&unused_list_lock); +} +EXPORT_SYMBOL(put_unused_buffer_head); + /* * Reserve NR_RESERVED buffer heads for async IO requests to avoid * no-buffer-head deadlock. Return NULL on failure; waiting for * buffer heads is now handled in create_buffers(). */ -static struct buffer_head * get_unused_buffer_head(int async) +struct buffer_head * get_unused_buffer_head(int async) { struct buffer_head * bh; @@ -1228,6 +1247,7 @@ return NULL; } +EXPORT_SYMBOL(get_unused_buffer_head); void set_bh_page (struct buffer_head *bh, struct page *page, unsigned long offset) { @@ -1242,6 +1262,7 @@ else bh->b_data = page_address(page) + offset; } +EXPORT_SYMBOL(set_bh_page); /* * Create the appropriate buffers when given a page for data area and @@ -1335,6 +1356,31 @@ } } +/** + * try_to_release_page - release old fs-specific metadata on a page + * + */ + +int try_to_release_page(struct page * page, int gfp_mask) +{ + if (!PageLocked(page)) + BUG(); + + if (!page->mapping) + goto try_to_free; + if (!page->mapping->a_ops->releasepage) + goto try_to_free; + if (page->mapping->a_ops->releasepage(page, gfp_mask)) + goto try_to_free; + /* + * We couldn't release buffer metadata; don't even bother trying + * to release buffers. + */ + return 0; +try_to_free: + return try_to_free_buffers(page, gfp_mask); +} + /* * We don't have to release all buffers here, but * we have to be sure that no dirty buffer is left @@ -1378,7 +1424,7 @@ * instead. */ if (!offset) { - if (!try_to_free_buffers(page, 0)) + if (!try_to_release_page(page, 0)) return 0; } @@ -1406,6 +1452,7 @@ page->buffers = head; page_cache_get(page); } +EXPORT_SYMBOL(create_empty_buffers); /* * We are taking a block for data and we don't want any output from any @@ -1446,8 +1493,7 @@ */ /* - * block_write_full_page() is SMP-safe - currently it's still - * being called with the kernel lock held, but the code is ready. + * block_write_full_page() is SMP threaded - the kernel lock is not held. */ static int __block_write_full_page(struct inode *inode, struct page *page, get_block_t *get_block) { @@ -2444,6 +2490,7 @@ wakeup_bdflush(); return 0; } +EXPORT_SYMBOL(try_to_free_buffers); /* ================== Debugging =================== */ diff -u --recursive --new-file v2.4.14/linux/fs/ext3/Makefile linux/fs/ext3/Makefile --- v2.4.14/linux/fs/ext3/Makefile Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/Makefile Fri Nov 9 14:25:04 2001 @@ -0,0 +1,16 @@ +# +# Makefile for the linux ext2-filesystem routines. +# +# 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... + +O_TARGET := ext3.o + +obj-y := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ + ioctl.o namei.o super.o symlink.o +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.14/linux/fs/ext3/acl.c linux/fs/ext3/acl.c --- v2.4.14/linux/fs/ext3/acl.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/acl.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,17 @@ +/* + * linux/fs/ext3/acl.c + * + * Copyright (C) 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include <linux/fs.h> +#include <linux/sched.h> + + +/* + * This file will contain the Access Control Lists management for the + * second extended file system. + */ diff -u --recursive --new-file v2.4.14/linux/fs/ext3/balloc.c linux/fs/ext3/balloc.c --- v2.4.14/linux/fs/ext3/balloc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/balloc.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,995 @@ +/* + * linux/fs/ext3/balloc.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * Enhanced block allocation by Stephen Tweedie (sct@redhat.com), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/ext3_fs.h> +#include <linux/ext3_jbd.h> +#include <linux/locks.h> +#include <linux/quotaops.h> + +/* + * balloc.c contains the blocks allocation and deallocation routines + */ + +/* + * The free blocks are managed by bitmaps. A file system contains several + * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap + * block for inodes, N blocks for the inode table and data blocks. + * + * The file system contains group descriptors which are located after the + * super block. Each descriptor contains the number of the bitmap block and + * the free blocks count in the block. The descriptors are loaded in memory + * when a file system is mounted (see ext3_read_super). + */ + + +#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) + +struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh) +{ + unsigned long group_desc; + unsigned long desc; + struct ext3_group_desc * gdp; + + if (block_group >= sb->u.ext3_sb.s_groups_count) { + ext3_error (sb, "ext3_get_group_desc", + "block_group >= groups_count - " + "block_group = %d, groups_count = %lu", + block_group, sb->u.ext3_sb.s_groups_count); + + return NULL; + } + + group_desc = block_group / EXT3_DESC_PER_BLOCK(sb); + desc = block_group % EXT3_DESC_PER_BLOCK(sb); + if (!sb->u.ext3_sb.s_group_desc[group_desc]) { + ext3_error (sb, "ext3_get_group_desc", + "Group descriptor not loaded - " + "block_group = %d, group_desc = %lu, desc = %lu", + block_group, group_desc, desc); + return NULL; + } + + gdp = (struct ext3_group_desc *) + sb->u.ext3_sb.s_group_desc[group_desc]->b_data; + if (bh) + *bh = sb->u.ext3_sb.s_group_desc[group_desc]; + return gdp + desc; +} + +/* + * Read the bitmap for a given block_group, reading into the specified + * slot in the superblock's bitmap cache. + * + * Return >=0 on success or a -ve error code. + */ + +static int read_block_bitmap (struct super_block * sb, + unsigned int block_group, + unsigned long bitmap_nr) +{ + struct ext3_group_desc * gdp; + struct buffer_head * bh = NULL; + int retval = -EIO; + + gdp = ext3_get_group_desc (sb, block_group, NULL); + if (!gdp) + goto error_out; + retval = 0; + bh = bread (sb->s_dev, + le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize); + if (!bh) { + ext3_error (sb, "read_block_bitmap", + "Cannot read block bitmap - " + "block_group = %d, block_bitmap = %lu", + block_group, (unsigned long) gdp->bg_block_bitmap); + retval = -EIO; + } + /* + * On IO error, just leave a zero in the superblock's block pointer for + * this group. The IO will be retried next time. + */ +error_out: + sb->u.ext3_sb.s_block_bitmap_number[bitmap_nr] = block_group; + sb->u.ext3_sb.s_block_bitmap[bitmap_nr] = bh; + return retval; +} + +/* + * load_block_bitmap loads the block bitmap for a blocks group + * + * It maintains a cache for the last bitmaps loaded. This cache is managed + * with a LRU algorithm. + * + * Notes: + * 1/ There is one cache per mounted file system. + * 2/ If the file system contains less than EXT3_MAX_GROUP_LOADED groups, + * this function reads the bitmap without maintaining a LRU cache. + * + * Return the slot used to store the bitmap, or a -ve error code. + */ +static int __load_block_bitmap (struct super_block * sb, + unsigned int block_group) +{ + int i, j, retval = 0; + unsigned long block_bitmap_number; + struct buffer_head * block_bitmap; + + if (block_group >= sb->u.ext3_sb.s_groups_count) + ext3_panic (sb, "load_block_bitmap", + "block_group >= groups_count - " + "block_group = %d, groups_count = %lu", + block_group, sb->u.ext3_sb.s_groups_count); + + if (sb->u.ext3_sb.s_groups_count <= EXT3_MAX_GROUP_LOADED) { + if (sb->u.ext3_sb.s_block_bitmap[block_group]) { + if (sb->u.ext3_sb.s_block_bitmap_number[block_group] == + block_group) + return block_group; + ext3_error (sb, "__load_block_bitmap", + "block_group != block_bitmap_number"); + } + retval = read_block_bitmap (sb, block_group, block_group); + if (retval < 0) + return retval; + return block_group; + } + + for (i = 0; i < sb->u.ext3_sb.s_loaded_block_bitmaps && + sb->u.ext3_sb.s_block_bitmap_number[i] != block_group; i++) + ; + if (i < sb->u.ext3_sb.s_loaded_block_bitmaps && + sb->u.ext3_sb.s_block_bitmap_number[i] == block_group) { + block_bitmap_number = sb->u.ext3_sb.s_block_bitmap_number[i]; + block_bitmap = sb->u.ext3_sb.s_block_bitmap[i]; + for (j = i; j > 0; j--) { + sb->u.ext3_sb.s_block_bitmap_number[j] = + sb->u.ext3_sb.s_block_bitmap_number[j - 1]; + sb->u.ext3_sb.s_block_bitmap[j] = + sb->u.ext3_sb.s_block_bitmap[j - 1]; + } + sb->u.ext3_sb.s_block_bitmap_number[0] = block_bitmap_number; + sb->u.ext3_sb.s_block_bitmap[0] = block_bitmap; + + /* + * There's still one special case here --- if block_bitmap == 0 + * then our last attempt to read the bitmap failed and we have + * just ended up caching that failure. Try again to read it. + */ + if (!block_bitmap) + retval = read_block_bitmap (sb, block_group, 0); + } else { + if (sb->u.ext3_sb.s_loaded_block_bitmaps<EXT3_MAX_GROUP_LOADED) + sb->u.ext3_sb.s_loaded_block_bitmaps++; + else + brelse (sb->u.ext3_sb.s_block_bitmap + [EXT3_MAX_GROUP_LOADED - 1]); + for (j = sb->u.ext3_sb.s_loaded_block_bitmaps - 1; + j > 0; j--) { + sb->u.ext3_sb.s_block_bitmap_number[j] = + sb->u.ext3_sb.s_block_bitmap_number[j - 1]; + sb->u.ext3_sb.s_block_bitmap[j] = + sb->u.ext3_sb.s_block_bitmap[j - 1]; + } + retval = read_block_bitmap (sb, block_group, 0); + } + return retval; +} + +/* + * Load the block bitmap for a given block group. First of all do a couple + * of fast lookups for common cases and then pass the request onto the guts + * of the bitmap loader. + * + * Return the slot number of the group in the superblock bitmap cache's on + * success, or a -ve error code. + * + * There is still one inconsistency here --- if the number of groups in this + * filesystems is <= EXT3_MAX_GROUP_LOADED, then we have no way of + * differentiating between a group for which we have never performed a bitmap + * IO request, and a group for which the last bitmap read request failed. + */ +static inline int load_block_bitmap (struct super_block * sb, + unsigned int block_group) +{ + int slot; + + /* + * Do the lookup for the slot. First of all, check if we're asking + * for the same slot as last time, and did we succeed that last time? + */ + if (sb->u.ext3_sb.s_loaded_block_bitmaps > 0 && + sb->u.ext3_sb.s_block_bitmap_number[0] == block_group && + sb->u.ext3_sb.s_block_bitmap[0]) { + return 0; + } + /* + * Or can we do a fast lookup based on a loaded group on a filesystem + * small enough to be mapped directly into the superblock? + */ + else if (sb->u.ext3_sb.s_groups_count <= EXT3_MAX_GROUP_LOADED && + sb->u.ext3_sb.s_block_bitmap_number[block_group]==block_group + && sb->u.ext3_sb.s_block_bitmap[block_group]) { + slot = block_group; + } + /* + * If not, then do a full lookup for this block group. + */ + else { + slot = __load_block_bitmap (sb, block_group); + } + + /* + * <0 means we just got an error + */ + if (slot < 0) + return slot; + + /* + * If it's a valid slot, we may still have cached a previous IO error, + * in which case the bh in the superblock cache will be zero. + */ + if (!sb->u.ext3_sb.s_block_bitmap[slot]) + return -EIO; + + /* + * Must have been read in OK to get this far. + */ + return slot; +} + +/* Free given blocks, update quota and i_blocks field */ +void ext3_free_blocks (handle_t *handle, struct inode * inode, + unsigned long block, unsigned long count) +{ + struct buffer_head *bitmap_bh; + struct buffer_head *gd_bh; + unsigned long block_group; + unsigned long bit; + unsigned long i; + int bitmap_nr; + unsigned long overflow; + struct super_block * sb; + struct ext3_group_desc * gdp; + struct ext3_super_block * es; + int err = 0, ret; + int dquot_freed_blocks = 0; + + sb = inode->i_sb; + if (!sb) { + printk ("ext3_free_blocks: nonexistent device"); + return; + } + lock_super (sb); + es = sb->u.ext3_sb.s_es; + if (block < le32_to_cpu(es->s_first_data_block) || + (block + count) > le32_to_cpu(es->s_blocks_count)) { + ext3_error (sb, "ext3_free_blocks", + "Freeing blocks not in datazone - " + "block = %lu, count = %lu", block, count); + goto error_return; + } + + ext3_debug ("freeing block %lu\n", block); + +do_more: + overflow = 0; + block_group = (block - le32_to_cpu(es->s_first_data_block)) / + EXT3_BLOCKS_PER_GROUP(sb); + bit = (block - le32_to_cpu(es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb); + /* + * Check to see if we are freeing blocks across a group + * boundary. + */ + if (bit + count > EXT3_BLOCKS_PER_GROUP(sb)) { + overflow = bit + count - EXT3_BLOCKS_PER_GROUP(sb); + count -= overflow; + } + bitmap_nr = load_block_bitmap (sb, block_group); + if (bitmap_nr < 0) + goto error_return; + + bitmap_bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr]; + gdp = ext3_get_group_desc (sb, block_group, &gd_bh); + if (!gdp) + goto error_return; + + if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) || + in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) || + in_range (block, le32_to_cpu(gdp->bg_inode_table), + sb->u.ext3_sb.s_itb_per_group) || + in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table), + sb->u.ext3_sb.s_itb_per_group)) + ext3_error (sb, "ext3_free_blocks", + "Freeing blocks in system zones - " + "Block = %lu, count = %lu", + block, count); + + /* + * We are about to start releasing blocks in the bitmap, + * so we need undo access. + */ + /* @@@ check errors */ + BUFFER_TRACE(bitmap_bh, "getting undo access"); + err = ext3_journal_get_undo_access(handle, bitmap_bh); + if (err) + goto error_return; + + /* + * We are about to modify some metadata. Call the journal APIs + * to unshare ->b_data if a currently-committing transaction is + * using it + */ + BUFFER_TRACE(gd_bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, gd_bh); + if (err) + goto error_return; + + BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "get_write_access"); + err = ext3_journal_get_write_access(handle, sb->u.ext3_sb.s_sbh); + if (err) + goto error_return; + + for (i = 0; i < count; i++) { + /* + * An HJ special. This is expensive... + */ +#ifdef CONFIG_JBD_DEBUG + { + struct buffer_head *debug_bh; + debug_bh = get_hash_table(sb->s_dev, block + i, + sb->s_blocksize); + if (debug_bh) { + BUFFER_TRACE(debug_bh, "Deleted!"); + if (!bh2jh(bitmap_bh)->b_committed_data) + BUFFER_TRACE(debug_bh, + "No commited data in bitmap"); + BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap"); + __brelse(debug_bh); + } + } +#endif + BUFFER_TRACE(bitmap_bh, "clear bit"); + if (!ext3_clear_bit (bit + i, bitmap_bh->b_data)) { + ext3_error (sb, __FUNCTION__, + "bit already cleared for block %lu", + block + i); + BUFFER_TRACE(bitmap_bh, "bit already cleared"); + } else { + dquot_freed_blocks++; + gdp->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1); + es->s_free_blocks_count = + cpu_to_le32(le32_to_cpu(es->s_free_blocks_count)+1); + } + /* @@@ This prevents newly-allocated data from being + * freed and then reallocated within the same + * transaction. + * + * Ideally we would want to allow that to happen, but to + * do so requires making journal_forget() capable of + * revoking the queued write of a data block, which + * implies blocking on the journal lock. *forget() + * cannot block due to truncate races. + * + * Eventually we can fix this by making journal_forget() + * return a status indicating whether or not it was able + * to revoke the buffer. On successful revoke, it is + * safe not to set the allocation bit in the committed + * bitmap, because we know that there is no outstanding + * activity on the buffer any more and so it is safe to + * reallocate it. + */ + BUFFER_TRACE(bitmap_bh, "clear in b_committed_data"); + J_ASSERT_BH(bitmap_bh, + bh2jh(bitmap_bh)->b_committed_data != NULL); + ext3_set_bit(bit + i, bh2jh(bitmap_bh)->b_committed_data); + } + + /* We dirtied the bitmap block */ + BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); + err = ext3_journal_dirty_metadata(handle, bitmap_bh); + + /* And the group descriptor block */ + BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); + ret = ext3_journal_dirty_metadata(handle, gd_bh); + if (!err) err = ret; + + /* And the superblock */ + BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "dirtied superblock"); + ret = ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh); + if (!err) err = ret; + + if (overflow && !err) { + block += count; + count = overflow; + goto do_more; + } + sb->s_dirt = 1; +error_return: + ext3_std_error(sb, err); + unlock_super(sb); + if (dquot_freed_blocks) + DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); + return; +} + +/* For ext3 allocations, we must not reuse any blocks which are + * allocated in the bitmap buffer's "last committed data" copy. This + * prevents deletes from freeing up the page for reuse until we have + * committed the delete transaction. + * + * If we didn't do this, then deleting something and reallocating it as + * data would allow the old block to be overwritten before the + * transaction committed (because we force data to disk before commit). + * This would lead to corruption if we crashed between overwriting the + * data and committing the delete. + * + * @@@ We may want to make this allocation behaviour conditional on + * data-writes at some point, and disable it for metadata allocations or + * sync-data inodes. + */ +static int ext3_test_allocatable(int nr, struct buffer_head *bh) +{ + if (ext3_test_bit(nr, bh->b_data)) + return 0; + if (!buffer_jbd(bh) || !bh2jh(bh)->b_committed_data) + return 1; + return !ext3_test_bit(nr, bh2jh(bh)->b_committed_data); +} + +/* + * Find an allocatable block in a bitmap. We honour both the bitmap and + * its last-committed copy (if that exists), and perform the "most + * appropriate allocation" algorithm of looking for a free block near + * the initial goal; then for a free byte somewhere in the bitmap; then + * for any free bit in the bitmap. + */ +static int find_next_usable_block(int start, + struct buffer_head *bh, int maxblocks) +{ + int here, next; + char *p, *r; + + if (start > 0) { + /* + * The goal was occupied; search forward for a free + * block within the next XX blocks. + * + * end_goal is more or less random, but it has to be + * less than EXT3_BLOCKS_PER_GROUP. Aligning up to the + * next 64-bit boundary is simple.. + */ + int end_goal = (start + 63) & ~63; + here = ext3_find_next_zero_bit(bh->b_data, end_goal, start); + if (here < end_goal && ext3_test_allocatable(here, bh)) + return here; + + ext3_debug ("Bit not found near goal\n"); + + } + + here = start; + if (here < 0) + here = 0; + + /* + * There has been no free block found in the near vicinity of + * the goal: do a search forward through the block groups, + * searching in each group first for an entire free byte in the + * bitmap and then for any free bit. + * + * Search first in the remainder of the current group + */ + p = ((char *) bh->b_data) + (here >> 3); + r = memscan(p, 0, (maxblocks - here + 7) >> 3); + next = (r - ((char *) bh->b_data)) << 3; + + if (next < maxblocks && ext3_test_allocatable(next, bh)) + return next; + + /* The bitmap search --- search forward alternately + * through the actual bitmap and the last-committed copy + * until we find a bit free in both. */ + + while (here < maxblocks) { + next = ext3_find_next_zero_bit ((unsigned long *) bh->b_data, + maxblocks, here); + if (next >= maxblocks) + return -1; + if (ext3_test_allocatable(next, bh)) + return next; + + J_ASSERT_BH(bh, bh2jh(bh)->b_committed_data); + here = ext3_find_next_zero_bit + ((unsigned long *) bh2jh(bh)->b_committed_data, + maxblocks, next); + } + return -1; +} + +/* + * ext3_new_block uses a goal block to assist allocation. If the goal is + * free, or there is a free block within 32 blocks of the goal, that block + * is allocated. Otherwise a forward search is made for a free block; within + * each block group the search first looks for an entire free byte in the block + * bitmap, and then for any free bit if that fails. + * This function also updates quota and i_blocks field. + */ +int ext3_new_block (handle_t *handle, struct inode * inode, + unsigned long goal, u32 * prealloc_count, + u32 * prealloc_block, int * errp) +{ + struct buffer_head * bh, *bhtmp; + struct buffer_head * bh2; +#if 0 + char * p, * r; +#endif + int i, j, k, tmp, alloctmp; + int bitmap_nr; + int fatal = 0, err; + struct super_block * sb; + struct ext3_group_desc * gdp; + struct ext3_super_block * es; +#ifdef EXT3FS_DEBUG + static int goal_hits = 0, goal_attempts = 0; +#endif + *errp = -ENOSPC; + sb = inode->i_sb; + if (!sb) { + printk ("ext3_new_block: nonexistent device"); + return 0; + } + + /* + * Check quota for allocation of this block. + */ + if (DQUOT_ALLOC_BLOCK(inode, 1)) { + *errp = -EDQUOT; + return 0; + } + + lock_super (sb); + es = sb->u.ext3_sb.s_es; + if (le32_to_cpu(es->s_free_blocks_count) <= + le32_to_cpu(es->s_r_blocks_count) && + ((sb->u.ext3_sb.s_resuid != current->fsuid) && + (sb->u.ext3_sb.s_resgid == 0 || + !in_group_p (sb->u.ext3_sb.s_resgid)) && + !capable(CAP_SYS_RESOURCE))) + goto out; + + ext3_debug ("goal=%lu.\n", goal); + + /* + * First, test whether the goal block is free. + */ + if (goal < le32_to_cpu(es->s_first_data_block) || + goal >= le32_to_cpu(es->s_blocks_count)) + goal = le32_to_cpu(es->s_first_data_block); + i = (goal - le32_to_cpu(es->s_first_data_block)) / + EXT3_BLOCKS_PER_GROUP(sb); + gdp = ext3_get_group_desc (sb, i, &bh2); + if (!gdp) + goto io_error; + + if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) { + j = ((goal - le32_to_cpu(es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb)); +#ifdef EXT3FS_DEBUG + if (j) + goal_attempts++; +#endif + bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) + goto io_error; + + bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr]; + + ext3_debug ("goal is at %d:%d.\n", i, j); + + if (ext3_test_allocatable(j, bh)) { +#ifdef EXT3FS_DEBUG + goal_hits++; + ext3_debug ("goal bit allocated.\n"); +#endif + goto got_block; + } + + j = find_next_usable_block(j, bh, EXT3_BLOCKS_PER_GROUP(sb)); + if (j >= 0) + goto search_back; + } + + ext3_debug ("Bit not found in block group %d.\n", i); + + /* + * Now search the rest of the groups. We assume that + * i and gdp correctly point to the last group visited. + */ + for (k = 0; k < sb->u.ext3_sb.s_groups_count; k++) { + i++; + if (i >= sb->u.ext3_sb.s_groups_count) + i = 0; + gdp = ext3_get_group_desc (sb, i, &bh2); + if (!gdp) { + *errp = -EIO; + goto out; + } + if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) { + bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) + goto io_error; + + bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr]; + j = find_next_usable_block(-1, bh, + EXT3_BLOCKS_PER_GROUP(sb)); + if (j >= 0) + goto search_back; + } + } + + /* No space left on the device */ + unlock_super (sb); + return 0; + +search_back: + /* + * We have succeeded in finding a free byte in the block + * bitmap. Now search backwards up to 7 bits to find the + * start of this group of free blocks. + */ + for ( k = 0; + k < 7 && j > 0 && ext3_test_allocatable(j - 1, bh); + k++, j--) + ; + +got_block: + + ext3_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count); + + /* Make sure we use undo access for the bitmap, because it is + critical that we do the frozen_data COW on bitmap buffers in + all cases even if the buffer is in BJ_Forget state in the + committing transaction. */ + BUFFER_TRACE(bh, "get undo access for marking new block"); + fatal = ext3_journal_get_undo_access(handle, bh); + if (fatal) goto out; + + BUFFER_TRACE(bh2, "get_write_access"); + fatal = ext3_journal_get_write_access(handle, bh2); + if (fatal) goto out; + + BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "get_write_access"); + fatal = ext3_journal_get_write_access(handle, sb->u.ext3_sb.s_sbh); + if (fatal) goto out; + + tmp = j + i * EXT3_BLOCKS_PER_GROUP(sb) + + le32_to_cpu(es->s_first_data_block); + + if (tmp == le32_to_cpu(gdp->bg_block_bitmap) || + tmp == le32_to_cpu(gdp->bg_inode_bitmap) || + in_range (tmp, le32_to_cpu(gdp->bg_inode_table), + sb->u.ext3_sb.s_itb_per_group)) + ext3_error (sb, "ext3_new_block", + "Allocating block in system zone - " + "block = %u", tmp); + + /* The superblock lock should guard against anybody else beating + * us to this point! */ + J_ASSERT_BH(bh, !ext3_test_bit(j, bh->b_data)); + BUFFER_TRACE(bh, "setting bitmap bit"); + ext3_set_bit(j, bh->b_data); + +#ifdef CONFIG_JBD_DEBUG + { + struct buffer_head *debug_bh; + + /* Record bitmap buffer state in the newly allocated block */ + debug_bh = get_hash_table(sb->s_dev, tmp, sb->s_blocksize); + if (debug_bh) { + BUFFER_TRACE(debug_bh, "state when allocated"); + BUFFER_TRACE2(debug_bh, bh, "bitmap state"); + brelse(debug_bh); + } + } +#endif + if (buffer_jbd(bh) && bh2jh(bh)->b_committed_data) + J_ASSERT_BH(bh, !ext3_test_bit(j, bh2jh(bh)->b_committed_data)); + bhtmp = bh; + alloctmp = j; + + ext3_debug ("found bit %d\n", j); + + /* + * Do block preallocation now if required. + */ +#ifdef EXT3_PREALLOCATE + /* + * akpm: this is not enabled for ext3. Need to use + * ext3_test_allocatable() + */ + /* Writer: ->i_prealloc* */ + if (prealloc_count && !*prealloc_count) { + int prealloc_goal; + unsigned long next_block = tmp + 1; + + prealloc_goal = es->s_prealloc_blocks ? + es->s_prealloc_blocks : EXT3_DEFAULT_PREALLOC_BLOCKS; + + *prealloc_block = next_block; + /* Writer: end */ + for (k = 1; + k < prealloc_goal && (j + k) < EXT3_BLOCKS_PER_GROUP(sb); + k++, next_block++) { + if (DQUOT_PREALLOC_BLOCK(inode, 1)) + break; + /* Writer: ->i_prealloc* */ + if (*prealloc_block + *prealloc_count != next_block || + ext3_set_bit (j + k, bh->b_data)) { + /* Writer: end */ + DQUOT_FREE_BLOCK(inode, 1); + break; + } + (*prealloc_count)++; + /* Writer: end */ + } + /* + * As soon as we go for per-group spinlocks we'll need these + * done inside the loop above. + */ + gdp->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - + (k - 1)); + es->s_free_blocks_count = + cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - + (k - 1)); + ext3_debug ("Preallocated a further %lu bits.\n", + (k - 1)); + } +#endif + + j = tmp; + + BUFFER_TRACE(bh, "journal_dirty_metadata for bitmap block"); + err = ext3_journal_dirty_metadata(handle, bh); + if (!fatal) fatal = err; + + if (j >= le32_to_cpu(es->s_blocks_count)) { + ext3_error (sb, "ext3_new_block", + "block(%d) >= blocks count(%d) - " + "block_group = %d, es == %p ",j, + le32_to_cpu(es->s_blocks_count), i, es); + goto out; + } + + /* + * It is up to the caller to add the new buffer to a journal + * list of some description. We don't know in advance whether + * the caller wants to use it as metadata or data. + */ + + ext3_debug ("allocating block %d. " + "Goal hits %d of %d.\n", j, goal_hits, goal_attempts); + + gdp->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1); + es->s_free_blocks_count = + cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1); + + BUFFER_TRACE(bh2, "journal_dirty_metadata for group descriptor"); + err = ext3_journal_dirty_metadata(handle, bh2); + if (!fatal) fatal = err; + + BUFFER_TRACE(bh, "journal_dirty_metadata for superblock"); + err = ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh); + if (!fatal) fatal = err; + + sb->s_dirt = 1; + if (fatal) + goto out; + + unlock_super (sb); + *errp = 0; + return j; + +io_error: + *errp = -EIO; +out: + if (fatal) { + *errp = fatal; + ext3_std_error(sb, fatal); + } + unlock_super (sb); + return 0; + +} + +unsigned long ext3_count_free_blocks (struct super_block * sb) +{ +#ifdef EXT3FS_DEBUG + struct ext3_super_block * es; + unsigned long desc_count, bitmap_count, x; + int bitmap_nr; + struct ext3_group_desc * gdp; + int i; + + lock_super (sb); + es = sb->u.ext3_sb.s_es; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) { + gdp = ext3_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_blocks_count); + bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + + x = ext3_count_free (sb->u.ext3_sb.s_block_bitmap[bitmap_nr], + sb->s_blocksize); + printk ("group %d: stored = %d, counted = %lu\n", + i, le16_to_cpu(gdp->bg_free_blocks_count), x); + bitmap_count += x; + } + printk("ext3_count_free_blocks: stored = %lu, computed = %lu, %lu\n", + le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count); + unlock_super (sb); + return bitmap_count; +#else + return le32_to_cpu(sb->u.ext3_sb.s_es->s_free_blocks_count); +#endif +} + +static inline int block_in_use (unsigned long block, + struct super_block * sb, + unsigned char * map) +{ + return ext3_test_bit ((block - + le32_to_cpu(sb->u.ext3_sb.s_es->s_first_data_block)) % + EXT3_BLOCKS_PER_GROUP(sb), map); +} + +static inline int test_root(int a, int b) +{ + if (a == 0) + return 1; + while (1) { + if (a == 1) + return 1; + if (a % b) + return 0; + a = a / b; + } +} + +int ext3_group_sparse(int group) +{ + return (test_root(group, 3) || test_root(group, 5) || + test_root(group, 7)); +} + +/** + * ext3_bg_has_super - number of blocks used by the superblock in group + * @sb: superblock for filesystem + * @group: group number to check + * + * Return the number of blocks used by the superblock (primary or backup) + * in this group. Currently this will be only 0 or 1. + */ +int ext3_bg_has_super(struct super_block *sb, int group) +{ + if (EXT3_HAS_RO_COMPAT_FEATURE(sb,EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)&& + !ext3_group_sparse(group)) + return 0; + return 1; +} + +/** + * ext3_bg_num_gdb - number of blocks used by the group table in group + * @sb: superblock for filesystem + * @group: group number to check + * + * Return the number of blocks used by the group descriptor table + * (primary or backup) in this group. In the future there may be a + * different number of descriptor blocks in each group. + */ +unsigned long ext3_bg_num_gdb(struct super_block *sb, int group) +{ + if (EXT3_HAS_RO_COMPAT_FEATURE(sb,EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)&& + !ext3_group_sparse(group)) + return 0; + return EXT3_SB(sb)->s_gdb_count; +} + +#ifdef CONFIG_EXT3_CHECK +/* Called at mount-time, super-block is locked */ +void ext3_check_blocks_bitmap (struct super_block * sb) +{ + struct buffer_head * bh; + struct ext3_super_block * es; + unsigned long desc_count, bitmap_count, x, j; + unsigned long desc_blocks; + int bitmap_nr; + struct ext3_group_desc * gdp; + int i; + + es = sb->u.ext3_sb.s_es; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) { + gdp = ext3_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_blocks_count); + bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + + bh = EXT3_SB(sb)->s_block_bitmap[bitmap_nr]; + + if (ext3_bg_has_super(sb, i) && !ext3_test_bit(0, bh->b_data)) + ext3_error(sb, __FUNCTION__, + "Superblock in group %d is marked free", i); + + desc_blocks = ext3_bg_num_gdb(sb, i); + for (j = 0; j < desc_blocks; j++) + if (!ext3_test_bit(j + 1, bh->b_data)) + ext3_error(sb, __FUNCTION__, + "Descriptor block #%ld in group " + "%d is marked free", j, i); + + if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap), + sb, bh->b_data)) + ext3_error (sb, "ext3_check_blocks_bitmap", + "Block bitmap for group %d is marked free", + i); + + if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap), + sb, bh->b_data)) + ext3_error (sb, "ext3_check_blocks_bitmap", + "Inode bitmap for group %d is marked free", + i); + + for (j = 0; j < sb->u.ext3_sb.s_itb_per_group; j++) + if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j, + sb, bh->b_data)) + ext3_error (sb, "ext3_check_blocks_bitmap", + "Block #%d of the inode table in " + "group %d is marked free", j, i); + + x = ext3_count_free (bh, sb->s_blocksize); + if (le16_to_cpu(gdp->bg_free_blocks_count) != x) + ext3_error (sb, "ext3_check_blocks_bitmap", + "Wrong free blocks count for group %d, " + "stored = %d, counted = %lu", i, + le16_to_cpu(gdp->bg_free_blocks_count), x); + bitmap_count += x; + } + if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count) + ext3_error (sb, "ext3_check_blocks_bitmap", + "Wrong free blocks count in super block, " + "stored = %lu, counted = %lu", + (unsigned long)le32_to_cpu(es->s_free_blocks_count), + bitmap_count); +} +#endif diff -u --recursive --new-file v2.4.14/linux/fs/ext3/bitmap.c linux/fs/ext3/bitmap.c --- v2.4.14/linux/fs/ext3/bitmap.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/bitmap.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,26 @@ +/* + * linux/fs/ext3/bitmap.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include <linux/fs.h> + + +static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; + +unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars) +{ + unsigned int i; + unsigned long sum = 0; + + if (!map) + return (0); + for (i = 0; i < numchars; i++) + sum += nibblemap[map->b_data[i] & 0xf] + + nibblemap[(map->b_data[i] >> 4) & 0xf]; + return (sum); +} diff -u --recursive --new-file v2.4.14/linux/fs/ext3/dir.c linux/fs/ext3/dir.c --- v2.4.14/linux/fs/ext3/dir.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/dir.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,190 @@ +/* + * linux/fs/ext3/dir.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/dir.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext3 directory handling functions + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/ext3_fs.h> + +static unsigned char ext3_filetype_table[] = { + DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK +}; + +static int ext3_readdir(struct file *, void *, filldir_t); + +struct file_operations ext3_dir_operations = { + read: generic_read_dir, + readdir: ext3_readdir, /* BKL held */ + ioctl: ext3_ioctl, /* BKL held */ + fsync: ext3_sync_file, /* BKL held */ +}; + +int ext3_check_dir_entry (const char * function, struct inode * dir, + struct ext3_dir_entry_2 * de, + struct buffer_head * bh, + unsigned long offset) +{ + const char * error_msg = NULL; + const int rlen = le16_to_cpu(de->rec_len); + + if (rlen < EXT3_DIR_REC_LEN(1)) + error_msg = "rec_len is smaller than minimal"; + else if (rlen % 4 != 0) + error_msg = "rec_len % 4 != 0"; + else if (rlen < EXT3_DIR_REC_LEN(de->name_len)) + error_msg = "rec_len is too small for name_len"; + else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) + error_msg = "directory entry across blocks"; + else if (le32_to_cpu(de->inode) > + le32_to_cpu(dir->i_sb->u.ext3_sb.s_es->s_inodes_count)) + error_msg = "inode out of bounds"; + + if (error_msg != NULL) + ext3_error (dir->i_sb, function, + "bad entry in directory #%lu: %s - " + "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", + dir->i_ino, error_msg, offset, + (unsigned long) le32_to_cpu(de->inode), + rlen, de->name_len); + return error_msg == NULL ? 1 : 0; +} + +static int ext3_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + int error = 0; + unsigned long offset, blk; + int i, num, stored; + struct buffer_head * bh, * tmp, * bha[16]; + struct ext3_dir_entry_2 * de; + struct super_block * sb; + int err; + struct inode *inode = filp->f_dentry->d_inode; + + sb = inode->i_sb; + + stored = 0; + bh = NULL; + offset = filp->f_pos & (sb->s_blocksize - 1); + + while (!error && !stored && filp->f_pos < inode->i_size) { + blk = (filp->f_pos) >> EXT3_BLOCK_SIZE_BITS(sb); + bh = ext3_bread (0, inode, blk, 0, &err); + if (!bh) { + ext3_error (sb, "ext3_readdir", + "directory #%lu contains a hole at offset %lu", + inode->i_ino, (unsigned long)filp->f_pos); + filp->f_pos += sb->s_blocksize - offset; + continue; + } + + /* + * Do the readahead + */ + if (!offset) { + for (i = 16 >> (EXT3_BLOCK_SIZE_BITS(sb) - 9), num = 0; + i > 0; i--) { + tmp = ext3_getblk (NULL, inode, ++blk, 0, &err); + if (tmp && !buffer_uptodate(tmp) && + !buffer_locked(tmp)) + bha[num++] = tmp; + else + brelse (tmp); + } + if (num) { + ll_rw_block (READA, num, bha); + for (i = 0; i < num; i++) + brelse (bha[i]); + } + } + +revalidate: + /* If the dir block has changed since the last call to + * readdir(2), then we might be pointing to an invalid + * dirent right now. Scan from the start of the block + * to make sure. */ + if (filp->f_version != inode->i_version) { + for (i = 0; i < sb->s_blocksize && i < offset; ) { + de = (struct ext3_dir_entry_2 *) + (bh->b_data + i); + /* It's too expensive to do a full + * dirent test each time round this + * loop, but we do have to test at + * least that it is non-zero. A + * failure will be detected in the + * dirent test below. */ + if (le16_to_cpu(de->rec_len) < + EXT3_DIR_REC_LEN(1)) + break; + i += le16_to_cpu(de->rec_len); + } + offset = i; + filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) + | offset; + filp->f_version = inode->i_version; + } + + while (!error && filp->f_pos < inode->i_size + && offset < sb->s_blocksize) { + de = (struct ext3_dir_entry_2 *) (bh->b_data + offset); + if (!ext3_check_dir_entry ("ext3_readdir", inode, de, + bh, offset)) { + /* On error, skip the f_pos to the + next block. */ + filp->f_pos = (filp->f_pos | + (sb->s_blocksize - 1)) + 1; + brelse (bh); + return stored; + } + offset += le16_to_cpu(de->rec_len); + if (le32_to_cpu(de->inode)) { + /* We might block in the next section + * if the data destination is + * currently swapped out. So, use a + * version stamp to detect whether or + * not the directory has been modified + * during the copy operation. + */ + unsigned long version = filp->f_version; + unsigned char d_type = DT_UNKNOWN; + + if (EXT3_HAS_INCOMPAT_FEATURE(sb, + EXT3_FEATURE_INCOMPAT_FILETYPE) + && de->file_type < EXT3_FT_MAX) + d_type = + ext3_filetype_table[de->file_type]; + error = filldir(dirent, de->name, + de->name_len, + filp->f_pos, + le32_to_cpu(de->inode), + d_type); + if (error) + break; + if (version != filp->f_version) + goto revalidate; + stored ++; + } + filp->f_pos += le16_to_cpu(de->rec_len); + } + offset = 0; + brelse (bh); + } + UPDATE_ATIME(inode); + return 0; +} diff -u --recursive --new-file v2.4.14/linux/fs/ext3/file.c linux/fs/ext3/file.c --- v2.4.14/linux/fs/ext3/file.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/file.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,97 @@ +/* + * linux/fs/ext3/file.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/file.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext3 fs regular file handling primitives + * + * 64-bit file support on 64-bit platforms by Jakub Jelinek + * (jj@sunsite.ms.mff.cuni.cz) + */ + +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/locks.h> +#include <linux/jbd.h> +#include <linux/ext3_fs.h> +#include <linux/ext3_jbd.h> +#include <linux/smp_lock.h> + +/* + * Called when an inode is released. Note that this is different + * from ext3_file_open: open gets called at every open, but release + * gets called only when /all/ the files are closed. + */ +static int ext3_release_file (struct inode * inode, struct file * filp) +{ + if (filp->f_mode & FMODE_WRITE) + ext3_discard_prealloc (inode); + return 0; +} + +/* + * Called when an inode is about to be opened. + * We use this to disallow opening RW large files on 32bit systems if + * the caller didn't specify O_LARGEFILE. On 64bit systems we force + * on this flag in sys_open. + */ +static int ext3_open_file (struct inode * inode, struct file * filp) +{ + if (!(filp->f_flags & O_LARGEFILE) && + inode->i_size > 0x7FFFFFFFLL) + return -EFBIG; + return 0; +} + +/* + * ext3_file_write(). + * + * Most things are done in ext3_prepare_write() and ext3_commit_write(). + */ + +static ssize_t +ext3_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + int ret; + struct inode *inode = file->f_dentry->d_inode; + + ret = generic_file_write(file, buf, count, ppos); + if ((ret >= 0) && IS_SYNC(inode)) { + if (file->f_flags & O_SYNC) { + /* + * generic_osync_inode() has already done the sync + */ + } else { + int ret2 = ext3_force_commit(inode->i_sb); + if (ret2) + ret = ret2; + } + } + return ret; +} + +struct file_operations ext3_file_operations = { + llseek: generic_file_llseek, /* BKL held */ + read: generic_file_read, /* BKL not held. Don't need */ + write: ext3_file_write, /* BKL not held. Don't need */ + ioctl: ext3_ioctl, /* BKL held */ + mmap: generic_file_mmap, + open: ext3_open_file, /* BKL not held. Don't need */ + release: ext3_release_file, /* BKL not held. Don't need */ + fsync: ext3_sync_file, /* BKL held */ +}; + +struct inode_operations ext3_file_inode_operations = { + truncate: ext3_truncate, /* BKL held */ + setattr: ext3_setattr, /* BKL held */ +}; + diff -u --recursive --new-file v2.4.14/linux/fs/ext3/fsync.c linux/fs/ext3/fsync.c --- v2.4.14/linux/fs/ext3/fsync.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/fsync.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,69 @@ +/* + * linux/fs/ext3/fsync.c + * + * Copyright (C) 1993 Stephen Tweedie (sct@redhat.com) + * from + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * from + * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds + * + * ext3fs fsync primitive + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + * + * Removed unnecessary code duplication for little endian machines + * and excessive __inline__s. + * Andi Kleen, 1997 + * + * Major simplications and cleanup - we only need to do the metadata, because + * we can depend on generic_block_fdatasync() to sync the data blocks. + */ + +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/ext3_fs.h> +#include <linux/ext3_jbd.h> +#include <linux/jbd.h> +#include <linux/smp_lock.h> + +/* + * akpm: A new design for ext3_sync_file(). + * + * This is only called from sys_fsync(), sys_fdatasync() and sys_msync(). + * There cannot be a transaction open by this task. (AKPM: quotas?) + * Another task could have dirtied this inode. Its data can be in any + * state in the journalling system. + * + * What we do is just kick off a commit and wait on it. This will snapshot the + * inode to disk. + * + * Note that there is a serious optimisation we can make here: if the current + * inode is not part of j_running_transaction or j_committing_transaction + * then we have nothing to do. That would require implementation of t_ilist, + * which isn't too hard. + */ + +int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) +{ + struct inode *inode = dentry->d_inode; + int ret; + + J_ASSERT(ext3_journal_current_handle() == 0); + + /* + * fsync_inode_buffers() just walks i_dirty_buffers and waits + * on them. It's a no-op for full data journalling because + * i_dirty_buffers will be ampty. + * Really, we only need to start I/O on the dirty buffers - + * we'll end up waiting on them in commit. + */ + ret = fsync_inode_buffers(inode); + + ext3_force_commit(inode->i_sb); + + return ret; +} diff -u --recursive --new-file v2.4.14/linux/fs/ext3/ialloc.c linux/fs/ext3/ialloc.c --- v2.4.14/linux/fs/ext3/ialloc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/ialloc.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,664 @@ +/* + * linux/fs/ext3/ialloc.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * BSD ufs-inspired inode and directory allocation by + * Stephen Tweedie (sct@redhat.com), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/ext3_fs.h> +#include <linux/ext3_jbd.h> +#include <linux/stat.h> +#include <linux/string.h> +#include <linux/locks.h> +#include <linux/quotaops.h> + +#include <asm/bitops.h> +#include <asm/byteorder.h> + +/* + * ialloc.c contains the inodes allocation and deallocation routines + */ + +/* + * The free inodes are managed by bitmaps. A file system contains several + * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap + * block for inodes, N blocks for the inode table and data blocks. + * + * The file system contains group descriptors which are located after the + * super block. Each descriptor contains the number of the bitmap block and + * the free blocks count in the block. The descriptors are loaded in memory + * when a file system is mounted (see ext3_read_super). + */ + + +/* + * Read the inode allocation bitmap for a given block_group, reading + * into the specified slot in the superblock's bitmap cache. + * + * Return >=0 on success or a -ve error code. + */ +static int read_inode_bitmap (struct super_block * sb, + unsigned long block_group, + unsigned int bitmap_nr) +{ + struct ext3_group_desc * gdp; + struct buffer_head * bh = NULL; + int retval = 0; + + gdp = ext3_get_group_desc (sb, block_group, NULL); + if (!gdp) { + retval = -EIO; + goto error_out; + } + bh = bread (sb->s_dev, + le32_to_cpu(gdp->bg_inode_bitmap), sb->s_blocksize); + if (!bh) { + ext3_error (sb, "read_inode_bitmap", + "Cannot read inode bitmap - " + "block_group = %lu, inode_bitmap = %lu", + block_group, (unsigned long) gdp->bg_inode_bitmap); + retval = -EIO; + } + /* + * On IO error, just leave a zero in the superblock's block pointer for + * this group. The IO will be retried next time. + */ +error_out: + sb->u.ext3_sb.s_inode_bitmap_number[bitmap_nr] = block_group; + sb->u.ext3_sb.s_inode_bitmap[bitmap_nr] = bh; + return retval; +} + +/* + * load_inode_bitmap loads the inode bitmap for a blocks group + * + * It maintains a cache for the last bitmaps loaded. This cache is managed + * with a LRU algorithm. + * + * Notes: + * 1/ There is one cache per mounted file system. + * 2/ If the file system contains less than EXT3_MAX_GROUP_LOADED groups, + * this function reads the bitmap without maintaining a LRU cache. + * + * Return the slot used to store the bitmap, or a -ve error code. + */ +static int load_inode_bitmap (struct super_block * sb, + unsigned int block_group) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + unsigned long inode_bitmap_number; + struct buffer_head * inode_bitmap; + int i, j, retval = 0; + + if (block_group >= sbi->s_groups_count) + ext3_panic (sb, "load_inode_bitmap", + "block_group >= groups_count - " + "block_group = %d, groups_count = %lu", + block_group, sbi->s_groups_count); + if (sbi->s_loaded_inode_bitmaps > 0 && + sbi->s_inode_bitmap_number[0] == block_group && + sbi->s_inode_bitmap[0] != NULL) + return 0; + if (sbi->s_groups_count <= EXT3_MAX_GROUP_LOADED) { + if (sbi->s_inode_bitmap[block_group]) { + if (sbi->s_inode_bitmap_number[block_group] != + block_group) + ext3_panic(sb, "load_inode_bitmap", + "block_group != inode_bitmap_number"); + return block_group; + } + retval = read_inode_bitmap(sb, block_group, block_group); + if (retval < 0) + return retval; + return block_group; + } + + for (i = 0; i < sbi->s_loaded_inode_bitmaps && + sbi->s_inode_bitmap_number[i] != block_group; i++) + /* do nothing */; + if (i < sbi->s_loaded_inode_bitmaps && + sbi->s_inode_bitmap_number[i] == block_group) { + inode_bitmap_number = sbi->s_inode_bitmap_number[i]; + inode_bitmap = sbi->s_inode_bitmap[i]; + for (j = i; j > 0; j--) { + sbi->s_inode_bitmap_number[j] = + sbi->s_inode_bitmap_number[j - 1]; + sbi->s_inode_bitmap[j] = sbi->s_inode_bitmap[j - 1]; + } + sbi->s_inode_bitmap_number[0] = inode_bitmap_number; + sbi->s_inode_bitmap[0] = inode_bitmap; + + /* + * There's still one special case here --- if inode_bitmap == 0 + * then our last attempt to read the bitmap failed and we have + * just ended up caching that failure. Try again to read it. + */ + if (!inode_bitmap) + retval = read_inode_bitmap (sb, block_group, 0); + } else { + if (sbi->s_loaded_inode_bitmaps < EXT3_MAX_GROUP_LOADED) + sbi->s_loaded_inode_bitmaps++; + else + brelse(sbi->s_inode_bitmap[EXT3_MAX_GROUP_LOADED - 1]); + for (j = sbi->s_loaded_inode_bitmaps - 1; j > 0; j--) { + sbi->s_inode_bitmap_number[j] = + sbi->s_inode_bitmap_number[j - 1]; + sbi->s_inode_bitmap[j] = sbi->s_inode_bitmap[j - 1]; + } + retval = read_inode_bitmap (sb, block_group, 0); + } + return retval; +} + +/* + * NOTE! When we get the inode, we're the only people + * that have access to it, and as such there are no + * race conditions we have to worry about. The inode + * is not on the hash-lists, and it cannot be reached + * through the filesystem because the directory entry + * has been deleted earlier. + * + * HOWEVER: we must make sure that we get no aliases, + * which means that we have to call "clear_inode()" + * _before_ we mark the inode not in use in the inode + * bitmaps. Otherwise a newly created file might use + * the same inode number (not actually the same pointer + * though), and then we'd have two inodes sharing the + * same inode number and space on the harddisk. + */ +void ext3_free_inode (handle_t *handle, struct inode * inode) +{ + struct super_block * sb = inode->i_sb; + int is_directory; + unsigned long ino; + struct buffer_head * bh; + struct buffer_head * bh2; + unsigned long block_group; + unsigned long bit; + int bitmap_nr; + struct ext3_group_desc * gdp; + struct ext3_super_block * es; + int fatal = 0, err; + + if (!inode->i_dev) { + printk ("ext3_free_inode: inode has no device\n"); + return; + } + if (atomic_read(&inode->i_count) > 1) { + printk ("ext3_free_inode: inode has count=%d\n", + atomic_read(&inode->i_count)); + return; + } + if (inode->i_nlink) { + printk ("ext3_free_inode: inode has nlink=%d\n", + inode->i_nlink); + return; + } + if (!sb) { + printk("ext3_free_inode: inode on nonexistent device\n"); + return; + } + + ino = inode->i_ino; + ext3_debug ("freeing inode %lu\n", ino); + + /* + * Note: we must free any quota before locking the superblock, + * as writing the quota to disk may need the lock as well. + */ + DQUOT_INIT(inode); + DQUOT_FREE_INODE(inode); + DQUOT_DROP(inode); + + is_directory = S_ISDIR(inode->i_mode); + + /* Do this BEFORE marking the inode not in use or returning an error */ + clear_inode (inode); + + lock_super (sb); + es = sb->u.ext3_sb.s_es; + if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { + ext3_error (sb, "ext3_free_inode", + "reserved or nonexistent inode %lu", ino); + goto error_return; + } + block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); + bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb); + bitmap_nr = load_inode_bitmap (sb, block_group); + if (bitmap_nr < 0) + goto error_return; + + bh = sb->u.ext3_sb.s_inode_bitmap[bitmap_nr]; + + BUFFER_TRACE(bh, "get_write_access"); + fatal = ext3_journal_get_write_access(handle, bh); + if (fatal) + goto error_return; + + /* Ok, now we can actually update the inode bitmaps.. */ + if (!ext3_clear_bit (bit, bh->b_data)) + ext3_error (sb, "ext3_free_inode", + "bit already cleared for inode %lu", ino); + else { + gdp = ext3_get_group_desc (sb, block_group, &bh2); + + BUFFER_TRACE(bh2, "get_write_access"); + fatal = ext3_journal_get_write_access(handle, bh2); + if (fatal) goto error_return; + + BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "get write access"); + fatal = ext3_journal_get_write_access(handle, sb->u.ext3_sb.s_sbh); + if (fatal) goto error_return; + + if (gdp) { + gdp->bg_free_inodes_count = cpu_to_le16( + le16_to_cpu(gdp->bg_free_inodes_count) + 1); + if (is_directory) + gdp->bg_used_dirs_count = cpu_to_le16( + le16_to_cpu(gdp->bg_used_dirs_count) - 1); + } + BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh2); + if (!fatal) fatal = err; + es->s_free_inodes_count = + cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1); + BUFFER_TRACE(sb->u.ext3_sb.s_sbh, + "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh); + if (!fatal) fatal = err; + } + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh); + if (!fatal) + fatal = err; + sb->s_dirt = 1; +error_return: + ext3_std_error(sb, fatal); + unlock_super(sb); +} + +/* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of + * the groups with above-average free space, that group with the fewest + * directories already is chosen. + * + * For other inodes, search forward from the parent directory's block + * group to find a free inode. + */ +struct inode * ext3_new_inode (handle_t *handle, + const struct inode * dir, int mode) +{ + struct super_block * sb; + struct buffer_head * bh; + struct buffer_head * bh2; + int i, j, avefreei; + struct inode * inode; + int bitmap_nr; + struct ext3_group_desc * gdp; + struct ext3_group_desc * tmp; + struct ext3_super_block * es; + int err = 0; + + /* Cannot create files in a deleted directory */ + if (!dir || !dir->i_nlink) + return ERR_PTR(-EPERM); + + sb = dir->i_sb; + inode = new_inode(sb); + if (!inode) + return ERR_PTR(-ENOMEM); + init_rwsem(&inode->u.ext3_i.truncate_sem); + + lock_super (sb); + es = sb->u.ext3_sb.s_es; +repeat: + gdp = NULL; + i = 0; + + if (S_ISDIR(mode)) { + avefreei = le32_to_cpu(es->s_free_inodes_count) / + sb->u.ext3_sb.s_groups_count; + if (!gdp) { + for (j = 0; j < sb->u.ext3_sb.s_groups_count; j++) { + struct buffer_head *temp_buffer; + tmp = ext3_get_group_desc (sb, j, &temp_buffer); + if (tmp && + le16_to_cpu(tmp->bg_free_inodes_count) && + le16_to_cpu(tmp->bg_free_inodes_count) >= + avefreei) { + if (!gdp || (le16_to_cpu(tmp->bg_free_blocks_count) > + le16_to_cpu(gdp->bg_free_blocks_count))) { + i = j; + gdp = tmp; + bh2 = temp_buffer; + } + } + } + } + } else { + /* + * Try to place the inode in its parent directory + */ + i = dir->u.ext3_i.i_block_group; + tmp = ext3_get_group_desc (sb, i, &bh2); + if (tmp && le16_to_cpu(tmp->bg_free_inodes_count)) + gdp = tmp; + else + { + /* + * Use a quadratic hash to find a group with a + * free inode + */ + for (j = 1; j < sb->u.ext3_sb.s_groups_count; j <<= 1) { + i += j; + if (i >= sb->u.ext3_sb.s_groups_count) + i -= sb->u.ext3_sb.s_groups_count; + tmp = ext3_get_group_desc (sb, i, &bh2); + if (tmp && + le16_to_cpu(tmp->bg_free_inodes_count)) { + gdp = tmp; + break; + } + } + } + if (!gdp) { + /* + * That failed: try linear search for a free inode + */ + i = dir->u.ext3_i.i_block_group + 1; + for (j = 2; j < sb->u.ext3_sb.s_groups_count; j++) { + if (++i >= sb->u.ext3_sb.s_groups_count) + i = 0; + tmp = ext3_get_group_desc (sb, i, &bh2); + if (tmp && + le16_to_cpu(tmp->bg_free_inodes_count)) { + gdp = tmp; + break; + } + } + } + } + + err = -ENOSPC; + if (!gdp) + goto fail; + + err = -EIO; + bitmap_nr = load_inode_bitmap (sb, i); + if (bitmap_nr < 0) + goto fail; + + bh = sb->u.ext3_sb.s_inode_bitmap[bitmap_nr]; + + if ((j = ext3_find_first_zero_bit ((unsigned long *) bh->b_data, + EXT3_INODES_PER_GROUP(sb))) < + EXT3_INODES_PER_GROUP(sb)) { + BUFFER_TRACE(bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, bh); + if (err) goto fail; + + if (ext3_set_bit (j, bh->b_data)) { + ext3_error (sb, "ext3_new_inode", + "bit already set for inode %d", j); + goto repeat; + } + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh); + if (err) goto fail; + } else { + if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) { + ext3_error (sb, "ext3_new_inode", + "Free inodes count corrupted in group %d", + i); + /* Is it really ENOSPC? */ + err = -ENOSPC; + if (sb->s_flags & MS_RDONLY) + goto fail; + + BUFFER_TRACE(bh2, "get_write_access"); + err = ext3_journal_get_write_access(handle, bh2); + if (err) goto fail; + gdp->bg_free_inodes_count = 0; + BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh2); + if (err) goto fail; + } + goto repeat; + } + j += i * EXT3_INODES_PER_GROUP(sb) + 1; + if (j < EXT3_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) { + ext3_error (sb, "ext3_new_inode", + "reserved inode or inode > inodes count - " + "block_group = %d,inode=%d", i, j); + err = -EIO; + goto fail; + } + + BUFFER_TRACE(bh2, "get_write_access"); + err = ext3_journal_get_write_access(handle, bh2); + if (err) goto fail; + gdp->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1); + if (S_ISDIR(mode)) + gdp->bg_used_dirs_count = + cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1); + BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh2); + if (err) goto fail; + + BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "get_write_access"); + err = ext3_journal_get_write_access(handle, sb->u.ext3_sb.s_sbh); + if (err) goto fail; + es->s_free_inodes_count = + cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1); + BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh); + sb->s_dirt = 1; + if (err) goto fail; + + inode->i_uid = current->fsuid; + if (test_opt (sb, GRPID)) + inode->i_gid = dir->i_gid; + else if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } else + inode->i_gid = current->fsgid; + inode->i_mode = mode; + + inode->i_ino = j; + /* This is the optimal IO size (for stat), not the fs block size */ + inode->i_blksize = PAGE_SIZE; + inode->i_blocks = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->u.ext3_i.i_flags = dir->u.ext3_i.i_flags & ~EXT3_INDEX_FL; + if (S_ISLNK(mode)) + inode->u.ext3_i.i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL); +#ifdef EXT3_FRAGMENTS + inode->u.ext3_i.i_faddr = 0; + inode->u.ext3_i.i_frag_no = 0; + inode->u.ext3_i.i_frag_size = 0; +#endif + inode->u.ext3_i.i_file_acl = 0; + inode->u.ext3_i.i_dir_acl = 0; + inode->u.ext3_i.i_dtime = 0; + INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan); +#ifdef EXT3_PREALLOCATE + inode->u.ext3_i.i_prealloc_count = 0; +#endif + inode->u.ext3_i.i_block_group = i; + + if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL) + inode->i_flags |= S_SYNC; + if (IS_SYNC(inode)) + handle->h_sync = 1; + insert_inode_hash(inode); + inode->i_generation = event++; + + inode->u.ext3_i.i_state = EXT3_STATE_NEW; + err = ext3_mark_inode_dirty(handle, inode); + if (err) goto fail; + + unlock_super (sb); + if(DQUOT_ALLOC_INODE(inode)) { + DQUOT_DROP(inode); + inode->i_flags |= S_NOQUOTA; + inode->i_nlink = 0; + iput(inode); + return ERR_PTR(-EDQUOT); + } + ext3_debug ("allocating inode %lu\n", inode->i_ino); + return inode; + +fail: + unlock_super(sb); + iput(inode); + ext3_std_error(sb, err); + return ERR_PTR(err); +} + +/* Verify that we are loading a valid orphan from disk */ +struct inode *ext3_orphan_get (struct super_block * sb, ino_t ino) +{ + ino_t max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count); + unsigned long block_group; + int bit; + int bitmap_nr; + struct buffer_head *bh; + struct inode *inode = NULL; + + /* Error cases - e2fsck has already cleaned up for us */ + if (ino > max_ino) { + ext3_warning(sb, __FUNCTION__, + "bad orphan ino %ld! e2fsck was run?\n", ino); + return NULL; + } + + block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); + bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb); + if ((bitmap_nr = load_inode_bitmap(sb, block_group)) < 0 || + !(bh = EXT3_SB(sb)->s_inode_bitmap[bitmap_nr])) { + ext3_warning(sb, __FUNCTION__, + "inode bitmap error for orphan %ld\n", ino); + return NULL; + } + + /* Having the inode bit set should be a 100% indicator that this + * is a valid orphan (no e2fsck run on fs). Orphans also include + * inodes that were being truncated, so we can't check i_nlink==0. + */ + if (!ext3_test_bit(bit, bh->b_data) || !(inode = iget(sb, ino)) || + is_bad_inode(inode) || NEXT_ORPHAN(inode) > max_ino) { + ext3_warning(sb, __FUNCTION__, + "bad orphan inode %ld! e2fsck was run?\n", ino); + printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%ld) = %d\n", + bit, bh->b_blocknr, ext3_test_bit(bit, bh->b_data)); + printk(KERN_NOTICE "inode=%p\n", inode); + if (inode) { + printk(KERN_NOTICE "is_bad_inode(inode)=%d\n", + is_bad_inode(inode)); + printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%d\n", + NEXT_ORPHAN(inode)); + printk(KERN_NOTICE "max_ino=%ld\n", max_ino); + } + /* Avoid freeing blocks if we got a bad deleted inode */ + if (inode && inode->i_nlink == 0) + inode->i_blocks = 0; + iput(inode); + return NULL; + } + + return inode; +} + +unsigned long ext3_count_free_inodes (struct super_block * sb) +{ +#ifdef EXT3FS_DEBUG + struct ext3_super_block * es; + unsigned long desc_count, bitmap_count, x; + int bitmap_nr; + struct ext3_group_desc * gdp; + int i; + + lock_super (sb); + es = sb->u.ext3_sb.s_es; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) { + gdp = ext3_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_inodes_count); + bitmap_nr = load_inode_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + + x = ext3_count_free (sb->u.ext3_sb.s_inode_bitmap[bitmap_nr], + EXT3_INODES_PER_GROUP(sb) / 8); + printk ("group %d: stored = %d, counted = %lu\n", + i, le16_to_cpu(gdp->bg_free_inodes_count), x); + bitmap_count += x; + } + printk("ext3_count_free_inodes: stored = %lu, computed = %lu, %lu\n", + le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count); + unlock_super (sb); + return desc_count; +#else + return le32_to_cpu(sb->u.ext3_sb.s_es->s_free_inodes_count); +#endif +} + +#ifdef CONFIG_EXT3_CHECK +/* Called at mount-time, super-block is locked */ +void ext3_check_inodes_bitmap (struct super_block * sb) +{ + struct ext3_super_block * es; + unsigned long desc_count, bitmap_count, x; + int bitmap_nr; + struct ext3_group_desc * gdp; + int i; + + es = sb->u.ext3_sb.s_es; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) { + gdp = ext3_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_inodes_count); + bitmap_nr = load_inode_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + + x = ext3_count_free (sb->u.ext3_sb.s_inode_bitmap[bitmap_nr], + EXT3_INODES_PER_GROUP(sb) / 8); + if (le16_to_cpu(gdp->bg_free_inodes_count) != x) + ext3_error (sb, "ext3_check_inodes_bitmap", + "Wrong free inodes count in group %d, " + "stored = %d, counted = %lu", i, + le16_to_cpu(gdp->bg_free_inodes_count), x); + bitmap_count += x; + } + if (le32_to_cpu(es->s_free_inodes_count) != bitmap_count) + ext3_error (sb, "ext3_check_inodes_bitmap", + "Wrong free inodes count in super block, " + "stored = %lu, counted = %lu", + (unsigned long)le32_to_cpu(es->s_free_inodes_count), + bitmap_count); +} +#endif diff -u --recursive --new-file v2.4.14/linux/fs/ext3/inode.c linux/fs/ext3/inode.c --- v2.4.14/linux/fs/ext3/inode.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/inode.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,2672 @@ +/* + * linux/fs/ext3/inode.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Goal-directed block allocation by Stephen Tweedie + * (sct@redhat.com), 1993, 1998 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + * 64-bit file support on 64-bit platforms by Jakub Jelinek + * (jj@sunsite.ms.mff.cuni.cz) + * + * Assorted race fixes, rewrite of ext3_get_block() by Al Viro, 2000 + */ + +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/ext3_jbd.h> +#include <linux/jbd.h> +#include <linux/locks.h> +#include <linux/smp_lock.h> +#include <linux/highuid.h> +#include <linux/quotaops.h> +#include <linux/module.h> + + +/* + * SEARCH_FROM_ZERO forces each block allocation to search from the start + * of the filesystem. This is to force rapid reallocation of recently-freed + * blocks. The file fragmentation is horrendous. + */ +#undef SEARCH_FROM_ZERO + +/* The ext3 forget function must perform a revoke if we are freeing data + * which has been journaled. Metadata (eg. indirect blocks) must be + * revoked in all cases. + * + * "bh" may be NULL: a metadata block may have been freed from memory + * but there may still be a record of it in the journal, and that record + * still needs to be revoked. + */ + +static int ext3_forget(handle_t *handle, int is_metadata, + struct inode *inode, struct buffer_head *bh, + int blocknr) +{ + int err; + + BUFFER_TRACE(bh, "enter"); + + jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " + "data mode %lx\n", + bh, is_metadata, inode->i_mode, + test_opt(inode->i_sb, DATA_FLAGS)); + + /* Never use the revoke function if we are doing full data + * journaling: there is no need to, and a V1 superblock won't + * support it. Otherwise, only skip the revoke on un-journaled + * data blocks. */ + + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA || + (!is_metadata && !ext3_should_journal_data(inode))) { + if (bh) { + BUFFER_TRACE(bh, "call journal_forget"); + ext3_journal_forget(handle, bh); + } + return 0; + } + + /* + * data!=journal && (is_metadata || should_journal_data(inode)) + */ + BUFFER_TRACE(bh, "call ext3_journal_revoke"); + err = ext3_journal_revoke(handle, blocknr, bh); + if (err) + ext3_abort(inode->i_sb, __FUNCTION__, + "error %d when attempting revoke", err); + BUFFER_TRACE(bh, "exit"); + return err; +} + +/* + * Truncate transactions can be complex and absolutely huge. So we need to + * be able to restart the transaction at a conventient checkpoint to make + * sure we don't overflow the journal. + * + * start_transaction gets us a new handle for a truncate transaction, + * and extend_transaction tries to extend the existing one a bit. If + * extend fails, we need to propagate the failure up and restart the + * transaction in the top-level truncate loop. --sct + */ + +static handle_t *start_transaction(struct inode *inode) +{ + long needed; + handle_t *result; + + needed = inode->i_blocks; + if (needed > EXT3_MAX_TRANS_DATA) + needed = EXT3_MAX_TRANS_DATA; + + result = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS + needed); + if (!IS_ERR(result)) + return result; + + ext3_std_error(inode->i_sb, PTR_ERR(result)); + return result; +} + +/* + * Try to extend this transaction for the purposes of truncation. + * + * Returns 0 if we managed to create more room. If we can't create more + * room, and the transaction must be restarted we return 1. + */ +static int try_to_extend_transaction(handle_t *handle, struct inode *inode) +{ + long needed; + + if (handle->h_buffer_credits > EXT3_RESERVE_TRANS_BLOCKS) + return 0; + needed = inode->i_blocks; + if (needed > EXT3_MAX_TRANS_DATA) + needed = EXT3_MAX_TRANS_DATA; + if (!ext3_journal_extend(handle, EXT3_RESERVE_TRANS_BLOCKS + needed)) + return 0; + return 1; +} + +/* + * Restart the transaction associated with *handle. This does a commit, + * so before we call here everything must be consistently dirtied against + * this transaction. + */ +static int ext3_journal_test_restart(handle_t *handle, struct inode *inode) +{ + long needed = inode->i_blocks; + if (needed > EXT3_MAX_TRANS_DATA) + needed = EXT3_MAX_TRANS_DATA; + jbd_debug(2, "restarting handle %p\n", handle); + return ext3_journal_restart(handle, EXT3_DATA_TRANS_BLOCKS + needed); +} + +/* + * Called at each iput() + */ +void ext3_put_inode (struct inode * inode) +{ + ext3_discard_prealloc (inode); +} + +/* + * Called at the last iput() if i_nlink is zero. + */ +void ext3_delete_inode (struct inode * inode) +{ + handle_t *handle; + + if (is_bad_inode(inode) || + inode->i_ino == EXT3_ACL_IDX_INO || + inode->i_ino == EXT3_ACL_DATA_INO) + goto no_delete; + + lock_kernel(); + handle = start_transaction(inode); + if (IS_ERR(handle)) { + /* If we're going to skip the normal cleanup, we still + * need to make sure that the in-core orphan linked list + * is properly cleaned up. */ + ext3_orphan_del(NULL, inode); + + ext3_std_error(inode->i_sb, PTR_ERR(handle)); + unlock_kernel(); + goto no_delete; + } + + if (IS_SYNC(inode)) + handle->h_sync = 1; + inode->i_size = 0; + if (inode->i_blocks) + ext3_truncate(inode); + /* + * Kill off the orphan record which ext3_truncate created. + * AKPM: I think this can be inside the above `if'. + * Note that ext3_orphan_del() has to be able to cope with the + * deletion of a non-existent orphan - this is because we don't + * know if ext3_truncate() actually created an orphan record. + * (Well, we could do this if we need to, but heck - it works) + */ + ext3_orphan_del(handle, inode); + inode->u.ext3_i.i_dtime = CURRENT_TIME; + + /* + * One subtle ordering requirement: if anything has gone wrong + * (transaction abort, IO errors, whatever), then we can still + * do these next steps (the fs will already have been marked as + * having errors), but we can't free the inode if the mark_dirty + * fails. + */ + if (ext3_mark_inode_dirty(handle, inode)) + /* If that failed, just do the required in-core inode clear. */ + clear_inode(inode); + else + ext3_free_inode(handle, inode); + ext3_journal_stop(handle, inode); + unlock_kernel(); + return; +no_delete: + clear_inode(inode); /* We must guarantee clearing of inode... */ +} + +void ext3_discard_prealloc (struct inode * inode) +{ +#ifdef EXT3_PREALLOCATE + lock_kernel(); + /* Writer: ->i_prealloc* */ + if (inode->u.ext3_i.i_prealloc_count) { + unsigned short total = inode->u.ext3_i.i_prealloc_count; + unsigned long block = inode->u.ext3_i.i_prealloc_block; + inode->u.ext3_i.i_prealloc_count = 0; + inode->u.ext3_i.i_prealloc_block = 0; + /* Writer: end */ + ext3_free_blocks (inode, block, total); + } + unlock_kernel(); +#endif +} + +static int ext3_alloc_block (handle_t *handle, + struct inode * inode, unsigned long goal, int *err) +{ +#ifdef EXT3FS_DEBUG + static unsigned long alloc_hits = 0, alloc_attempts = 0; +#endif + unsigned long result; + +#ifdef EXT3_PREALLOCATE + /* Writer: ->i_prealloc* */ + if (inode->u.ext3_i.i_prealloc_count && + (goal == inode->u.ext3_i.i_prealloc_block || + goal + 1 == inode->u.ext3_i.i_prealloc_block)) + { + result = inode->u.ext3_i.i_prealloc_block++; + inode->u.ext3_i.i_prealloc_count--; + /* Writer: end */ + ext3_debug ("preallocation hit (%lu/%lu).\n", + ++alloc_hits, ++alloc_attempts); + } else { + ext3_discard_prealloc (inode); + ext3_debug ("preallocation miss (%lu/%lu).\n", + alloc_hits, ++alloc_attempts); + if (S_ISREG(inode->i_mode)) + result = ext3_new_block (inode, goal, + &inode->u.ext3_i.i_prealloc_count, + &inode->u.ext3_i.i_prealloc_block, err); + else + result = ext3_new_block (inode, goal, 0, 0, err); + /* + * AKPM: this is somewhat sticky. I'm not surprised it was + * disabled in 2.2's ext3. Need to integrate b_committed_data + * guarding with preallocation, if indeed preallocation is + * effective. + */ + } +#else + result = ext3_new_block (handle, inode, goal, 0, 0, err); +#endif + return result; +} + + +typedef struct { + u32 *p; + u32 key; + struct buffer_head *bh; +} Indirect; + +static inline void add_chain(Indirect *p, struct buffer_head *bh, u32 *v) +{ + p->key = *(p->p = v); + p->bh = bh; +} + +static inline int verify_chain(Indirect *from, Indirect *to) +{ + while (from <= to && from->key == *from->p) + from++; + return (from > to); +} + +/** + * ext3_block_to_path - parse the block number into array of offsets + * @inode: inode in question (we are only interested in its superblock) + * @i_block: block number to be parsed + * @offsets: array to store the offsets in + * + * To store the locations of file's data ext3 uses a data structure common + * for UNIX filesystems - tree of pointers anchored in the inode, with + * data blocks at leaves and indirect blocks in intermediate nodes. + * This function translates the block number into path in that tree - + * return value is the path length and @offsets[n] is the offset of + * pointer to (n+1)th node in the nth one. If @block is out of range + * (negative or too large) warning is printed and zero returned. + * + * Note: function doesn't find node addresses, so no IO is needed. All + * we need to know is the capacity of indirect blocks (taken from the + * inode->i_sb). + */ + +/* + * Portability note: the last comparison (check that we fit into triple + * indirect block) is spelled differently, because otherwise on an + * architecture with 32-bit longs and 8Kb pages we might get into trouble + * if our filesystem had 8Kb blocks. We might use long long, but that would + * kill us on x86. Oh, well, at least the sign propagation does not matter - + * i_block would have to be negative in the very beginning, so we would not + * get there at all. + */ + +static int ext3_block_to_path(struct inode *inode, long i_block, int offsets[4]) +{ + int ptrs = EXT3_ADDR_PER_BLOCK(inode->i_sb); + int ptrs_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb); + const long direct_blocks = EXT3_NDIR_BLOCKS, + indirect_blocks = ptrs, + double_blocks = (1 << (ptrs_bits * 2)); + int n = 0; + + if (i_block < 0) { + ext3_warning (inode->i_sb, "ext3_block_to_path", "block < 0"); + } else if (i_block < direct_blocks) { + offsets[n++] = i_block; + } else if ( (i_block -= direct_blocks) < indirect_blocks) { + offsets[n++] = EXT3_IND_BLOCK; + offsets[n++] = i_block; + } else if ((i_block -= indirect_blocks) < double_blocks) { + offsets[n++] = EXT3_DIND_BLOCK; + offsets[n++] = i_block >> ptrs_bits; + offsets[n++] = i_block & (ptrs - 1); + } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { + offsets[n++] = EXT3_TIND_BLOCK; + offsets[n++] = i_block >> (ptrs_bits * 2); + offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); + offsets[n++] = i_block & (ptrs - 1); + } else { + ext3_warning (inode->i_sb, "ext3_block_to_path", "block > big"); + } + return n; +} + +/** + * ext3_get_branch - read the chain of indirect blocks leading to data + * @inode: inode in question + * @depth: depth of the chain (1 - direct pointer, etc.) + * @offsets: offsets of pointers in inode/indirect blocks + * @chain: place to store the result + * @err: here we store the error value + * + * Function fills the array of triples <key, p, bh> and returns %NULL + * if everything went OK or the pointer to the last filled triple + * (incomplete one) otherwise. Upon the return chain[i].key contains + * the number of (i+1)-th block in the chain (as it is stored in memory, + * i.e. little-endian 32-bit), chain[i].p contains the address of that + * number (it points into struct inode for i==0 and into the bh->b_data + * for i>0) and chain[i].bh points to the buffer_head of i-th indirect + * block for i>0 and NULL for i==0. In other words, it holds the block + * numbers of the chain, addresses they were taken from (and where we can + * verify that chain did not change) and buffer_heads hosting these + * numbers. + * + * Function stops when it stumbles upon zero pointer (absent block) + * (pointer to last triple returned, *@err == 0) + * or when it gets an IO error reading an indirect block + * (ditto, *@err == -EIO) + * or when it notices that chain had been changed while it was reading + * (ditto, *@err == -EAGAIN) + * or when it reads all @depth-1 indirect blocks successfully and finds + * the whole chain, all way to the data (returns %NULL, *err == 0). + */ +static Indirect *ext3_get_branch(struct inode *inode, int depth, int *offsets, + Indirect chain[4], int *err) +{ + kdev_t dev = inode->i_dev; + int blocksize = inode->i_sb->s_blocksize; + Indirect *p = chain; + struct buffer_head *bh; + + *err = 0; + /* i_data is not going away, no lock needed */ + add_chain (chain, NULL, inode->u.ext3_i.i_data + *offsets); + if (!p->key) + goto no_block; + while (--depth) { + bh = bread(dev, le32_to_cpu(p->key), blocksize); + if (!bh) + goto failure; + /* Reader: pointers */ + if (!verify_chain(chain, p)) + goto changed; + add_chain(++p, bh, (u32*)bh->b_data + *++offsets); + /* Reader: end */ + if (!p->key) + goto no_block; + } + return NULL; + +changed: + *err = -EAGAIN; + goto no_block; +failure: + *err = -EIO; +no_block: + return p; +} + +/** + * ext3_find_near - find a place for allocation with sufficient locality + * @inode: owner + * @ind: descriptor of indirect block. + * + * This function returns the prefered place for block allocation. + * It is used when heuristic for sequential allocation fails. + * Rules are: + * + if there is a block to the left of our position - allocate near it. + * + if pointer will live in indirect block - allocate near that block. + * + if pointer will live in inode - allocate in the same + * cylinder group. + * Caller must make sure that @ind is valid and will stay that way. + */ + +static inline unsigned long ext3_find_near(struct inode *inode, Indirect *ind) +{ + u32 *start = ind->bh ? (u32*) ind->bh->b_data : inode->u.ext3_i.i_data; + u32 *p; + + /* Try to find previous block */ + for (p = ind->p - 1; p >= start; p--) + if (*p) + return le32_to_cpu(*p); + + /* No such thing, so let's try location of indirect block */ + if (ind->bh) + return ind->bh->b_blocknr; + + /* + * It is going to be refered from inode itself? OK, just put it into + * the same cylinder group then. + */ + return (inode->u.ext3_i.i_block_group * + EXT3_BLOCKS_PER_GROUP(inode->i_sb)) + + le32_to_cpu(inode->i_sb->u.ext3_sb.s_es->s_first_data_block); +} + +/** + * ext3_find_goal - find a prefered place for allocation. + * @inode: owner + * @block: block we want + * @chain: chain of indirect blocks + * @partial: pointer to the last triple within a chain + * @goal: place to store the result. + * + * Normally this function find the prefered place for block allocation, + * stores it in *@goal and returns zero. If the branch had been changed + * under us we return -EAGAIN. + */ + +static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4], + Indirect *partial, unsigned long *goal) +{ + /* Writer: ->i_next_alloc* */ + if (block == inode->u.ext3_i.i_next_alloc_block + 1) { + inode->u.ext3_i.i_next_alloc_block++; + inode->u.ext3_i.i_next_alloc_goal++; + } +#ifdef SEARCH_FROM_ZERO + inode->u.ext3_i.i_next_alloc_block = 0; + inode->u.ext3_i.i_next_alloc_goal = 0; +#endif + /* Writer: end */ + /* Reader: pointers, ->i_next_alloc* */ + if (verify_chain(chain, partial)) { + /* + * try the heuristic for sequential allocation, + * failing that at least try to get decent locality. + */ + if (block == inode->u.ext3_i.i_next_alloc_block) + *goal = inode->u.ext3_i.i_next_alloc_goal; + if (!*goal) + *goal = ext3_find_near(inode, partial); +#ifdef SEARCH_FROM_ZERO + *goal = 0; +#endif + return 0; + } + /* Reader: end */ + return -EAGAIN; +} + +/** + * ext3_alloc_branch - allocate and set up a chain of blocks. + * @inode: owner + * @num: depth of the chain (number of blocks to allocate) + * @offsets: offsets (in the blocks) to store the pointers to next. + * @branch: place to store the chain in. + * + * This function allocates @num blocks, zeroes out all but the last one, + * links them into chain and (if we are synchronous) writes them to disk. + * In other words, it prepares a branch that can be spliced onto the + * inode. It stores the information about that chain in the branch[], in + * the same format as ext3_get_branch() would do. We are calling it after + * we had read the existing part of chain and partial points to the last + * triple of that (one with zero ->key). Upon the exit we have the same + * picture as after the successful ext3_get_block(), excpet that in one + * place chain is disconnected - *branch->p is still zero (we did not + * set the last link), but branch->key contains the number that should + * be placed into *branch->p to fill that gap. + * + * If allocation fails we free all blocks we've allocated (and forget + * their buffer_heads) and return the error value the from failed + * ext3_alloc_block() (normally -ENOSPC). Otherwise we set the chain + * as described above and return 0. + */ + +static int ext3_alloc_branch(handle_t *handle, struct inode *inode, + int num, + unsigned long goal, + int *offsets, + Indirect *branch) +{ + int blocksize = inode->i_sb->s_blocksize; + int n = 0, keys = 0; + int err = 0; + int i; + int parent = ext3_alloc_block(handle, inode, goal, &err); + + branch[0].key = cpu_to_le32(parent); + if (parent) { + for (n = 1; n < num; n++) { + struct buffer_head *bh; + /* Allocate the next block */ + int nr = ext3_alloc_block(handle, inode, parent, &err); + if (!nr) + break; + branch[n].key = cpu_to_le32(nr); + keys = n+1; + + /* + * Get buffer_head for parent block, zero it out + * and set the pointer to new one, then send + * parent to disk. + */ + bh = getblk(inode->i_dev, parent, blocksize); + branch[n].bh = bh; + lock_buffer(bh); + BUFFER_TRACE(bh, "call get_create_access"); + err = ext3_journal_get_create_access(handle, bh); + if (err) { + unlock_buffer(bh); + brelse(bh); + break; + } + + memset(bh->b_data, 0, blocksize); + branch[n].p = (u32*) bh->b_data + offsets[n]; + *branch[n].p = branch[n].key; + BUFFER_TRACE(bh, "marking uptodate"); + mark_buffer_uptodate(bh, 1); + unlock_buffer(bh); + + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh); + if (err) + break; + + parent = nr; + } + if (IS_SYNC(inode)) + handle->h_sync = 1; + } + if (n == num) + return 0; + + /* Allocation failed, free what we already allocated */ + for (i = 1; i < keys; i++) { + BUFFER_TRACE(branch[i].bh, "call journal_forget"); + ext3_journal_forget(handle, branch[i].bh); + } + for (i = 0; i < keys; i++) + ext3_free_blocks(handle, inode, le32_to_cpu(branch[i].key), 1); + return err; +} + +/** + * ext3_splice_branch - splice the allocated branch onto inode. + * @inode: owner + * @block: (logical) number of block we are adding + * @chain: chain of indirect blocks (with a missing link - see + * ext3_alloc_branch) + * @where: location of missing link + * @num: number of blocks we are adding + * + * This function verifies that chain (up to the missing link) had not + * changed, fills the missing link and does all housekeeping needed in + * inode (->i_blocks, etc.). In case of success we end up with the full + * chain to new block and return 0. Otherwise (== chain had been changed) + * we free the new blocks (forgetting their buffer_heads, indeed) and + * return -EAGAIN. + */ + +static int ext3_splice_branch(handle_t *handle, struct inode *inode, long block, + Indirect chain[4], Indirect *where, int num) +{ + int i; + int err = 0; + + /* + * If we're splicing into a [td]indirect block (as opposed to the + * inode) then we need to get write access to the [td]indirect block + * before the splice. + */ + if (where->bh) { + BUFFER_TRACE(where->bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, where->bh); + if (err) + goto err_out; + } + /* Verify that place we are splicing to is still there and vacant */ + + /* Writer: pointers, ->i_next_alloc* */ + if (!verify_chain(chain, where-1) || *where->p) + /* Writer: end */ + goto changed; + + /* That's it */ + + *where->p = where->key; + inode->u.ext3_i.i_next_alloc_block = block; + inode->u.ext3_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key); +#ifdef SEARCH_FROM_ZERO + inode->u.ext3_i.i_next_alloc_block = 0; + inode->u.ext3_i.i_next_alloc_goal = 0; +#endif + /* Writer: end */ + + /* We are done with atomic stuff, now do the rest of housekeeping */ + + inode->i_ctime = CURRENT_TIME; + ext3_mark_inode_dirty(handle, inode); + + /* had we spliced it onto indirect block? */ + if (where->bh) { + /* + * akpm: If we spliced it onto an indirect block, we haven't + * altered the inode. Note however that if it is being spliced + * onto an indirect block at the very end of the file (the + * file is growing) then we *will* alter the inode to reflect + * the new i_size. But that is not done here - it is done in + * generic_commit_write->__mark_inode_dirty->ext3_dirty_inode. + */ + jbd_debug(5, "splicing indirect only\n"); + BUFFER_TRACE(where->bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, where->bh); + if (err) + goto err_out; + } else { + /* + * OK, we spliced it into the inode itself on a direct block. + * Inode was dirtied above. + */ + jbd_debug(5, "splicing direct\n"); + } + return err; + +changed: + /* + * AKPM: if where[i].bh isn't part of the current updating + * transaction then we explode nastily. Test this code path. + */ + jbd_debug(1, "the chain changed: try again\n"); + err = -EAGAIN; + +err_out: + for (i = 1; i < num; i++) { + BUFFER_TRACE(where[i].bh, "call journal_forget"); + ext3_journal_forget(handle, where[i].bh); + } + /* For the normal collision cleanup case, we free up the blocks. + * On genuine filesystem errors we don't even think about doing + * that. */ + if (err == -EAGAIN) + for (i = 0; i < num; i++) + ext3_free_blocks(handle, inode, + le32_to_cpu(where[i].key), 1); + return err; +} + +/* + * Allocation strategy is simple: if we have to allocate something, we will + * have to go the whole way to leaf. So let's do it before attaching anything + * to tree, set linkage between the newborn blocks, write them if sync is + * required, recheck the path, free and repeat if check fails, otherwise + * set the last missing link (that will protect us from any truncate-generated + * removals - all blocks on the path are immune now) and possibly force the + * write on the parent block. + * That has a nice additional property: no special recovery from the failed + * allocations is needed - we simply release blocks and do not touch anything + * reachable from inode. + * + * akpm: `handle' can be NULL if create == 0. + */ + +static int ext3_get_block_handle(handle_t *handle, struct inode *inode, + long iblock, + struct buffer_head *bh_result, int create) +{ + int err = -EIO; + int offsets[4]; + Indirect chain[4]; + Indirect *partial; + unsigned long goal; + int left; + int depth = ext3_block_to_path(inode, iblock, offsets); + loff_t new_size; + + J_ASSERT(handle != NULL || create == 0); + + if (depth == 0) + goto out; + + lock_kernel(); +reread: + partial = ext3_get_branch(inode, depth, offsets, chain, &err); + + /* Simplest case - block found, no allocation needed */ + if (!partial) { + bh_result->b_state &= ~(1UL << BH_New); +got_it: + bh_result->b_dev = inode->i_dev; + bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key); + bh_result->b_state |= (1UL << BH_Mapped); + /* Clean up and exit */ + partial = chain+depth-1; /* the whole chain */ + goto cleanup; + } + + /* Next simple case - plain lookup or failed read of indirect block */ + if (!create || err == -EIO) { +cleanup: + while (partial > chain) { + BUFFER_TRACE(partial->bh, "call brelse"); + brelse(partial->bh); + partial--; + } + BUFFER_TRACE(bh_result, "returned"); + unlock_kernel(); +out: + return err; + } + + /* + * Indirect block might be removed by truncate while we were + * reading it. Handling of that case (forget what we've got and + * reread) is taken out of the main path. + */ + if (err == -EAGAIN) + goto changed; + + if (ext3_find_goal(inode, iblock, chain, partial, &goal) < 0) + goto changed; + + left = (chain + depth) - partial; + + /* + * Block out ext3_truncate while we alter the tree + */ + down_read(&inode->u.ext3_i.truncate_sem); + err = ext3_alloc_branch(handle, inode, left, goal, + offsets+(partial-chain), partial); + + /* The ext3_splice_branch call will free and forget any buffers + * on the new chain if there is a failure, but that risks using + * up transaction credits, especially for bitmaps where the + * credits cannot be returned. Can we handle this somehow? We + * may need to return -EAGAIN upwards in the worst case. --sct */ + if (!err) + err = ext3_splice_branch(handle, inode, iblock, chain, + partial, left); + up_read(&inode->u.ext3_i.truncate_sem); + if (err == -EAGAIN) + goto changed; + if (err) + goto cleanup; + + new_size = inode->i_size; + /* + * This is not racy against ext3_truncate's modification of i_disksize + * because VM/VFS ensures that the file cannot be extended while + * truncate is in progress. It is racy between multiple parallel + * instances of get_block, but we have the BKL. + */ + if (new_size > inode->u.ext3_i.i_disksize) + inode->u.ext3_i.i_disksize = new_size; + + bh_result->b_state |= (1UL << BH_New); + goto got_it; + +changed: + while (partial > chain) { + jbd_debug(1, "buffer chain changed, retrying\n"); + BUFFER_TRACE(partial->bh, "brelsing"); + brelse(partial->bh); + partial--; + } + goto reread; +} + +static int ext3_get_block(struct inode *inode, long iblock, + struct buffer_head *bh_result, int create) +{ + handle_t *handle = 0; + int ret; + + if (create) { + handle = ext3_journal_current_handle(); + J_ASSERT(handle != 0); + } + ret = ext3_get_block_handle(handle, inode, iblock, bh_result, create); + return ret; +} + +/* + * `handle' can be NULL if create is zero + */ +struct buffer_head *ext3_getblk(handle_t *handle, struct inode * inode, + long block, int create, int * errp) +{ + struct buffer_head dummy; + int fatal = 0, err; + + J_ASSERT(handle != NULL || create == 0); + + dummy.b_state = 0; + dummy.b_blocknr = -1000; + buffer_trace_init(&dummy.b_history); + *errp = ext3_get_block_handle(handle, inode, block, &dummy, create); + if (!*errp && buffer_mapped(&dummy)) { + struct buffer_head *bh; + bh = getblk(dummy.b_dev, dummy.b_blocknr, + inode->i_sb->s_blocksize); + if (buffer_new(&dummy)) { + J_ASSERT(create != 0); + J_ASSERT(handle != 0); + + /* Now that we do not always journal data, we + should keep in mind whether this should + always journal the new buffer as metadata. + For now, regular file writes use + ext3_get_block instead, so it's not a + problem. */ + lock_kernel(); + lock_buffer(bh); + BUFFER_TRACE(bh, "call get_create_access"); + fatal = ext3_journal_get_create_access(handle, bh); + if (!fatal) { + memset(bh->b_data, 0, + inode->i_sb->s_blocksize); + mark_buffer_uptodate(bh, 1); + } + unlock_buffer(bh); + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, bh); + if (!fatal) fatal = err; + unlock_kernel(); + } else { + BUFFER_TRACE(bh, "not a new buffer"); + } + if (fatal) { + *errp = fatal; + brelse(bh); + bh = NULL; + } + return bh; + } + return NULL; +} + +struct buffer_head *ext3_bread(handle_t *handle, struct inode * inode, + int block, int create, int *err) +{ + struct buffer_head * bh; + int prev_blocks; + + prev_blocks = inode->i_blocks; + + bh = ext3_getblk (handle, inode, block, create, err); + if (!bh) + return bh; +#ifdef EXT3_PREALLOCATE + /* + * If the inode has grown, and this is a directory, then use a few + * more of the preallocated blocks to keep directory fragmentation + * down. The preallocated blocks are guaranteed to be contiguous. + */ + if (create && + S_ISDIR(inode->i_mode) && + inode->i_blocks > prev_blocks && + EXT3_HAS_COMPAT_FEATURE(inode->i_sb, + EXT3_FEATURE_COMPAT_DIR_PREALLOC)) { + int i; + struct buffer_head *tmp_bh; + + for (i = 1; + inode->u.ext3_i.i_prealloc_count && + i < EXT3_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks; + i++) { + /* + * ext3_getblk will zero out the contents of the + * directory for us + */ + tmp_bh = ext3_getblk(handle, inode, + block+i, create, err); + if (!tmp_bh) { + brelse (bh); + return 0; + } + brelse (tmp_bh); + } + } +#endif + if (buffer_uptodate(bh)) + return bh; + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (buffer_uptodate(bh)) + return bh; + brelse (bh); + *err = -EIO; + return NULL; +} + +static int walk_page_buffers( handle_t *handle, + struct buffer_head *head, + unsigned from, + unsigned to, + int *partial, + int (*fn)( handle_t *handle, + struct buffer_head *bh)) +{ + struct buffer_head *bh; + unsigned block_start, block_end; + unsigned blocksize = head->b_size; + int err, ret = 0; + + for ( bh = head, block_start = 0; + ret == 0 && (bh != head || !block_start); + block_start = block_end, bh = bh->b_this_page) + { + block_end = block_start + blocksize; + if (block_end <= from || block_start >= to) { + if (partial && !buffer_uptodate(bh)) + *partial = 1; + continue; + } + err = (*fn)(handle, bh); + if (!ret) + ret = err; + } + return ret; +} + +/* + * To preserve ordering, it is essential that the hole instantiation and + * the data write be encapsulated in a single transaction. We cannot + * close off a transaction and start a new one between the ext3_get_block() + * and the commit_write(). So doing the journal_start at the start of + * prepare_write() is the right place. + * + * Also, this function can nest inside ext3_writepage() -> + * block_write_full_page(). In that case, we *know* that ext3_writepage() + * has generated enough buffer credits to do the whole page. So we won't + * block on the journal in that case, which is good, because the caller may + * be PF_MEMALLOC. + * + * By accident, ext3 can be reentered when a transaction is open via + * quota file writes. If we were to commit the transaction while thus + * reentered, there can be a deadlock - we would be holding a quota + * lock, and the commit would never complete if another thread had a + * transaction open and was blocking on the quota lock - a ranking + * violation. + * + * So what we do is to rely on the fact that journal_stop/journal_start + * will _not_ run commit under these circumstances because handle->h_ref + * is elevated. We'll still have enough credits for the tiny quotafile + * write. + */ + +static int do_journal_get_write_access(handle_t *handle, + struct buffer_head *bh) +{ + return ext3_journal_get_write_access(handle, bh); +} + +static int ext3_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct inode *inode = page->mapping->host; + handle_t *handle = ext3_journal_current_handle(); + int ret, needed_blocks = ext3_writepage_trans_blocks(inode); + + lock_kernel(); + handle = ext3_journal_start(inode, needed_blocks); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } + ret = block_prepare_write(page, from, to, ext3_get_block); + if (ret != 0) + goto prepare_write_failed; + + if (ext3_should_journal_data(inode)) + ret = walk_page_buffers(handle, page->buffers, + from, to, NULL, do_journal_get_write_access); +prepare_write_failed: + if (ret) + ext3_journal_stop(handle, inode); +out: + unlock_kernel(); + return ret; +} + +static int journal_dirty_sync_data(handle_t *handle, struct buffer_head *bh) +{ + return ext3_journal_dirty_data(handle, bh, 0); +} + +/* + * For ext3_writepage(). We also brelse() the buffer to account for + * the bget() which ext3_writepage() performs. + */ +static int journal_dirty_async_data(handle_t *handle, struct buffer_head *bh) +{ + int ret = ext3_journal_dirty_data(handle, bh, 1); + __brelse(bh); + return ret; +} + +/* For commit_write() in data=journal mode */ +static int commit_write_fn(handle_t *handle, struct buffer_head *bh) +{ + set_bit(BH_Uptodate, &bh->b_state); + return ext3_journal_dirty_metadata(handle, bh); +} + +/* + * We need to pick up the new inode size which generic_commit_write gave us + * `file' can be NULL - eg, when called from block_symlink(). + * + * ext3 inode->i_dirty_buffers policy: If we're journalling data we + * definitely don't want them to appear on the inode at all - instead + * we need to manage them at the JBD layer and we need to intercept + * the relevant sync operations and translate them into journal operations. + * + * If we're not journalling data then we can just leave the buffers + * on ->i_dirty_buffers. If someone writes them out for us then thanks. + * Otherwise we'll do it in commit, if we're using ordered data. + */ + +static int ext3_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + handle_t *handle = ext3_journal_current_handle(); + struct inode *inode = page->mapping->host; + int ret = 0, ret2; + + lock_kernel(); + if (ext3_should_journal_data(inode)) { + /* + * Here we duplicate the generic_commit_write() functionality + */ + int partial = 0; + loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + + ret = walk_page_buffers(handle, page->buffers, + from, to, &partial, commit_write_fn); + if (!partial) + SetPageUptodate(page); + kunmap(page); + if (pos > inode->i_size) + inode->i_size = pos; + set_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state); + } else { + if (ext3_should_order_data(inode)) { + ret = walk_page_buffers(handle, page->buffers, + from, to, NULL, journal_dirty_sync_data); + } + /* Be careful here if generic_commit_write becomes a + * required invocation after block_prepare_write. */ + if (ret == 0) + ret = generic_commit_write(file, page, from, to); + } + if (inode->i_size > inode->u.ext3_i.i_disksize) { + inode->u.ext3_i.i_disksize = inode->i_size; + ret2 = ext3_mark_inode_dirty(handle, inode); + if (!ret) + ret = ret2; + } + ret2 = ext3_journal_stop(handle, inode); + unlock_kernel(); + if (!ret) + ret = ret2; + return ret; +} + +/* + * bmap() is special. It gets used by applications such as lilo and by + * the swapper to find the on-disk block of a specific piece of data. + * + * Naturally, this is dangerous if the block concerned is still in the + * journal. If somebody makes a swapfile on an ext3 data-journaling + * filesystem and enables swap, then they may get a nasty shock when the + * data getting swapped to that swapfile suddenly gets overwritten by + * the original zero's written out previously to the journal and + * awaiting writeback in the kernel's buffer cache. + * + * So, if we see any bmap calls here on a modified, data-journaled file, + * take extra steps to flush any blocks which might be in the cache. + */ +static int ext3_bmap(struct address_space *mapping, long block) +{ + struct inode *inode = mapping->host; + journal_t *journal; + int err; + + if (test_and_clear_bit(EXT3_STATE_JDATA, &inode->u.ext3_i.i_state)) { + /* + * This is a REALLY heavyweight approach, but the use of + * bmap on dirty files is expected to be extremely rare: + * only if we run lilo or swapon on a freshly made file + * do we expect this to happen. + * + * (bmap requires CAP_SYS_RAWIO so this does not + * represent an unprivileged user DOS attack --- we'd be + * in trouble if mortal users could trigger this path at + * will.) + * + * NB. EXT3_STATE_JDATA is not set on files other than + * regular files. If somebody wants to bmap a directory + * or symlink and gets confused because the buffer + * hasn't yet been flushed to disk, they deserve + * everything they get. + */ + + journal = EXT3_JOURNAL(inode); + journal_lock_updates(journal); + err = journal_flush(journal); + journal_unlock_updates(journal); + + if (err) + return 0; + } + + return generic_block_bmap(mapping,block,ext3_get_block); +} + +static int bget_one(handle_t *handle, struct buffer_head *bh) +{ + atomic_inc(&bh->b_count); + return 0; +} + +/* + * Note that we always start a transaction even if we're not journalling + * data. This is to preserve ordering: any hole instantiation within + * __block_write_full_page -> ext3_get_block() should be journalled + * along with the data so we don't crash and then get metadata which + * refers to old data. + * + * In all journalling modes block_write_full_page() will start the I/O. + * + * Problem: + * + * ext3_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() -> + * ext3_writepage() + * + * Similar for: + * + * ext3_file_write() -> generic_file_write() -> __alloc_pages() -> ... + * + * Same applies to ext3_get_block(). We will deadlock on various things like + * lock_journal and i_truncate_sem. + * + * Setting PF_MEMALLOC here doesn't work - too many internal memory + * allocations fail. + * + * 16May01: If we're reentered then journal_current_handle() will be + * non-zero. We simply *return*. + * + * 1 July 2001: @@@ FIXME: + * In journalled data mode, a data buffer may be metadata against the + * current transaction. But the same file is part of a shared mapping + * and someone does a writepage() on it. + * + * We will move the buffer onto the async_data list, but *after* it has + * been dirtied. So there's a small window where we have dirty data on + * BJ_Metadata. + * + * Note that this only applies to the last partial page in the file. The + * bit which block_write_full_page() uses prepare/commit for. (That's + * broken code anyway: it's wrong for msync()). + * + * It's a rare case: affects the final partial page, for journalled data + * where the file is subject to bith write() and writepage() in the same + * transction. To fix it we'll need a custom block_write_full_page(). + * We'll probably need that anyway for journalling writepage() output. + * + * We don't honour synchronous mounts for writepage(). That would be + * disastrous. Any write() or metadata operation will sync the fs for + * us. + */ +static int ext3_writepage(struct page *page) +{ + struct inode *inode = page->mapping->host; + struct buffer_head *page_buffers; + handle_t *handle = NULL; + int ret = 0, err; + int needed; + int order_data; + + J_ASSERT(PageLocked(page)); + + /* + * We give up here if we're reentered, because it might be + * for a different filesystem. One *could* look for a + * nested transaction opportunity. + */ + lock_kernel(); + if (ext3_journal_current_handle()) + goto out_fail; + + needed = ext3_writepage_trans_blocks(inode); + if (current->flags & PF_MEMALLOC) + handle = ext3_journal_try_start(inode, needed); + else + handle = ext3_journal_start(inode, needed); + + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out_fail; + } + + order_data = ext3_should_order_data(inode) || + ext3_should_journal_data(inode); + + unlock_kernel(); + + page_buffers = NULL; /* Purely to prevent compiler warning */ + + /* bget() all the buffers */ + if (order_data) { + if (!page->buffers) + create_empty_buffers(page, + inode->i_dev, inode->i_sb->s_blocksize); + page_buffers = page->buffers; + walk_page_buffers(handle, page_buffers, 0, + PAGE_CACHE_SIZE, NULL, bget_one); + } + + ret = block_write_full_page(page, ext3_get_block); + + /* + * The page can become unlocked at any point now, and + * truncate can then come in and change things. So we + * can't touch *page from now on. But *page_buffers is + * safe due to elevated refcount. + */ + + handle = ext3_journal_current_handle(); + lock_kernel(); + + /* And attach them to the current transaction */ + if (order_data) { + err = walk_page_buffers(handle, page_buffers, + 0, PAGE_CACHE_SIZE, NULL, journal_dirty_async_data); + if (!ret) + ret = err; + } + + err = ext3_journal_stop(handle, inode); + if (!ret) + ret = err; + unlock_kernel(); + return ret; + +out_fail: + + unlock_kernel(); + SetPageDirty(page); + UnlockPage(page); + return ret; +} + +static int ext3_readpage(struct file *file, struct page *page) +{ + return block_read_full_page(page,ext3_get_block); +} + + +static int ext3_flushpage(struct page *page, unsigned long offset) +{ + journal_t *journal = EXT3_JOURNAL(page->mapping->host); + return journal_flushpage(journal, page, offset); +} + +static int ext3_releasepage(struct page *page, int wait) +{ + journal_t *journal = EXT3_JOURNAL(page->mapping->host); + return journal_try_to_free_buffers(journal, page, wait); +} + + +struct address_space_operations ext3_aops = { + readpage: ext3_readpage, /* BKL not held. Don't need */ + writepage: ext3_writepage, /* BKL not held. We take it */ + sync_page: block_sync_page, + prepare_write: ext3_prepare_write, /* BKL not held. We take it */ + commit_write: ext3_commit_write, /* BKL not held. We take it */ + bmap: ext3_bmap, /* BKL held */ + flushpage: ext3_flushpage, /* BKL not held. Don't need */ + releasepage: ext3_releasepage, /* BKL not held. Don't need */ +}; + +/* + * ext3_block_truncate_page() zeroes out a mapping from file offset `from' + * up to the end of the block which corresponds to `from'. + * This required during truncate. We need to physically zero the tail end + * of that block so it doesn't yield old data if the file is later grown. + */ +static int ext3_block_truncate_page(handle_t *handle, + struct address_space *mapping, loff_t from) +{ + unsigned long index = from >> PAGE_CACHE_SHIFT; + unsigned offset = from & (PAGE_CACHE_SIZE-1); + unsigned blocksize, iblock, length, pos; + struct inode *inode = mapping->host; + struct page *page; + struct buffer_head *bh; + int err; + + blocksize = inode->i_sb->s_blocksize; + length = offset & (blocksize - 1); + + /* Block boundary? Nothing to do */ + if (!length) + return 0; + + length = blocksize - length; + iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); + + page = grab_cache_page(mapping, index); + err = -ENOMEM; + if (!page) + goto out; + + if (!page->buffers) + create_empty_buffers(page, inode->i_dev, blocksize); + + /* Find the buffer that contains "offset" */ + bh = page->buffers; + pos = blocksize; + while (offset >= pos) { + bh = bh->b_this_page; + iblock++; + pos += blocksize; + } + + err = 0; + if (!buffer_mapped(bh)) { + /* Hole? Nothing to do */ + if (buffer_uptodate(bh)) + goto unlock; + ext3_get_block(inode, iblock, bh, 0); + /* Still unmapped? Nothing to do */ + if (!buffer_mapped(bh)) + goto unlock; + } + + /* Ok, it's mapped. Make sure it's up-to-date */ + if (Page_Uptodate(page)) + set_bit(BH_Uptodate, &bh->b_state); + + if (!buffer_uptodate(bh)) { + err = -EIO; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + /* Uhhuh. Read error. Complain and punt. */ + if (!buffer_uptodate(bh)) + goto unlock; + } + + if (ext3_should_journal_data(inode)) { + BUFFER_TRACE(bh, "get write access"); + err = ext3_journal_get_write_access(handle, bh); + if (err) + goto unlock; + } + + memset(kmap(page) + offset, 0, length); + flush_dcache_page(page); + kunmap(page); + + BUFFER_TRACE(bh, "zeroed end of block"); + + err = 0; + if (ext3_should_journal_data(inode)) { + err = ext3_journal_dirty_metadata(handle, bh); + } else { + if (ext3_should_order_data(inode)) + err = ext3_journal_dirty_data(handle, bh, 0); + __mark_buffer_dirty(bh); + } + +unlock: + UnlockPage(page); + page_cache_release(page); +out: + return err; +} + +/* + * Probably it should be a library function... search for first non-zero word + * or memcmp with zero_page, whatever is better for particular architecture. + * Linus? + */ +static inline int all_zeroes(u32 *p, u32 *q) +{ + while (p < q) + if (*p++) + return 0; + return 1; +} + +/** + * ext3_find_shared - find the indirect blocks for partial truncation. + * @inode: inode in question + * @depth: depth of the affected branch + * @offsets: offsets of pointers in that branch (see ext3_block_to_path) + * @chain: place to store the pointers to partial indirect blocks + * @top: place to the (detached) top of branch + * + * This is a helper function used by ext3_truncate(). + * + * When we do truncate() we may have to clean the ends of several + * indirect blocks but leave the blocks themselves alive. Block is + * partially truncated if some data below the new i_size is refered + * from it (and it is on the path to the first completely truncated + * data block, indeed). We have to free the top of that path along + * with everything to the right of the path. Since no allocation + * past the truncation point is possible until ext3_truncate() + * finishes, we may safely do the latter, but top of branch may + * require special attention - pageout below the truncation point + * might try to populate it. + * + * We atomically detach the top of branch from the tree, store the + * block number of its root in *@top, pointers to buffer_heads of + * partially truncated blocks - in @chain[].bh and pointers to + * their last elements that should not be removed - in + * @chain[].p. Return value is the pointer to last filled element + * of @chain. + * + * The work left to caller to do the actual freeing of subtrees: + * a) free the subtree starting from *@top + * b) free the subtrees whose roots are stored in + * (@chain[i].p+1 .. end of @chain[i].bh->b_data) + * c) free the subtrees growing from the inode past the @chain[0]. + * (no partially truncated stuff there). */ + +static Indirect *ext3_find_shared(struct inode *inode, + int depth, + int offsets[4], + Indirect chain[4], + u32 *top) +{ + Indirect *partial, *p; + int k, err; + + *top = 0; + /* Make k index the deepest non-null offest + 1 */ + for (k = depth; k > 1 && !offsets[k-1]; k--) + ; + partial = ext3_get_branch(inode, k, offsets, chain, &err); + /* Writer: pointers */ + if (!partial) + partial = chain + k-1; + /* + * If the branch acquired continuation since we've looked at it - + * fine, it should all survive and (new) top doesn't belong to us. + */ + if (!partial->key && *partial->p) + /* Writer: end */ + goto no_top; + for (p=partial; p>chain && all_zeroes((u32*)p->bh->b_data,p->p); p--) + ; + /* + * OK, we've found the last block that must survive. The rest of our + * branch should be detached before unlocking. However, if that rest + * of branch is all ours and does not grow immediately from the inode + * it's easier to cheat and just decrement partial->p. + */ + if (p == chain + k - 1 && p > chain) { + p->p--; + } else { + *top = *p->p; + /* Nope, don't do this in ext3. Must leave the tree intact */ +#if 0 + *p->p = 0; +#endif + } + /* Writer: end */ + + while(partial > p) + { + brelse(partial->bh); + partial--; + } +no_top: + return partial; +} + +/* + * Zero a number of block pointers in either an inode or an indirect block. + * If we restart the transaction we must again get write access to the + * indirect block for further modification. + * + * We release `count' blocks on disk, but (last - first) may be greater + * than `count' because there can be holes in there. + */ +static void +ext3_clear_blocks(handle_t *handle, struct inode *inode, struct buffer_head *bh, + unsigned long block_to_free, unsigned long count, + u32 *first, u32 *last) +{ + u32 *p; + kdev_t dev = inode->i_sb->s_dev; + unsigned long blocksize = inode->i_sb->s_blocksize; + + if (try_to_extend_transaction(handle, inode)) { + if (bh) { + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, bh); + } + ext3_mark_inode_dirty(handle, inode); + ext3_journal_test_restart(handle, inode); + BUFFER_TRACE(bh, "get_write_access"); + ext3_journal_get_write_access(handle, bh); + } + + /* + * Any buffers which are on the journal will be in memory. We find + * them on the hash table so journal_revoke() will run journal_forget() + * on them. We've already detached each block from the file, so + * bforget() in journal_forget() should be safe. + * + * AKPM: turn on bforget in journal_forget()!!! + */ + for (p = first; p < last; p++) { + u32 nr = le32_to_cpu(*p); + if (nr) { + struct buffer_head *bh; + + *p = 0; + bh = get_hash_table(dev, nr, blocksize); + ext3_forget(handle, 0, inode, bh, nr); + } + } + + ext3_free_blocks(handle, inode, block_to_free, count); +} + +/** + * ext3_free_data - free a list of data blocks + * @handle: handle for this transaction + * @inode: inode we are dealing with + * @this_bh: indirect buffer_head which contains *@first and *@last + * @first: array of block numbers + * @last: points immediately past the end of array + * + * We are freeing all blocks refered from that array (numbers are stored as + * little-endian 32-bit) and updating @inode->i_blocks appropriately. + * + * We accumulate contiguous runs of blocks to free. Conveniently, if these + * blocks are contiguous then releasing them at one time will only affect one + * or two bitmap blocks (+ group descriptor(s) and superblock) and we won't + * actually use a lot of journal space. + * + * @this_bh will be %NULL if @first and @last point into the inode's direct + * block pointers. + */ +static void ext3_free_data(handle_t *handle, struct inode *inode, + struct buffer_head *this_bh, u32 *first, u32 *last) +{ + unsigned long block_to_free = 0; /* Starting block # of a run */ + unsigned long count = 0; /* Number of blocks in the run */ + u32 *block_to_free_p = NULL; /* Pointer into inode/ind + corresponding to + block_to_free */ + unsigned long nr; /* Current block # */ + u32 *p; /* Pointer into inode/ind + for current block */ + int err; + + if (this_bh) { /* For indirect block */ + BUFFER_TRACE(this_bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, this_bh); + /* Important: if we can't update the indirect pointers + * to the blocks, we can't free them. */ + if (err) + return; + } + + for (p = first; p < last; p++) { + nr = le32_to_cpu(*p); + if (nr) { + /* accumulate blocks to free if they're contiguous */ + if (count == 0) { + block_to_free = nr; + block_to_free_p = p; + count = 1; + } else if (nr == block_to_free + count) { + count++; + } else { + ext3_clear_blocks(handle, inode, this_bh, + block_to_free, + count, block_to_free_p, p); + block_to_free = nr; + block_to_free_p = p; + count = 1; + } + } + } + + if (count > 0) + ext3_clear_blocks(handle, inode, this_bh, block_to_free, + count, block_to_free_p, p); + + if (this_bh) { + BUFFER_TRACE(this_bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, this_bh); + } +} + +/** + * ext3_free_branches - free an array of branches + * @handle: JBD handle for this transaction + * @inode: inode we are dealing with + * @parent_bh: the buffer_head which contains *@first and *@last + * @first: array of block numbers + * @last: pointer immediately past the end of array + * @depth: depth of the branches to free + * + * We are freeing all blocks refered from these branches (numbers are + * stored as little-endian 32-bit) and updating @inode->i_blocks + * appropriately. + */ +static void ext3_free_branches(handle_t *handle, struct inode *inode, + struct buffer_head *parent_bh, + u32 *first, u32 *last, int depth) +{ + unsigned long nr; + u32 *p; + + if (is_handle_aborted(handle)) + return; + + if (depth--) { + struct buffer_head *bh; + int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb); + p = last; + while (--p >= first) { + nr = le32_to_cpu(*p); + if (!nr) + continue; /* A hole */ + + /* Go read the buffer for the next level down */ + bh = bread(inode->i_dev, nr, inode->i_sb->s_blocksize); + + /* + * A read failure? Report error and clear slot + * (should be rare). + */ + if (!bh) { + ext3_error(inode->i_sb, "ext3_free_branches", + "Read failure, inode=%ld, block=%ld", + inode->i_ino, nr); + continue; + } + + /* This zaps the entire block. Bottom up. */ + BUFFER_TRACE(bh, "free child branches"); + ext3_free_branches(handle, inode, bh, (u32*)bh->b_data, + (u32*)bh->b_data + addr_per_block, + depth); + + /* + * We've probably journalled the indirect block several + * times during the truncate. But it's no longer + * needed and we now drop it from the transaction via + * journal_revoke(). + * + * That's easy if it's exclusively part of this + * transaction. But if it's part of the committing + * transaction then journal_forget() will simply + * brelse() it. That means that if the underlying + * block is reallocated in ext3_get_block(), + * unmap_underlying_metadata() will find this block + * and will try to get rid of it. damn, damn. + * + * If this block has already been committed to the + * journal, a revoke record will be written. And + * revoke records must be emitted *before* clearing + * this block's bit in the bitmaps. + */ + ext3_forget(handle, 1, inode, bh, bh->b_blocknr); + + /* + * Everything below this this pointer has been + * released. Now let this top-of-subtree go. + * + * We want the freeing of this indirect block to be + * atomic in the journal with the updating of the + * bitmap block which owns it. So make some room in + * the journal. + * + * We zero the parent pointer *after* freeing its + * pointee in the bitmaps, so if extend_transaction() + * for some reason fails to put the bitmap changes and + * the release into the same transaction, recovery + * will merely complain about releasing a free block, + * rather than leaking blocks. + */ + if (is_handle_aborted(handle)) + return; + if (try_to_extend_transaction(handle, inode)) { + ext3_mark_inode_dirty(handle, inode); + ext3_journal_test_restart(handle, inode); + } + + ext3_free_blocks(handle, inode, nr, 1); + + if (parent_bh) { + /* + * The block which we have just freed is + * pointed to by an indirect block: journal it + */ + BUFFER_TRACE(parent_bh, "get_write_access"); + if (!ext3_journal_get_write_access(handle, + parent_bh)){ + *p = 0; + BUFFER_TRACE(parent_bh, + "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, + parent_bh); + } + } + } + } else { + /* We have reached the bottom of the tree. */ + BUFFER_TRACE(parent_bh, "free data blocks"); + ext3_free_data(handle, inode, parent_bh, first, last); + } +} + +/* + * ext3_truncate() + * + * We block out ext3_get_block() block instantiations across the entire + * transaction, and VFS/VM ensures that ext3_truncate() cannot run + * simultaneously on behalf of the same inode. + * + * As we work through the truncate and commmit bits of it to the journal there + * is one core, guiding principle: the file's tree must always be consistent on + * disk. We must be able to restart the truncate after a crash. + * + * The file's tree may be transiently inconsistent in memory (although it + * probably isn't), but whenever we close off and commit a journal transaction, + * the contents of (the filesystem + the journal) must be consistent and + * restartable. It's pretty simple, really: bottom up, right to left (although + * left-to-right works OK too). + * + * Note that at recovery time, journal replay occurs *before* the restart of + * truncate against the orphan inode list. + * + * The committed inode has the new, desired i_size (which is the same as + * i_disksize in this case). After a crash, ext3_orphan_cleanup() will see + * that this inode's truncate did not complete and it will again call + * ext3_truncate() to have another go. So there will be instantiated blocks + * to the right of the truncation point in a crashed ext3 filesystem. But + * that's fine - as long as they are linked from the inode, the post-crash + * ext3_truncate() run will find them and release them. + */ + +void ext3_truncate(struct inode * inode) +{ + handle_t *handle; + u32 *i_data = inode->u.ext3_i.i_data; + int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb); + int offsets[4]; + Indirect chain[4]; + Indirect *partial; + int nr = 0; + int n; + long last_block; + unsigned blocksize; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + + ext3_discard_prealloc(inode); + + handle = start_transaction(inode); + if (IS_ERR(handle)) + return; /* AKPM: return what? */ + + blocksize = inode->i_sb->s_blocksize; + last_block = (inode->i_size + blocksize-1) + >> EXT3_BLOCK_SIZE_BITS(inode->i_sb); + + ext3_block_truncate_page(handle, inode->i_mapping, inode->i_size); + + + n = ext3_block_to_path(inode, last_block, offsets); + if (n == 0) + goto out_stop; /* error */ + + /* + * OK. This truncate is going to happen. We add the inode to the + * orphan list, so that if this truncate spans multiple transactions, + * and we crash, we will resume the truncate when the filesystem + * recovers. It also marks the inode dirty, to catch the new size. + * + * Implication: the file must always be in a sane, consistent + * truncatable state while each transaction commits. + */ + if (ext3_orphan_add(handle, inode)) + goto out_stop; + + /* + * The orphan list entry will now protect us from any crash which + * occurs before the truncate completes, so it is now safe to propagate + * the new, shorter inode size (held for now in i_size) into the + * on-disk inode. We do this via i_disksize, which is the value which + * ext3 *really* writes onto the disk inode. + */ + inode->u.ext3_i.i_disksize = inode->i_size; + + /* + * From here we block out all ext3_get_block() callers who want to + * modify the block allocation tree. + */ + down_write(&inode->u.ext3_i.truncate_sem); + + if (n == 1) { /* direct blocks */ + ext3_free_data(handle, inode, NULL, i_data+offsets[0], + i_data + EXT3_NDIR_BLOCKS); + goto do_indirects; + } + + partial = ext3_find_shared(inode, n, offsets, chain, &nr); + /* Kill the top of shared branch (not detached) */ + if (nr) { + if (partial == chain) { + /* Shared branch grows from the inode */ + ext3_free_branches(handle, inode, NULL, + &nr, &nr+1, (chain+n-1) - partial); + *partial->p = 0; + /* + * We mark the inode dirty prior to restart, + * and prior to stop. No need for it here. + */ + } else { + /* Shared branch grows from an indirect block */ + BUFFER_TRACE(partial->bh, "get_write_access"); + ext3_free_branches(handle, inode, partial->bh, + partial->p, + partial->p+1, (chain+n-1) - partial); + } + } + /* Clear the ends of indirect blocks on the shared branch */ + while (partial > chain) { + ext3_free_branches(handle, inode, partial->bh, partial->p + 1, + (u32*)partial->bh->b_data + addr_per_block, + (chain+n-1) - partial); + BUFFER_TRACE(partial->bh, "call brelse"); + brelse (partial->bh); + partial--; + } +do_indirects: + /* Kill the remaining (whole) subtrees */ + switch (offsets[0]) { + default: + nr = i_data[EXT3_IND_BLOCK]; + if (nr) { + ext3_free_branches(handle, inode, NULL, + &nr, &nr+1, 1); + i_data[EXT3_IND_BLOCK] = 0; + } + case EXT3_IND_BLOCK: + nr = i_data[EXT3_DIND_BLOCK]; + if (nr) { + ext3_free_branches(handle, inode, NULL, + &nr, &nr+1, 2); + i_data[EXT3_DIND_BLOCK] = 0; + } + case EXT3_DIND_BLOCK: + nr = i_data[EXT3_TIND_BLOCK]; + if (nr) { + ext3_free_branches(handle, inode, NULL, + &nr, &nr+1, 3); + i_data[EXT3_TIND_BLOCK] = 0; + } + case EXT3_TIND_BLOCK: + ; + } + up_write(&inode->u.ext3_i.truncate_sem); + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + ext3_mark_inode_dirty(handle, inode); + + /* In a multi-transaction truncate, we only make the final + * transaction synchronous */ + if (IS_SYNC(inode)) + handle->h_sync = 1; +out_stop: + /* + * If this was a simple ftruncate(), and the file will remain alive + * then we need to clear up the orphan record which we created above. + * However, if this was a real unlink then we were called by + * ext3_delete_inode(), and we allow that function to clean up the + * orphan info for us. + */ + if (inode->i_nlink) + ext3_orphan_del(handle, inode); + + ext3_journal_stop(handle, inode); +} + +/* + * ext3_get_inode_loc returns with an extra refcount against the + * inode's underlying buffer_head on success. + */ + +int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc) +{ + struct buffer_head *bh = 0; + unsigned long block; + unsigned long block_group; + unsigned long group_desc; + unsigned long desc; + unsigned long offset; + struct ext3_group_desc * gdp; + + if ((inode->i_ino != EXT3_ROOT_INO && + inode->i_ino != EXT3_ACL_IDX_INO && + inode->i_ino != EXT3_ACL_DATA_INO && + inode->i_ino != EXT3_JOURNAL_INO && + inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) || + inode->i_ino > le32_to_cpu( + inode->i_sb->u.ext3_sb.s_es->s_inodes_count)) { + ext3_error (inode->i_sb, "ext3_get_inode_loc", + "bad inode number: %lu", inode->i_ino); + goto bad_inode; + } + block_group = (inode->i_ino - 1) / EXT3_INODES_PER_GROUP(inode->i_sb); + if (block_group >= inode->i_sb->u.ext3_sb.s_groups_count) { + ext3_error (inode->i_sb, "ext3_get_inode_loc", + "group >= groups count"); + goto bad_inode; + } + group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(inode->i_sb); + desc = block_group & (EXT3_DESC_PER_BLOCK(inode->i_sb) - 1); + bh = inode->i_sb->u.ext3_sb.s_group_desc[group_desc]; + if (!bh) { + ext3_error (inode->i_sb, "ext3_get_inode_loc", + "Descriptor not loaded"); + goto bad_inode; + } + + gdp = (struct ext3_group_desc *) bh->b_data; + /* + * Figure out the offset within the block group inode table + */ + offset = ((inode->i_ino - 1) % EXT3_INODES_PER_GROUP(inode->i_sb)) * + EXT3_INODE_SIZE(inode->i_sb); + block = le32_to_cpu(gdp[desc].bg_inode_table) + + (offset >> EXT3_BLOCK_SIZE_BITS(inode->i_sb)); + if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) { + ext3_error (inode->i_sb, "ext3_get_inode_loc", + "unable to read inode block - " + "inode=%lu, block=%lu", inode->i_ino, block); + goto bad_inode; + } + offset &= (EXT3_BLOCK_SIZE(inode->i_sb) - 1); + + iloc->bh = bh; + iloc->raw_inode = (struct ext3_inode *) (bh->b_data + offset); + iloc->block_group = block_group; + + return 0; + + bad_inode: + return -EIO; +} + +void ext3_read_inode(struct inode * inode) +{ + struct ext3_iloc iloc; + struct ext3_inode *raw_inode; + struct buffer_head *bh; + int block; + + if(ext3_get_inode_loc(inode, &iloc)) + goto bad_inode; + bh = iloc.bh; + raw_inode = iloc.raw_inode; + init_rwsem(&inode->u.ext3_i.truncate_sem); + inode->i_mode = le16_to_cpu(raw_inode->i_mode); + inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); + inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); + if(!(test_opt (inode->i_sb, NO_UID32))) { + inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; + inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; + } + inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); + inode->i_size = le32_to_cpu(raw_inode->i_size); + inode->i_atime = le32_to_cpu(raw_inode->i_atime); + inode->i_ctime = le32_to_cpu(raw_inode->i_ctime); + inode->i_mtime = le32_to_cpu(raw_inode->i_mtime); + inode->u.ext3_i.i_dtime = le32_to_cpu(raw_inode->i_dtime); + /* We now have enough fields to check if the inode was active or not. + * This is needed because nfsd might try to access dead inodes + * the test is that same one that e2fsck uses + * NeilBrown 1999oct15 + */ + if (inode->i_nlink == 0) { + if (inode->i_mode == 0 || + !(inode->i_sb->u.ext3_sb.s_mount_state & EXT3_ORPHAN_FS)) { + /* this inode is deleted */ + brelse (bh); + goto bad_inode; + } + /* The only unlinked inodes we let through here have + * valid i_mode and are being read by the orphan + * recovery code: that's fine, we're about to complete + * the process of deleting those. */ + } + inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size + * (for stat), not the fs block + * size */ + inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); + inode->i_version = ++event; + inode->u.ext3_i.i_flags = le32_to_cpu(raw_inode->i_flags); +#ifdef EXT3_FRAGMENTS + inode->u.ext3_i.i_faddr = le32_to_cpu(raw_inode->i_faddr); + inode->u.ext3_i.i_frag_no = raw_inode->i_frag; + inode->u.ext3_i.i_frag_size = raw_inode->i_fsize; +#endif + inode->u.ext3_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl); + if (!S_ISREG(inode->i_mode)) { + inode->u.ext3_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); + } else { + inode->i_size |= + ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; + } + inode->u.ext3_i.i_disksize = inode->i_size; + inode->i_generation = le32_to_cpu(raw_inode->i_generation); +#ifdef EXT3_PREALLOCATE + inode->u.ext3_i.i_prealloc_count = 0; +#endif + inode->u.ext3_i.i_block_group = iloc.block_group; + + /* + * NOTE! The in-memory inode i_data array is in little-endian order + * even on big-endian machines: we do NOT byteswap the block numbers! + */ + for (block = 0; block < EXT3_N_BLOCKS; block++) + inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block]; + INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan); + + brelse (iloc.bh); + + if (inode->i_ino == EXT3_ACL_IDX_INO || + inode->i_ino == EXT3_ACL_DATA_INO) + /* Nothing to do */ ; + else if (S_ISREG(inode->i_mode)) { + inode->i_op = &ext3_file_inode_operations; + inode->i_fop = &ext3_file_operations; + inode->i_mapping->a_ops = &ext3_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &ext3_dir_inode_operations; + inode->i_fop = &ext3_dir_operations; + } else if (S_ISLNK(inode->i_mode)) { + if (!inode->i_blocks) + inode->i_op = &ext3_fast_symlink_inode_operations; + else { + inode->i_op = &page_symlink_inode_operations; + inode->i_mapping->a_ops = &ext3_aops; + } + } else + init_special_inode(inode, inode->i_mode, + le32_to_cpu(iloc.raw_inode->i_block[0])); + /* inode->i_attr_flags = 0; unused */ + if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL) { + /* inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS; unused */ + inode->i_flags |= S_SYNC; + } + if (inode->u.ext3_i.i_flags & EXT3_APPEND_FL) { + /* inode->i_attr_flags |= ATTR_FLAG_APPEND; unused */ + inode->i_flags |= S_APPEND; + } + if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_FL) { + /* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE; unused */ + inode->i_flags |= S_IMMUTABLE; + } + if (inode->u.ext3_i.i_flags & EXT3_NOATIME_FL) { + /* inode->i_attr_flags |= ATTR_FLAG_NOATIME; unused */ + inode->i_flags |= S_NOATIME; + } + return; + +bad_inode: + make_bad_inode(inode); + return; +} + +/* + * Post the struct inode info into an on-disk inode location in the + * buffer-cache. This gobbles the caller's reference to the + * buffer_head in the inode location struct. + */ + +static int ext3_do_update_inode(handle_t *handle, + struct inode *inode, + struct ext3_iloc *iloc) +{ + struct ext3_inode *raw_inode = iloc->raw_inode; + struct buffer_head *bh = iloc->bh; + int err = 0, rc, block; + + if (handle) { + BUFFER_TRACE(bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, bh); + if (err) + goto out_brelse; + } + raw_inode->i_mode = cpu_to_le16(inode->i_mode); + if(!(test_opt(inode->i_sb, NO_UID32))) { + raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); + raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); +/* + * Fix up interoperability with old kernels. Otherwise, old inodes get + * re-used with the upper 16 bits of the uid/gid intact + */ + if(!inode->u.ext3_i.i_dtime) { + raw_inode->i_uid_high = + cpu_to_le16(high_16_bits(inode->i_uid)); + raw_inode->i_gid_high = + cpu_to_le16(high_16_bits(inode->i_gid)); + } else { + raw_inode->i_uid_high = 0; + raw_inode->i_gid_high = 0; + } + } else { + raw_inode->i_uid_low = + cpu_to_le16(fs_high2lowuid(inode->i_uid)); + raw_inode->i_gid_low = + cpu_to_le16(fs_high2lowgid(inode->i_gid)); + raw_inode->i_uid_high = 0; + raw_inode->i_gid_high = 0; + } + raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); + raw_inode->i_size = cpu_to_le32(inode->u.ext3_i.i_disksize); + raw_inode->i_atime = cpu_to_le32(inode->i_atime); + raw_inode->i_ctime = cpu_to_le32(inode->i_ctime); + raw_inode->i_mtime = cpu_to_le32(inode->i_mtime); + raw_inode->i_blocks = cpu_to_le32(inode->i_blocks); + raw_inode->i_dtime = cpu_to_le32(inode->u.ext3_i.i_dtime); + raw_inode->i_flags = cpu_to_le32(inode->u.ext3_i.i_flags); +#ifdef EXT3_FRAGMENTS + raw_inode->i_faddr = cpu_to_le32(inode->u.ext3_i.i_faddr); + raw_inode->i_frag = inode->u.ext3_i.i_frag_no; + raw_inode->i_fsize = inode->u.ext3_i.i_frag_size; +#else + /* If we are not tracking these fields in the in-memory inode, + * then preserve them on disk, but still initialise them to zero + * for new inodes. */ + if (inode->u.ext3_i.i_state & EXT3_STATE_NEW) { + raw_inode->i_faddr = 0; + raw_inode->i_frag = 0; + raw_inode->i_fsize = 0; + } +#endif + raw_inode->i_file_acl = cpu_to_le32(inode->u.ext3_i.i_file_acl); + if (!S_ISREG(inode->i_mode)) { + raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext3_i.i_dir_acl); + } else { + raw_inode->i_size_high = + cpu_to_le32(inode->u.ext3_i.i_disksize >> 32); + if (inode->u.ext3_i.i_disksize > 0x7fffffffULL) { + struct super_block *sb = inode->i_sb; + if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, + EXT3_FEATURE_RO_COMPAT_LARGE_FILE) || + EXT3_SB(sb)->s_es->s_rev_level == + cpu_to_le32(EXT3_GOOD_OLD_REV)) { + /* If this is the first large file + * created, add a flag to the superblock. + */ + err = ext3_journal_get_write_access(handle, + sb->u.ext3_sb.s_sbh); + if (err) + goto out_brelse; + ext3_update_dynamic_rev(sb); + EXT3_SET_RO_COMPAT_FEATURE(sb, + EXT3_FEATURE_RO_COMPAT_LARGE_FILE); + sb->s_dirt = 1; + handle->h_sync = 1; + err = ext3_journal_dirty_metadata(handle, + sb->u.ext3_sb.s_sbh); + } + } + } + raw_inode->i_generation = le32_to_cpu(inode->i_generation); + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + raw_inode->i_block[0] = + cpu_to_le32(kdev_t_to_nr(inode->i_rdev)); + else for (block = 0; block < EXT3_N_BLOCKS; block++) + raw_inode->i_block[block] = inode->u.ext3_i.i_data[block]; + + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + rc = ext3_journal_dirty_metadata(handle, bh); + if (!err) + err = rc; + inode->u.ext3_i.i_state &= ~EXT3_STATE_NEW; + +out_brelse: + brelse (bh); + ext3_std_error(inode->i_sb, err); + return err; +} + +/* + * ext3_write_inode() + * + * We are called from a few places: + * + * - Within generic_file_write() for O_SYNC files. + * Here, there will be no transaction running. We wait for any running + * trasnaction to commit. + * + * - Within sys_sync(), kupdate and such. + * We wait on commit, if tol to. + * + * - Within prune_icache() (PF_MEMALLOC == true) + * Here we simply return. We can't afford to block kswapd on the + * journal commit. + * + * In all cases it is actually safe for us to return without doing anything, + * because the inode has been copied into a raw inode buffer in + * ext3_mark_inode_dirty(). This is a correctness thing for O_SYNC and for + * knfsd. + * + * Note that we are absolutely dependent upon all inode dirtiers doing the + * right thing: they *must* call mark_inode_dirty() after dirtying info in + * which we are interested. + * + * It would be a bug for them to not do this. The code: + * + * mark_inode_dirty(inode) + * stuff(); + * inode->i_size = expr; + * + * is in error because a kswapd-driven write_inode() could occur while + * `stuff()' is running, and the new i_size will be lost. Plus the inode + * will no longer be on the superblock's dirty inode list. + */ +void ext3_write_inode(struct inode *inode, int wait) +{ + if (current->flags & PF_MEMALLOC) + return; + + if (ext3_journal_current_handle()) { + jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n"); + return; + } + + if (!wait) + return; + + ext3_force_commit(inode->i_sb); +} + +/* + * ext3_setattr() + * + * Called from notify_change. + * + * We want to trap VFS attempts to truncate the file as soon as + * possible. In particular, we want to make sure that when the VFS + * shrinks i_size, we put the inode on the orphan list and modify + * i_disksize immediately, so that during the subsequent flushing of + * dirty pages and freeing of disk blocks, we can guarantee that any + * commit will leave the blocks being flushed in an unused state on + * disk. (On recovery, the inode will get truncated and the blocks will + * be freed, so we have a strong guarantee that no future commit will + * leave these blocks visible to the user.) + * + * This is only needed for regular files. rmdir() has its own path, and + * we can never truncate a direcory except on final unlink (at which + * point i_nlink is zero so recovery is easy.) + * + * Called with the BKL. + */ + +int ext3_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + int error, rc; + + error = inode_change_ok(inode, attr); + if (error) + return error; + + if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { + handle_t *handle; + + handle = ext3_journal_start(inode, 3); + if (IS_ERR(handle)) { + error = PTR_ERR(handle); + goto err_out; + } + + error = ext3_orphan_add(handle, inode); + inode->u.ext3_i.i_disksize = attr->ia_size; + rc = ext3_mark_inode_dirty(handle, inode); + if (!error) + error = rc; + ext3_journal_stop(handle, inode); + } + + inode_setattr(inode, attr); + + /* If inode_setattr's call to ext3_truncate failed to get a + * transaction handle at all, we need to clean up the in-core + * orphan list manually. */ + if (inode->i_nlink) + ext3_orphan_del(NULL, inode); + +err_out: + ext3_std_error(inode->i_sb, error); + return 0; +} + + +/* + * akpm: how many blocks doth make a writepage()? + * + * With N blocks per page, it may be: + * N data blocks + * 2 indirect block + * 2 dindirect + * 1 tindirect + * N+5 bitmap blocks (from the above) + * N+5 group descriptor summary blocks + * 1 inode block + * 1 superblock. + * 2 * EXT3_SINGLEDATA_TRANS_BLOCKS for the quote files + * + * 3 * (N + 5) + 2 + 2 * EXT3_SINGLEDATA_TRANS_BLOCKS + * + * With ordered or writeback data it's the same, less the N data blocks. + * + * If the inode's direct blocks can hold an integral number of pages then a + * page cannot straddle two indirect blocks, and we can only touch one indirect + * and dindirect block, and the "5" above becomes "3". + * + * This still overestimates under most circumstances. If we were to pass the + * start and end offsets in here as well we could do block_to_path() on each + * block and work out the exact number of indirects which are touched. Pah. + */ + +int ext3_writepage_trans_blocks(struct inode *inode) +{ + int bpp = ext3_journal_blocks_per_page(inode); + int indirects = (EXT3_NDIR_BLOCKS % bpp) ? 5 : 3; + int ret; + + if (ext3_should_journal_data(inode)) + ret = 3 * (bpp + indirects) + 2; + else + ret = 2 * (bpp + indirects) + 2; + +#ifdef CONFIG_QUOTA + ret += 2 * EXT3_SINGLEDATA_TRANS_BLOCKS; +#endif + + return ret; +} + +int +ext3_mark_iloc_dirty(handle_t *handle, + struct inode *inode, + struct ext3_iloc *iloc) +{ + int err = 0; + + if (handle) { + /* the do_update_inode consumes one bh->b_count */ + atomic_inc(&iloc->bh->b_count); + err = ext3_do_update_inode(handle, inode, iloc); + /* ext3_do_update_inode() does journal_dirty_metadata */ + brelse(iloc->bh); + } else { + printk(KERN_EMERG __FUNCTION__ ": called with no handle!\n"); + } + return err; +} + +/* + * On success, We end up with an outstanding reference count against + * iloc->bh. This _must_ be cleaned up later. + */ + +int +ext3_reserve_inode_write(handle_t *handle, struct inode *inode, + struct ext3_iloc *iloc) +{ + int err = 0; + if (handle) { + err = ext3_get_inode_loc(inode, iloc); + if (!err) { + BUFFER_TRACE(iloc->bh, "get_write_access"); + err = ext3_journal_get_write_access(handle, iloc->bh); + if (err) { + brelse(iloc->bh); + iloc->bh = NULL; + } + } + } + ext3_std_error(inode->i_sb, err); + return err; +} + +/* + * akpm: What we do here is to mark the in-core inode as clean + * with respect to inode dirtiness (it may still be data-dirty). + * This means that the in-core inode may be reaped by prune_icache + * without having to perform any I/O. This is a very good thing, + * because *any* task may call prune_icache - even ones which + * have a transaction open against a different journal. + * + * Is this cheating? Not really. Sure, we haven't written the + * inode out, but prune_icache isn't a user-visible syncing function. + * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync) + * we start and wait on commits. + * + * Is this efficient/effective? Well, we're being nice to the system + * by cleaning up our inodes proactively so they can be reaped + * without I/O. But we are potentially leaving up to five seconds' + * worth of inodes floating about which prune_icache wants us to + * write out. One way to fix that would be to get prune_icache() + * to do a write_super() to free up some memory. It has the desired + * effect. + */ +int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode) +{ + struct ext3_iloc iloc; + int err; + + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (!err) + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + return err; +} + +/* + * akpm: ext3_dirty_inode() is called from __mark_inode_dirty() + * + * We're really interested in the case where a file is being extended. + * i_size has been changed by generic_commit_write() and we thus need + * to include the updated inode in the current transaction. + * + * Also, DQUOT_ALLOC_SPACE() will always dirty the inode when blocks + * are allocated to the file. + * + * If the inode is marked synchronous, we don't honour that here - doing + * so would cause a commit on atime updates, which we don't bother doing. + * We handle synchronous inodes at the highest possible level. + */ +void ext3_dirty_inode(struct inode *inode) +{ + handle_t *current_handle = ext3_journal_current_handle(); + handle_t *handle; + + lock_kernel(); + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) + goto out; + if (current_handle && + current_handle->h_transaction != handle->h_transaction) { + /* This task has a transaction open against a different fs */ + printk(KERN_EMERG __FUNCTION__": transactions do not match!\n"); + } else { + jbd_debug(5, "marking dirty. outer handle=%p\n", + current_handle); + ext3_mark_inode_dirty(handle, inode); + } + ext3_journal_stop(handle, inode); +out: + unlock_kernel(); +} + +#ifdef AKPM +/* + * Bind an inode's backing buffer_head into this transaction, to prevent + * it from being flushed to disk early. Unlike + * ext3_reserve_inode_write, this leaves behind no bh reference and + * returns no iloc structure, so the caller needs to repeat the iloc + * lookup to mark the inode dirty later. + */ +static inline int +ext3_pin_inode(handle_t *handle, struct inode *inode) +{ + struct ext3_iloc iloc; + + int err = 0; + if (handle) { + err = ext3_get_inode_loc(inode, &iloc); + if (!err) { + BUFFER_TRACE(iloc.bh, "get_write_access"); + err = journal_get_write_access(handle, iloc.bh); + if (!err) + err = ext3_journal_dirty_metadata(handle, + iloc.bh); + brelse(iloc.bh); + } + } + ext3_std_error(inode->i_sb, err); + return err; +} +#endif + +int ext3_change_inode_journal_flag(struct inode *inode, int val) +{ + journal_t *journal; + handle_t *handle; + int err; + + /* + * We have to be very careful here: changing a data block's + * journaling status dynamically is dangerous. If we write a + * data block to the journal, change the status and then delete + * that block, we risk forgetting to revoke the old log record + * from the journal and so a subsequent replay can corrupt data. + * So, first we make sure that the journal is empty and that + * nobody is changing anything. + */ + + journal = EXT3_JOURNAL(inode); + if (is_journal_aborted(journal) || IS_RDONLY(inode)) + return -EROFS; + + journal_lock_updates(journal); + journal_flush(journal); + + /* + * OK, there are no updates running now, and all cached data is + * synced to disk. We are now in a completely consistent state + * which doesn't have anything in the journal, and we know that + * no filesystem updates are running, so it is safe to modify + * the inode's in-core data-journaling state flag now. + */ + + if (val) + inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL; + else + inode->u.ext3_i.i_flags &= ~EXT3_JOURNAL_DATA_FL; + + journal_unlock_updates(journal); + + /* Finally we can mark the inode as dirty. */ + + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + err = ext3_mark_inode_dirty(handle, inode); + handle->h_sync = 1; + ext3_journal_stop(handle, inode); + ext3_std_error(inode->i_sb, err); + + return err; +} + + +/* + * ext3_aops_journal_start(). + * + * <This function died, but the comment lives on> + * + * We need to take the inode semaphore *outside* the + * journal_start/journal_stop. Otherwise, a different task could do a + * wait_for_commit() while holding ->i_sem, which deadlocks. The rule + * is: transaction open/closes are considered to be a locking operation + * and they nest *inside* ->i_sem. + * ---------------------------------------------------------------------------- + * Possible problem: + * ext3_file_write() + * -> generic_file_write() + * -> __alloc_pages() + * -> page_launder() + * -> ext3_writepage() + * + * And the writepage can be on a different fs while we have a + * transaction open against this one! Bad. + * + * I tried making the task PF_MEMALLOC here, but that simply results in + * 0-order allocation failures passed back to generic_file_write(). + * Instead, we rely on the reentrancy protection in ext3_writepage(). + * ---------------------------------------------------------------------------- + * When we do the journal_start() here we don't really need to reserve + * any blocks - we won't need any until we hit ext3_prepare_write(), + * which does all the needed journal extending. However! There is a + * problem with quotas: + * + * Thread 1: + * sys_sync + * ->sync_dquots + * ->commit_dquot + * ->lock_dquot + * ->write_dquot + * ->ext3_file_write + * ->journal_start + * ->ext3_prepare_write + * ->journal_extend + * ->journal_start + * Thread 2: + * ext3_create (for example) + * ->ext3_new_inode + * ->dquot_initialize + * ->lock_dquot + * + * Deadlock. Thread 1's journal_start blocks because thread 2 has a + * transaction open. Thread 2's transaction will never close because + * thread 2 is stuck waiting for the dquot lock. + * + * So. We must ensure that thread 1 *never* needs to extend the journal + * for quota writes. We do that by reserving enough journal blocks + * here, in ext3_aops_journal_start() to ensure that the forthcoming "see if we + * need to extend" test in ext3_prepare_write() succeeds. + */ + + +MODULE_LICENSE("GPL"); diff -u --recursive --new-file v2.4.14/linux/fs/ext3/ioctl.c linux/fs/ext3/ioctl.c --- v2.4.14/linux/fs/ext3/ioctl.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/ioctl.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,170 @@ +/* + * linux/fs/ext3/ioctl.c + * + * Copyright (C) 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/ext3_fs.h> +#include <linux/ext3_jbd.h> +#include <linux/sched.h> +#include <asm/uaccess.h> + + +int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + unsigned long arg) +{ + unsigned int flags; + + ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); + + switch (cmd) { + case EXT3_IOC_GETFLAGS: + flags = inode->u.ext3_i.i_flags & EXT3_FL_USER_VISIBLE; + return put_user(flags, (int *) arg); + case EXT3_IOC_SETFLAGS: { + handle_t *handle = NULL; + int err; + struct ext3_iloc iloc; + unsigned int oldflags; + unsigned int jflag; + + if (IS_RDONLY(inode)) + return -EROFS; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + + if (get_user(flags, (int *) arg)) + return -EFAULT; + + oldflags = inode->u.ext3_i.i_flags; + + /* The JOURNAL_DATA flag is modifiable only by root */ + jflag = flags & EXT3_JOURNAL_DATA_FL; + + /* + * The IMMUTABLE and APPEND_ONLY flags can only be changed by + * the relevant capability. + * + * This test looks nicer. Thanks to Pauline Middelink + */ + if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + } + + /* + * The JOURNAL_DATA flag can only be changed by + * the relevant capability. + */ + if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; + } + + + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (IS_SYNC(inode)) + handle->h_sync = 1; + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + goto flags_err; + + flags = flags & EXT3_FL_USER_MODIFIABLE; + flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE; + inode->u.ext3_i.i_flags = flags; + + if (flags & EXT3_SYNC_FL) + inode->i_flags |= S_SYNC; + else + inode->i_flags &= ~S_SYNC; + if (flags & EXT3_APPEND_FL) + inode->i_flags |= S_APPEND; + else + inode->i_flags &= ~S_APPEND; + if (flags & EXT3_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= ~S_IMMUTABLE; + if (flags & EXT3_NOATIME_FL) + inode->i_flags |= S_NOATIME; + else + inode->i_flags &= ~S_NOATIME; + inode->i_ctime = CURRENT_TIME; + + err = ext3_mark_iloc_dirty(handle, inode, &iloc); +flags_err: + ext3_journal_stop(handle, inode); + if (err) + return err; + + if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) + err = ext3_change_inode_journal_flag(inode, jflag); + return err; + } + case EXT3_IOC_GETVERSION: + case EXT3_IOC_GETVERSION_OLD: + return put_user(inode->i_generation, (int *) arg); + case EXT3_IOC_SETVERSION: + case EXT3_IOC_SETVERSION_OLD: { + handle_t *handle; + struct ext3_iloc iloc; + __u32 generation; + int err; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + if (get_user(generation, (int *) arg)) + return -EFAULT; + + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + return err; + + inode->i_ctime = CURRENT_TIME; + inode->i_generation = generation; + + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + ext3_journal_stop(handle, inode); + return err; + } +#ifdef CONFIG_JBD_DEBUG + case EXT3_IOC_WAIT_FOR_READONLY: + /* + * This is racy - by the time we're woken up and running, + * the superblock could be released. And the module could + * have been unloaded. So sue me. + * + * Returns 1 if it slept, else zero. + */ + { + struct super_block *sb = inode->i_sb; + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&sb->u.ext3_sb.ro_wait_queue, &wait); + if (timer_pending(&sb->u.ext3_sb.turn_ro_timer)) { + schedule(); + ret = 1; + } + remove_wait_queue(&sb->u.ext3_sb.ro_wait_queue, &wait); + return ret; + } +#endif + default: + return -ENOTTY; + } +} diff -u --recursive --new-file v2.4.14/linux/fs/ext3/namei.c linux/fs/ext3/namei.c --- v2.4.14/linux/fs/ext3/namei.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/namei.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,1125 @@ +/* + * linux/fs/ext3/namei.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/namei.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + * Directory entry file type support and forward compatibility hooks + * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998 + */ + +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/sched.h> +#include <linux/ext3_fs.h> +#include <linux/ext3_jbd.h> +#include <linux/fcntl.h> +#include <linux/stat.h> +#include <linux/string.h> +#include <linux/locks.h> +#include <linux/quotaops.h> + + +/* + * define how far ahead to read directories while searching them. + */ +#define NAMEI_RA_CHUNKS 2 +#define NAMEI_RA_BLOCKS 4 +#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) +#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) + +/* + * NOTE! unlike strncmp, ext3_match returns 1 for success, 0 for failure. + * + * `len <= EXT3_NAME_LEN' is guaranteed by caller. + * `de != NULL' is guaranteed by caller. + */ +static inline int ext3_match (int len, const char * const name, + struct ext3_dir_entry_2 * de) +{ + if (len != de->name_len) + return 0; + if (!de->inode) + return 0; + return !memcmp(name, de->name, len); +} + +/* + * Returns 0 if not found, -1 on failure, and 1 on success + */ +static int inline search_dirblock(struct buffer_head * bh, + struct inode *dir, + struct dentry *dentry, + unsigned long offset, + struct ext3_dir_entry_2 ** res_dir) +{ + struct ext3_dir_entry_2 * de; + char * dlimit; + int de_len; + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; + + de = (struct ext3_dir_entry_2 *) bh->b_data; + dlimit = bh->b_data + dir->i_sb->s_blocksize; + while ((char *) de < dlimit) { + /* this code is executed quadratically often */ + /* do minimal checking `by hand' */ + + if ((char *) de + namelen <= dlimit && + ext3_match (namelen, name, de)) { + /* found a match - just to be sure, do a full check */ + if (!ext3_check_dir_entry("ext3_find_entry", + dir, de, bh, offset)) + return -1; + *res_dir = de; + return 1; + } + /* prevent looping on a bad block */ + de_len = le16_to_cpu(de->rec_len); + if (de_len <= 0) + return -1; + offset += de_len; + de = (struct ext3_dir_entry_2 *) ((char *) de + de_len); + } + return 0; +} + +/* + * ext3_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + * + * The returned buffer_head has ->b_count elevated. The caller is expected + * to brelse() it when appropriate. + */ +static struct buffer_head * ext3_find_entry (struct dentry *dentry, + struct ext3_dir_entry_2 ** res_dir) +{ + struct super_block * sb; + struct buffer_head * bh_use[NAMEI_RA_SIZE]; + struct buffer_head * bh, *ret = NULL; + unsigned long start, block, b; + int ra_max = 0; /* Number of bh's in the readahead + buffer, bh_use[] */ + int ra_ptr = 0; /* Current index into readahead + buffer */ + int num = 0; + int nblocks, i, err; + struct inode *dir = dentry->d_parent->d_inode; + + *res_dir = NULL; + sb = dir->i_sb; + + nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb); + start = dir->u.ext3_i.i_dir_start_lookup; + if (start >= nblocks) + start = 0; + block = start; +restart: + do { + /* + * We deal with the read-ahead logic here. + */ + if (ra_ptr >= ra_max) { + /* Refill the readahead buffer */ + ra_ptr = 0; + b = block; + for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) { + /* + * Terminate if we reach the end of the + * directory and must wrap, or if our + * search has finished at this block. + */ + if (b >= nblocks || (num && block == start)) { + bh_use[ra_max] = NULL; + break; + } + num++; + bh = ext3_getblk(NULL, dir, b++, 0, &err); + bh_use[ra_max] = bh; + if (bh) + ll_rw_block(READ, 1, &bh); + } + } + if ((bh = bh_use[ra_ptr++]) == NULL) + goto next; + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { + /* read error, skip block & hope for the best */ + brelse(bh); + goto next; + } + i = search_dirblock(bh, dir, dentry, + block << EXT3_BLOCK_SIZE_BITS(sb), res_dir); + if (i == 1) { + dir->u.ext3_i.i_dir_start_lookup = block; + ret = bh; + goto cleanup_and_exit; + } else { + brelse(bh); + if (i < 0) + goto cleanup_and_exit; + } + next: + if (++block >= nblocks) + block = 0; + } while (block != start); + + /* + * If the directory has grown while we were searching, then + * search the last part of the directory before giving up. + */ + block = nblocks; + nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb); + if (block < nblocks) { + start = 0; + goto restart; + } + +cleanup_and_exit: + /* Clean up the read-ahead blocks */ + for (; ra_ptr < ra_max; ra_ptr++) + brelse (bh_use[ra_ptr]); + return ret; +} + +static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry) +{ + struct inode * inode; + struct ext3_dir_entry_2 * de; + struct buffer_head * bh; + + if (dentry->d_name.len > EXT3_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + bh = ext3_find_entry(dentry, &de); + inode = NULL; + if (bh) { + unsigned long ino = le32_to_cpu(de->inode); + brelse (bh); + inode = iget(dir->i_sb, ino); + + if (!inode) + return ERR_PTR(-EACCES); + } + d_add(dentry, inode); + return NULL; +} + +#define S_SHIFT 12 +static unsigned char ext3_type_by_mode[S_IFMT >> S_SHIFT] = { + [S_IFREG >> S_SHIFT] EXT3_FT_REG_FILE, + [S_IFDIR >> S_SHIFT] EXT3_FT_DIR, + [S_IFCHR >> S_SHIFT] EXT3_FT_CHRDEV, + [S_IFBLK >> S_SHIFT] EXT3_FT_BLKDEV, + [S_IFIFO >> S_SHIFT] EXT3_FT_FIFO, + [S_IFSOCK >> S_SHIFT] EXT3_FT_SOCK, + [S_IFLNK >> S_SHIFT] EXT3_FT_SYMLINK, +}; + +static inline void ext3_set_de_type(struct super_block *sb, + struct ext3_dir_entry_2 *de, + umode_t mode) { + if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) + de->file_type = ext3_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; +} + +/* + * ext3_add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as ext3_find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ + +/* + * AKPM: the journalling code here looks wrong on the error paths + */ +static int ext3_add_entry (handle_t *handle, struct dentry *dentry, + struct inode *inode) +{ + struct inode *dir = dentry->d_parent->d_inode; + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; + unsigned long offset; + unsigned short rec_len; + struct buffer_head * bh; + struct ext3_dir_entry_2 * de, * de1; + struct super_block * sb; + int retval; + + sb = dir->i_sb; + + if (!namelen) + return -EINVAL; + bh = ext3_bread (handle, dir, 0, 0, &retval); + if (!bh) + return retval; + rec_len = EXT3_DIR_REC_LEN(namelen); + offset = 0; + de = (struct ext3_dir_entry_2 *) bh->b_data; + while (1) { + if ((char *)de >= sb->s_blocksize + bh->b_data) { + brelse (bh); + bh = NULL; + bh = ext3_bread (handle, dir, + offset >> EXT3_BLOCK_SIZE_BITS(sb), 1, &retval); + if (!bh) + return retval; + if (dir->i_size <= offset) { + if (dir->i_size == 0) { + brelse(bh); + return -ENOENT; + } + + ext3_debug ("creating next block\n"); + + BUFFER_TRACE(bh, "get_write_access"); + ext3_journal_get_write_access(handle, bh); + de = (struct ext3_dir_entry_2 *) bh->b_data; + de->inode = 0; + de->rec_len = le16_to_cpu(sb->s_blocksize); + dir->u.ext3_i.i_disksize = + dir->i_size = offset + sb->s_blocksize; + dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL; + ext3_mark_inode_dirty(handle, dir); + } else { + + ext3_debug ("skipping to next block\n"); + + de = (struct ext3_dir_entry_2 *) bh->b_data; + } + } + if (!ext3_check_dir_entry ("ext3_add_entry", dir, de, bh, + offset)) { + brelse (bh); + return -ENOENT; + } + if (ext3_match (namelen, name, de)) { + brelse (bh); + return -EEXIST; + } + if ((le32_to_cpu(de->inode) == 0 && + le16_to_cpu(de->rec_len) >= rec_len) || + (le16_to_cpu(de->rec_len) >= + EXT3_DIR_REC_LEN(de->name_len) + rec_len)) { + BUFFER_TRACE(bh, "get_write_access"); + ext3_journal_get_write_access(handle, bh); + /* By now the buffer is marked for journaling */ + offset += le16_to_cpu(de->rec_len); + if (le32_to_cpu(de->inode)) { + de1 = (struct ext3_dir_entry_2 *) ((char *) de + + EXT3_DIR_REC_LEN(de->name_len)); + de1->rec_len = + cpu_to_le16(le16_to_cpu(de->rec_len) - + EXT3_DIR_REC_LEN(de->name_len)); + de->rec_len = cpu_to_le16( + EXT3_DIR_REC_LEN(de->name_len)); + de = de1; + } + de->file_type = EXT3_FT_UNKNOWN; + if (inode) { + de->inode = cpu_to_le32(inode->i_ino); + ext3_set_de_type(dir->i_sb, de, inode->i_mode); + } else + de->inode = 0; + de->name_len = namelen; + memcpy (de->name, name, namelen); + /* + * XXX shouldn't update any times until successful + * completion of syscall, but too many callers depend + * on this. + * + * XXX similarly, too many callers depend on + * ext3_new_inode() setting the times, but error + * recovery deletes the inode, so the worst that can + * happen is that the times are slightly out of date + * and/or different from the directory change time. + */ + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL; + ext3_mark_inode_dirty(handle, dir); + dir->i_version = ++event; + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, bh); + brelse(bh); + return 0; + } + offset += le16_to_cpu(de->rec_len); + de = (struct ext3_dir_entry_2 *) + ((char *) de + le16_to_cpu(de->rec_len)); + } + brelse (bh); + return -ENOSPC; +} + +/* + * ext3_delete_entry deletes a directory entry by merging it with the + * previous entry + */ +static int ext3_delete_entry (handle_t *handle, + struct inode * dir, + struct ext3_dir_entry_2 * de_del, + struct buffer_head * bh) +{ + struct ext3_dir_entry_2 * de, * pde; + int i; + + i = 0; + pde = NULL; + de = (struct ext3_dir_entry_2 *) bh->b_data; + while (i < bh->b_size) { + if (!ext3_check_dir_entry("ext3_delete_entry", dir, de, bh, i)) + return -EIO; + if (de == de_del) { + BUFFER_TRACE(bh, "get_write_access"); + ext3_journal_get_write_access(handle, bh); + if (pde) + pde->rec_len = + cpu_to_le16(le16_to_cpu(pde->rec_len) + + le16_to_cpu(de->rec_len)); + else + de->inode = 0; + dir->i_version = ++event; + BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, bh); + return 0; + } + i += le16_to_cpu(de->rec_len); + pde = de; + de = (struct ext3_dir_entry_2 *) + ((char *) de + le16_to_cpu(de->rec_len)); + } + return -ENOENT; +} + +/* + * ext3_mark_inode_dirty is somewhat expensive, so unlike ext2 we + * do not perform it in these functions. We perform it at the call site, + * if it is needed. + */ +static inline void ext3_inc_count(handle_t *handle, struct inode *inode) +{ + inode->i_nlink++; +} + +static inline void ext3_dec_count(handle_t *handle, struct inode *inode) +{ + inode->i_nlink--; +} + +static int ext3_add_nondir(handle_t *handle, + struct dentry *dentry, struct inode *inode) +{ + int err = ext3_add_entry(handle, dentry, inode); + if (!err) { + d_instantiate(dentry, inode); + return 0; + } + ext3_dec_count(handle, inode); + iput(inode); + return err; +} + +/* + * By the time this is called, we already have created + * the directory cache entry for the new file, but it + * is so far negative - it has no inode. + * + * If the create succeeds, we fill in the inode information + * with d_instantiate(). + */ +static int ext3_create (struct inode * dir, struct dentry * dentry, int mode) +{ + handle_t *handle; + struct inode * inode; + int err; + + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_SYNC(dir)) + handle->h_sync = 1; + + inode = ext3_new_inode (handle, dir, mode); + err = PTR_ERR(inode); + if (!IS_ERR(inode)) { + inode->i_op = &ext3_file_inode_operations; + inode->i_fop = &ext3_file_operations; + inode->i_mapping->a_ops = &ext3_aops; + ext3_mark_inode_dirty(handle, inode); + err = ext3_add_nondir(handle, dentry, inode); + } + ext3_journal_stop(handle, dir); + return err; +} + +static int ext3_mknod (struct inode * dir, struct dentry *dentry, + int mode, int rdev) +{ + handle_t *handle; + struct inode *inode; + int err; + + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_SYNC(dir)) + handle->h_sync = 1; + + inode = ext3_new_inode (handle, dir, mode); + err = PTR_ERR(inode); + if (!IS_ERR(inode)) { + init_special_inode(inode, mode, rdev); + ext3_mark_inode_dirty(handle, inode); + err = ext3_add_nondir(handle, dentry, inode); + } + ext3_journal_stop(handle, dir); + return err; +} + +static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) +{ + handle_t *handle; + struct inode * inode; + struct buffer_head * dir_block; + struct ext3_dir_entry_2 * de; + int err; + + if (dir->i_nlink >= EXT3_LINK_MAX) + return -EMLINK; + + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_SYNC(dir)) + handle->h_sync = 1; + + inode = ext3_new_inode (handle, dir, S_IFDIR); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_stop; + + inode->i_op = &ext3_dir_inode_operations; + inode->i_fop = &ext3_dir_operations; + inode->i_size = inode->u.ext3_i.i_disksize = inode->i_sb->s_blocksize; + inode->i_blocks = 0; + dir_block = ext3_bread (handle, inode, 0, 1, &err); + if (!dir_block) { + inode->i_nlink--; /* is this nlink == 0? */ + ext3_mark_inode_dirty(handle, inode); + iput (inode); + goto out_stop; + } + BUFFER_TRACE(dir_block, "get_write_access"); + ext3_journal_get_write_access(handle, dir_block); + de = (struct ext3_dir_entry_2 *) dir_block->b_data; + de->inode = cpu_to_le32(inode->i_ino); + de->name_len = 1; + de->rec_len = cpu_to_le16(EXT3_DIR_REC_LEN(de->name_len)); + strcpy (de->name, "."); + ext3_set_de_type(dir->i_sb, de, S_IFDIR); + de = (struct ext3_dir_entry_2 *) + ((char *) de + le16_to_cpu(de->rec_len)); + de->inode = cpu_to_le32(dir->i_ino); + de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT3_DIR_REC_LEN(1)); + de->name_len = 2; + strcpy (de->name, ".."); + ext3_set_de_type(dir->i_sb, de, S_IFDIR); + inode->i_nlink = 2; + BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, dir_block); + brelse (dir_block); + inode->i_mode = S_IFDIR | mode; + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + ext3_mark_inode_dirty(handle, inode); + err = ext3_add_entry (handle, dentry, inode); + if (err) + goto out_no_entry; + dir->i_nlink++; + dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL; + ext3_mark_inode_dirty(handle, dir); + d_instantiate(dentry, inode); +out_stop: + ext3_journal_stop(handle, dir); + return err; + +out_no_entry: + inode->i_nlink = 0; + ext3_mark_inode_dirty(handle, inode); + iput (inode); + goto out_stop; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir (struct inode * inode) +{ + unsigned long offset; + struct buffer_head * bh; + struct ext3_dir_entry_2 * de, * de1; + struct super_block * sb; + int err; + + sb = inode->i_sb; + if (inode->i_size < EXT3_DIR_REC_LEN(1) + EXT3_DIR_REC_LEN(2) || + !(bh = ext3_bread (NULL, inode, 0, 0, &err))) { + ext3_warning (inode->i_sb, "empty_dir", + "bad directory (dir #%lu) - no data block", + inode->i_ino); + return 1; + } + de = (struct ext3_dir_entry_2 *) bh->b_data; + de1 = (struct ext3_dir_entry_2 *) + ((char *) de + le16_to_cpu(de->rec_len)); + if (le32_to_cpu(de->inode) != inode->i_ino || + !le32_to_cpu(de1->inode) || + strcmp (".", de->name) || + strcmp ("..", de1->name)) { + ext3_warning (inode->i_sb, "empty_dir", + "bad directory (dir #%lu) - no `.' or `..'", + inode->i_ino); + brelse (bh); + return 1; + } + offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len); + de = (struct ext3_dir_entry_2 *) + ((char *) de1 + le16_to_cpu(de1->rec_len)); + while (offset < inode->i_size ) { + if (!bh || + (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { + brelse (bh); + bh = ext3_bread (NULL, inode, + offset >> EXT3_BLOCK_SIZE_BITS(sb), 0, &err); + if (!bh) { +#if 0 + ext3_error (sb, "empty_dir", + "directory #%lu contains a hole at offset %lu", + inode->i_ino, offset); +#endif + offset += sb->s_blocksize; + continue; + } + de = (struct ext3_dir_entry_2 *) bh->b_data; + } + if (!ext3_check_dir_entry ("empty_dir", inode, de, bh, + offset)) { + brelse (bh); + return 1; + } + if (le32_to_cpu(de->inode)) { + brelse (bh); + return 0; + } + offset += le16_to_cpu(de->rec_len); + de = (struct ext3_dir_entry_2 *) + ((char *) de + le16_to_cpu(de->rec_len)); + } + brelse (bh); + return 1; +} + +/* ext3_orphan_add() links an unlinked or truncated inode into a list of + * such inodes, starting at the superblock, in case we crash before the + * file is closed/deleted, or in case the inode truncate spans multiple + * transactions and the last transaction is not recovered after a crash. + * + * At filesystem recovery time, we walk this list deleting unlinked + * inodes and truncating linked inodes in ext3_orphan_cleanup(). + */ +int ext3_orphan_add(handle_t *handle, struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + struct ext3_iloc iloc; + int err = 0, rc; + + lock_super(sb); + if (!list_empty(&inode->u.ext3_i.i_orphan)) + goto out_unlock; + + /* Orphan handling is only valid for files with data blocks + * being truncated, or files being unlinked. */ + + /* @@@ FIXME: Observation from aviro: + * I think I can trigger J_ASSERT in ext3_orphan_add(). We block + * here (on lock_super()), so race with ext3_link() which might bump + * ->i_nlink. For, say it, character device. Not a regular file, + * not a directory, not a symlink and ->i_nlink > 0. + */ + J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); + + BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "get_write_access"); + err = ext3_journal_get_write_access(handle, sb->u.ext3_sb.s_sbh); + if (err) + goto out_unlock; + + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + goto out_unlock; + + /* Insert this inode at the head of the on-disk orphan list... */ + NEXT_ORPHAN(inode) = le32_to_cpu(EXT3_SB(sb)->s_es->s_last_orphan); + EXT3_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); + err = ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh); + rc = ext3_mark_iloc_dirty(handle, inode, &iloc); + if (!err) + err = rc; + + /* Only add to the head of the in-memory list if all the + * previous operations succeeded. If the orphan_add is going to + * fail (possibly taking the journal offline), we can't risk + * leaving the inode on the orphan list: stray orphan-list + * entries can cause panics at unmount time. + * + * This is safe: on error we're going to ignore the orphan list + * anyway on the next recovery. */ + if (!err) + list_add(&inode->u.ext3_i.i_orphan, &EXT3_SB(sb)->s_orphan); + + jbd_debug(4, "superblock will point to %ld\n", inode->i_ino); + jbd_debug(4, "orphan inode %ld will point to %d\n", + inode->i_ino, NEXT_ORPHAN(inode)); +out_unlock: + unlock_super(sb); + ext3_std_error(inode->i_sb, err); + return err; +} + +/* + * ext3_orphan_del() removes an unlinked or truncated inode from the list + * of such inodes stored on disk, because it is finally being cleaned up. + */ +int ext3_orphan_del(handle_t *handle, struct inode *inode) +{ + struct list_head *prev; + struct ext3_sb_info *sbi; + ino_t ino_next; + struct ext3_iloc iloc; + int err = 0; + + lock_super(inode->i_sb); + if (list_empty(&inode->u.ext3_i.i_orphan)) { + unlock_super(inode->i_sb); + return 0; + } + + ino_next = NEXT_ORPHAN(inode); + prev = inode->u.ext3_i.i_orphan.prev; + sbi = EXT3_SB(inode->i_sb); + + jbd_debug(4, "remove inode %ld from orphan list\n", inode->i_ino); + + list_del(&inode->u.ext3_i.i_orphan); + INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan); + + /* If we're on an error path, we may not have a valid + * transaction handle with which to update the orphan list on + * disk, but we still need to remove the inode from the linked + * list in memory. */ + if (!handle) + goto out; + + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + goto out_err; + + if (prev == &sbi->s_orphan) { + jbd_debug(4, "superblock will point to %ld\n", ino_next); + BUFFER_TRACE(sbi->s_sbh, "get_write_access"); + err = ext3_journal_get_write_access(handle, sbi->s_sbh); + if (err) + goto out_brelse; + sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); + err = ext3_journal_dirty_metadata(handle, sbi->s_sbh); + } else { + struct ext3_iloc iloc2; + struct inode *i_prev = + list_entry(prev, struct inode, u.ext3_i.i_orphan); + + jbd_debug(4, "orphan inode %ld will point to %ld\n", + i_prev->i_ino, ino_next); + err = ext3_reserve_inode_write(handle, i_prev, &iloc2); + if (err) + goto out_brelse; + NEXT_ORPHAN(i_prev) = ino_next; + err = ext3_mark_iloc_dirty(handle, i_prev, &iloc2); + } + if (err) + goto out_brelse; + NEXT_ORPHAN(inode) = 0; + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + if (err) + goto out_brelse; + +out_err: + ext3_std_error(inode->i_sb, err); +out: + unlock_super(inode->i_sb); + return err; + +out_brelse: + brelse(iloc.bh); + goto out_err; +} + +static int ext3_rmdir (struct inode * dir, struct dentry *dentry) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext3_dir_entry_2 * de; + handle_t *handle; + + handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + retval = -ENOENT; + bh = ext3_find_entry (dentry, &de); + if (!bh) + goto end_rmdir; + + if (IS_SYNC(dir)) + handle->h_sync = 1; + + inode = dentry->d_inode; + DQUOT_INIT(inode); + + retval = -EIO; + if (le32_to_cpu(de->inode) != inode->i_ino) + goto end_rmdir; + + retval = -ENOTEMPTY; + if (!empty_dir (inode)) + goto end_rmdir; + + retval = ext3_delete_entry(handle, dir, de, bh); + if (retval) + goto end_rmdir; + if (inode->i_nlink != 2) + ext3_warning (inode->i_sb, "ext3_rmdir", + "empty directory has nlink!=2 (%d)", + inode->i_nlink); + inode->i_version = ++event; + inode->i_nlink = 0; + /* There's no need to set i_disksize: the fact that i_nlink is + * zero will ensure that the right thing happens during any + * recovery. */ + inode->i_size = 0; + ext3_orphan_add(handle, inode); + ext3_mark_inode_dirty(handle, inode); + dir->i_nlink--; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL; + ext3_mark_inode_dirty(handle, dir); + +end_rmdir: + ext3_journal_stop(handle, dir); + brelse (bh); + return retval; +} + +static int ext3_unlink(struct inode * dir, struct dentry *dentry) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext3_dir_entry_2 * de; + handle_t *handle; + + handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_SYNC(dir)) + handle->h_sync = 1; + + retval = -ENOENT; + bh = ext3_find_entry (dentry, &de); + if (!bh) + goto end_unlink; + + inode = dentry->d_inode; + DQUOT_INIT(inode); + + retval = -EIO; + if (le32_to_cpu(de->inode) != inode->i_ino) + goto end_unlink; + + if (!inode->i_nlink) { + ext3_warning (inode->i_sb, "ext3_unlink", + "Deleting nonexistent file (%lu), %d", + inode->i_ino, inode->i_nlink); + inode->i_nlink = 1; + } + retval = ext3_delete_entry(handle, dir, de, bh); + if (retval) + goto end_unlink; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL; + ext3_mark_inode_dirty(handle, dir); + inode->i_nlink--; + if (!inode->i_nlink) + ext3_orphan_add(handle, inode); + ext3_mark_inode_dirty(handle, inode); + inode->i_ctime = dir->i_ctime; + retval = 0; + +end_unlink: + ext3_journal_stop(handle, dir); + brelse (bh); + return retval; +} + +static int ext3_symlink (struct inode * dir, + struct dentry *dentry, const char * symname) +{ + handle_t *handle; + struct inode * inode; + int l, err; + + l = strlen(symname)+1; + if (l > dir->i_sb->s_blocksize) + return -ENAMETOOLONG; + + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 5); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_SYNC(dir)) + handle->h_sync = 1; + + inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_stop; + + if (l > sizeof (inode->u.ext3_i.i_data)) { + inode->i_op = &page_symlink_inode_operations; + inode->i_mapping->a_ops = &ext3_aops; + /* + * block_symlink() calls back into ext3_prepare/commit_write. + * We have a transaction open. All is sweetness. It also sets + * i_size in generic_commit_write(). + */ + err = block_symlink(inode, symname, l); + if (err) + goto out_no_entry; + } else { + inode->i_op = &ext3_fast_symlink_inode_operations; + memcpy((char*)&inode->u.ext3_i.i_data,symname,l); + inode->i_size = l-1; + } + inode->u.ext3_i.i_disksize = inode->i_size; + ext3_mark_inode_dirty(handle, inode); + err = ext3_add_nondir(handle, dentry, inode); +out_stop: + ext3_journal_stop(handle, dir); + return err; + +out_no_entry: + ext3_dec_count(handle, inode); + ext3_mark_inode_dirty(handle, inode); + iput (inode); + goto out_stop; +} + +static int ext3_link (struct dentry * old_dentry, + struct inode * dir, struct dentry *dentry) +{ + handle_t *handle; + struct inode *inode = old_dentry->d_inode; + int err; + + if (S_ISDIR(inode->i_mode)) + return -EPERM; + + if (inode->i_nlink >= EXT3_LINK_MAX) + return -EMLINK; + + handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_SYNC(dir)) + handle->h_sync = 1; + + inode->i_ctime = CURRENT_TIME; + ext3_inc_count(handle, inode); + atomic_inc(&inode->i_count); + + ext3_mark_inode_dirty(handle, inode); + err = ext3_add_nondir(handle, dentry, inode); + ext3_journal_stop(handle, dir); + return err; +} + +#define PARENT_INO(buffer) \ + ((struct ext3_dir_entry_2 *) ((char *) buffer + \ + le16_to_cpu(((struct ext3_dir_entry_2 *) buffer)->rec_len)))->inode + +/* + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, + struct inode * new_dir,struct dentry *new_dentry) +{ + handle_t *handle; + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct ext3_dir_entry_2 * old_de, * new_de; + int retval; + + old_bh = new_bh = dir_bh = NULL; + + handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS + 2); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (IS_SYNC(old_dir) || IS_SYNC(new_dir)) + handle->h_sync = 1; + + old_bh = ext3_find_entry (old_dentry, &old_de); + /* + * Check for inode number is _not_ due to possible IO errors. + * We might rmdir the source, keep it as pwd of some process + * and merrily kill the link to whatever was created under the + * same name. Goodbye sticky bit ;-< + */ + old_inode = old_dentry->d_inode; + retval = -ENOENT; + if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino) + goto end_rename; + + new_inode = new_dentry->d_inode; + new_bh = ext3_find_entry (new_dentry, &new_de); + if (new_bh) { + if (!new_inode) { + brelse (new_bh); + new_bh = NULL; + } else { + DQUOT_INIT(new_inode); + } + } + if (S_ISDIR(old_inode->i_mode)) { + if (new_inode) { + retval = -ENOTEMPTY; + if (!empty_dir (new_inode)) + goto end_rename; + } + retval = -EIO; + dir_bh = ext3_bread (handle, old_inode, 0, 0, &retval); + if (!dir_bh) + goto end_rename; + if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino) + goto end_rename; + retval = -EMLINK; + if (!new_inode && new_dir!=old_dir && + new_dir->i_nlink >= EXT3_LINK_MAX) + goto end_rename; + } + if (!new_bh) { + retval = ext3_add_entry (handle, new_dentry, old_inode); + if (retval) + goto end_rename; + } else { + BUFFER_TRACE(new_bh, "get write access"); + BUFFER_TRACE(new_bh, "get_write_access"); + ext3_journal_get_write_access(handle, new_bh); + new_de->inode = le32_to_cpu(old_inode->i_ino); + if (EXT3_HAS_INCOMPAT_FEATURE(new_dir->i_sb, + EXT3_FEATURE_INCOMPAT_FILETYPE)) + new_de->file_type = old_de->file_type; + new_dir->i_version = ++event; + BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, new_bh); + brelse(new_bh); + new_bh = NULL; + } + + /* + * Like most other Unix systems, set the ctime for inodes on a + * rename. + */ + old_inode->i_ctime = CURRENT_TIME; + ext3_mark_inode_dirty(handle, old_inode); + + /* + * ok, that's it + */ + ext3_delete_entry(handle, old_dir, old_de, old_bh); + + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_ctime = CURRENT_TIME; + } + old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; + old_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL; + if (dir_bh) { + BUFFER_TRACE(dir_bh, "get_write_access"); + ext3_journal_get_write_access(handle, dir_bh); + PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino); + BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, dir_bh); + old_dir->i_nlink--; + if (new_inode) { + new_inode->i_nlink--; + } else { + new_dir->i_nlink++; + new_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL; + ext3_mark_inode_dirty(handle, new_dir); + } + } + ext3_mark_inode_dirty(handle, old_dir); + if (new_inode) { + ext3_mark_inode_dirty(handle, new_inode); + if (!new_inode->i_nlink) + ext3_orphan_add(handle, new_inode); + } + retval = 0; + +end_rename: + brelse (dir_bh); + brelse (old_bh); + brelse (new_bh); + ext3_journal_stop(handle, old_dir); + return retval; +} + +/* + * directories can handle most operations... + */ +struct inode_operations ext3_dir_inode_operations = { + create: ext3_create, /* BKL held */ + lookup: ext3_lookup, /* BKL held */ + link: ext3_link, /* BKL held */ + unlink: ext3_unlink, /* BKL held */ + symlink: ext3_symlink, /* BKL held */ + mkdir: ext3_mkdir, /* BKL held */ + rmdir: ext3_rmdir, /* BKL held */ + mknod: ext3_mknod, /* BKL held */ + rename: ext3_rename, /* BKL held */ +}; diff -u --recursive --new-file v2.4.14/linux/fs/ext3/super.c linux/fs/ext3/super.c --- v2.4.14/linux/fs/ext3/super.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/super.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,1745 @@ +/* + * linux/fs/ext3/super.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/jbd.h> +#include <linux/ext3_fs.h> +#include <linux/ext3_jbd.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/locks.h> +#include <linux/blkdev.h> +#include <linux/smp_lock.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_JBD_DEBUG +static int ext3_ro_after; /* Make fs read-only after this many jiffies */ +#endif + +static int ext3_load_journal(struct super_block *, struct ext3_super_block *); +static int ext3_create_journal(struct super_block *, struct ext3_super_block *, + int); +static void ext3_commit_super (struct super_block * sb, + struct ext3_super_block * es, + int sync); +static void ext3_mark_recovery_complete(struct super_block * sb, + struct ext3_super_block * es); +static void ext3_clear_journal_err(struct super_block * sb, + struct ext3_super_block * es); + +#ifdef CONFIG_JBD_DEBUG +int journal_no_write[2]; + +/* + * Debug code for turning filesystems "read-only" after a specified + * amount of time. This is for crash/recovery testing. + */ + +static void make_rdonly(kdev_t dev, int *no_write) +{ + if (dev) { + printk(KERN_WARNING "Turning device %s read-only\n", + bdevname(dev)); + *no_write = 0xdead0000 + dev; + } +} + +static void turn_fs_readonly(unsigned long arg) +{ + struct super_block *sb = (struct super_block *)arg; + + make_rdonly(sb->s_dev, &journal_no_write[0]); + make_rdonly(EXT3_SB(sb)->s_journal->j_dev, &journal_no_write[1]); + wake_up(&EXT3_SB(sb)->ro_wait_queue); +} + +static void setup_ro_after(struct super_block *sb) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + init_timer(&sbi->turn_ro_timer); + if (ext3_ro_after) { + printk(KERN_DEBUG "fs will go read-only in %d jiffies\n", + ext3_ro_after); + init_waitqueue_head(&sbi->ro_wait_queue); + journal_no_write[0] = 0; + journal_no_write[1] = 0; + sbi->turn_ro_timer.function = turn_fs_readonly; + sbi->turn_ro_timer.data = (unsigned long)sb; + sbi->turn_ro_timer.expires = jiffies + ext3_ro_after; + ext3_ro_after = 0; + add_timer(&sbi->turn_ro_timer); + } +} + +static void clear_ro_after(struct super_block *sb) +{ + del_timer_sync(&EXT3_SB(sb)->turn_ro_timer); + journal_no_write[0] = 0; + journal_no_write[1] = 0; + ext3_ro_after = 0; +} +#else +#define setup_ro_after(sb) do {} while (0) +#define clear_ro_after(sb) do {} while (0) +#endif + + +static char error_buf[1024]; + +/* Determine the appropriate response to ext3_error on a given filesystem */ + +static int ext3_error_behaviour(struct super_block *sb) +{ + /* First check for mount-time options */ + if (test_opt (sb, ERRORS_PANIC)) + return EXT3_ERRORS_PANIC; + if (test_opt (sb, ERRORS_RO)) + return EXT3_ERRORS_RO; + if (test_opt (sb, ERRORS_CONT)) + return EXT3_ERRORS_CONTINUE; + + /* If no overrides were specified on the mount, then fall back + * to the default behaviour set in the filesystem's superblock + * on disk. */ + switch (le16_to_cpu(sb->u.ext3_sb.s_es->s_errors)) { + case EXT3_ERRORS_PANIC: + return EXT3_ERRORS_PANIC; + case EXT3_ERRORS_RO: + return EXT3_ERRORS_RO; + default: + break; + } + return EXT3_ERRORS_CONTINUE; +} + +/* Deal with the reporting of failure conditions on a filesystem such as + * inconsistencies detected or read IO failures. + * + * On ext2, we can store the error state of the filesystem in the + * superblock. That is not possible on ext3, because we may have other + * write ordering constraints on the superblock which prevent us from + * writing it out straight away; and given that the journal is about to + * be aborted, we can't rely on the current, or future, transactions to + * write out the superblock safely. + * + * We'll just use the journal_abort() error code to record an error in + * the journal instead. On recovery, the journal will compain about + * that error until we've noted it down and cleared it. + */ + +static void ext3_handle_error(struct super_block *sb) +{ + struct ext3_super_block *es = EXT3_SB(sb)->s_es; + + EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; + es->s_state |= cpu_to_le32(EXT3_ERROR_FS); + + if (sb->s_flags & MS_RDONLY) + return; + + if (ext3_error_behaviour(sb) != EXT3_ERRORS_CONTINUE) { + EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT; + journal_abort(EXT3_SB(sb)->s_journal, -EIO); + } + + if (ext3_error_behaviour(sb) == EXT3_ERRORS_PANIC) + panic ("EXT3-fs (device %s): panic forced after error\n", + bdevname(sb->s_dev)); + + if (ext3_error_behaviour(sb) == EXT3_ERRORS_RO) { + printk (KERN_CRIT "Remounting filesystem read-only\n"); + sb->s_flags |= MS_RDONLY; + } + + ext3_commit_super(sb, es, 1); +} + +void ext3_error (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + + printk (KERN_CRIT "EXT3-fs error (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); + + ext3_handle_error(sb); +} + +const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16]) +{ + char *errstr = NULL; + + switch (errno) { + case -EIO: + errstr = "IO failure"; + break; + case -ENOMEM: + errstr = "Out of memory"; + break; + case -EROFS: + if (!sb || EXT3_SB(sb)->s_journal->j_flags & JFS_ABORT) + errstr = "Journal has aborted"; + else + errstr = "Readonly filesystem"; + break; + default: + /* If the caller passed in an extra buffer for unknown + * errors, textualise them now. Else we just return + * NULL. */ + if (nbuf) { + /* Check for truncated error codes... */ + if (snprintf(nbuf, 16, "error %d", -errno) >= 0) + errstr = nbuf; + } + + break; + } + + return errstr; +} + +/* __ext3_std_error decodes expected errors from journaling functions + * automatically and invokes the appropriate error response. */ + +void __ext3_std_error (struct super_block * sb, const char * function, + int errno) +{ + char nbuf[16]; + const char *errstr = ext3_decode_error(sb, errno, nbuf); + + printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n", + bdevname(sb->s_dev), function, errstr); + + ext3_handle_error(sb); +} + +/* + * ext3_abort is a much stronger failure handler than ext3_error. The + * abort function may be used to deal with unrecoverable failures such + * as journal IO errors or ENOMEM at a critical moment in log management. + * + * We unconditionally force the filesystem into an ABORT|READONLY state, + * unless the error response on the fs has been set to panic in which + * case we take the easy way out and panic immediately. + */ + +void ext3_abort (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + printk (KERN_CRIT "ext3_abort called.\n"); + + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + + if (ext3_error_behaviour(sb) == EXT3_ERRORS_PANIC) + panic ("EXT3-fs panic (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); + + printk (KERN_CRIT "EXT3-fs abort (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); + + if (sb->s_flags & MS_RDONLY) + return; + + printk (KERN_CRIT "Remounting filesystem read-only\n"); + sb->u.ext3_sb.s_mount_state |= EXT3_ERROR_FS; + sb->s_flags |= MS_RDONLY; + sb->u.ext3_sb.s_mount_opt |= EXT3_MOUNT_ABORT; + journal_abort(EXT3_SB(sb)->s_journal, -EIO); +} + +/* Deal with the reporting of failure conditions while running, such as + * inconsistencies in operation or invalid system states. + * + * Use ext3_error() for cases of invalid filesystem states, as that will + * record an error on disk and force a filesystem check on the next boot. + */ +NORET_TYPE void ext3_panic (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + + /* this is to prevent panic from syncing this filesystem */ + /* AKPM: is this sufficient? */ + sb->s_flags |= MS_RDONLY; + panic ("EXT3-fs panic (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); +} + +void ext3_warning (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + printk (KERN_WARNING "EXT3-fs warning (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); +} + +void ext3_update_dynamic_rev(struct super_block *sb) +{ + struct ext3_super_block *es = EXT3_SB(sb)->s_es; + + if (le32_to_cpu(es->s_rev_level) > EXT3_GOOD_OLD_REV) + return; + + ext3_warning(sb, __FUNCTION__, + "updating to rev %d because of new feature flag, " + "running e2fsck is recommended", + EXT3_DYNAMIC_REV); + + es->s_first_ino = cpu_to_le32(EXT3_GOOD_OLD_FIRST_INO); + es->s_inode_size = cpu_to_le16(EXT3_GOOD_OLD_INODE_SIZE); + es->s_rev_level = cpu_to_le32(EXT3_DYNAMIC_REV); + /* leave es->s_feature_*compat flags alone */ + /* es->s_uuid will be set by e2fsck if empty */ + + /* + * The rest of the superblock fields should be zero, and if not it + * means they are likely already in use, so leave them alone. We + * can leave it up to e2fsck to clean up any inconsistencies there. + */ +} + +/* + * Open the external journal device + */ +static struct block_device *ext3_blkdev_get(kdev_t dev) +{ + struct block_device *bdev; + int err = -ENODEV; + + bdev = bdget(kdev_t_to_nr(dev)); + if (bdev == NULL) + goto fail; + err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS); + if (err < 0) + goto fail; + return bdev; + +fail: + printk(KERN_ERR "EXT3: failed to open journal device %s: %d\n", + bdevname(dev), err); + return NULL; +} + +/* + * Release the journal device + */ +static int ext3_blkdev_put(struct block_device *bdev) +{ + return blkdev_put(bdev, BDEV_FS); +} + +static int ext3_blkdev_remove(struct ext3_sb_info *sbi) +{ + struct block_device *bdev; + int ret = -ENODEV; + + bdev = sbi->journal_bdev; + if (bdev) { + ret = ext3_blkdev_put(bdev); + sbi->journal_bdev = 0; + } + return ret; +} + +#define orphan_list_entry(l) list_entry((l), struct inode, u.ext3_i.i_orphan) + +static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi) +{ + struct list_head *l; + + printk(KERN_ERR "sb orphan head is %d\n", + le32_to_cpu(sbi->s_es->s_last_orphan)); + + printk(KERN_ERR "sb_info orphan list:\n"); + list_for_each(l, &sbi->s_orphan) { + struct inode *inode = orphan_list_entry(l); + printk(KERN_ERR " " + "inode 0x%04x:%ld at %p: mode %o, nlink %d, next %d\n", + inode->i_dev, inode->i_ino, inode, + inode->i_mode, inode->i_nlink, + le32_to_cpu(NEXT_ORPHAN(inode))); + } +} + +void ext3_put_super (struct super_block * sb) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext3_super_block *es = sbi->s_es; + kdev_t j_dev = sbi->s_journal->j_dev; + int i; + + journal_destroy(sbi->s_journal); + if (!(sb->s_flags & MS_RDONLY)) { + EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + es->s_state = le16_to_cpu(sbi->s_mount_state); + BUFFER_TRACE(sbi->s_sbh, "marking dirty"); + mark_buffer_dirty(sbi->s_sbh); + ext3_commit_super(sb, es, 1); + } + + for (i = 0; i < sbi->s_gdb_count; i++) + brelse(sbi->s_group_desc[i]); + kfree(sbi->s_group_desc); + for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++) + brelse(sbi->s_inode_bitmap[i]); + for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++) + brelse(sbi->s_block_bitmap[i]); + brelse(sbi->s_sbh); + + /* Debugging code just in case the in-memory inode orphan list + * isn't empty. The on-disk one can be non-empty if we've + * detected an error and taken the fs readonly, but the + * in-memory list had better be clean by this point. */ + if (!list_empty(&sbi->s_orphan)) + dump_orphan_list(sb, sbi); + J_ASSERT(list_empty(&sbi->s_orphan)); + + invalidate_buffers(sb->s_dev); + if (j_dev != sb->s_dev) { + /* + * Invalidate the journal device's buffers. We don't want them + * floating about in memory - the physical journal device may + * hotswapped, and it breaks the `ro-after' testing code. + */ + fsync_no_super(j_dev); + invalidate_buffers(j_dev); + ext3_blkdev_remove(sbi); + } + clear_ro_after(sb); + + return; +} + +static struct super_operations ext3_sops = { + read_inode: ext3_read_inode, /* BKL held */ + write_inode: ext3_write_inode, /* BKL not held. Don't need */ + dirty_inode: ext3_dirty_inode, /* BKL not held. We take it */ + put_inode: ext3_put_inode, /* BKL not held. Don't need */ + delete_inode: ext3_delete_inode, /* BKL not held. We take it */ + put_super: ext3_put_super, /* BKL held */ + write_super: ext3_write_super, /* BKL held */ + write_super_lockfs: ext3_write_super_lockfs, /* BKL not held. Take it */ + unlockfs: ext3_unlockfs, /* BKL not held. We take it */ + statfs: ext3_statfs, /* BKL held */ + remount_fs: ext3_remount, /* BKL held */ +}; + +static int want_value(char *value, char *option) +{ + if (!value || !*value) { + printk(KERN_NOTICE "EXT3-fs: the %s option needs an argument\n", + option); + return -1; + } + return 0; +} + +static int want_null_value(char *value, char *option) +{ + if (*value) { + printk(KERN_NOTICE "EXT3-fs: Invalid %s argument: %s\n", + option, value); + return -1; + } + return 0; +} + +static int want_numeric(char *value, char *option, unsigned long *number) +{ + if (want_value(value, option)) + return -1; + *number = simple_strtoul(value, &value, 0); + if (want_null_value(value, option)) + return -1; + return 0; +} + +/* + * This function has been shamelessly adapted from the msdos fs + */ +static int parse_options (char * options, unsigned long * sb_block, + struct ext3_sb_info *sbi, + unsigned long * inum, + int is_remount) +{ + unsigned long *mount_options = &sbi->s_mount_opt; + uid_t *resuid = &sbi->s_resuid; + gid_t *resgid = &sbi->s_resgid; + char * this_char; + char * value; + + if (!options) + return 1; + for (this_char = strtok (options, ","); + this_char != NULL; + this_char = strtok (NULL, ",")) { + if ((value = strchr (this_char, '=')) != NULL) + *value++ = 0; + if (!strcmp (this_char, "bsddf")) + clear_opt (*mount_options, MINIX_DF); + else if (!strcmp (this_char, "nouid32")) { + set_opt (*mount_options, NO_UID32); + } + else if (!strcmp (this_char, "abort")) + set_opt (*mount_options, ABORT); + else if (!strcmp (this_char, "check")) { + if (!value || !*value || !strcmp (value, "none")) + clear_opt (*mount_options, CHECK); + else +#ifdef CONFIG_EXT3_CHECK + set_opt (*mount_options, CHECK); +#else + printk(KERN_ERR + "EXT3 Check option not supported\n"); +#endif + } + else if (!strcmp (this_char, "debug")) + set_opt (*mount_options, DEBUG); + else if (!strcmp (this_char, "errors")) { + if (want_value(value, "errors")) + return 0; + if (!strcmp (value, "continue")) { + clear_opt (*mount_options, ERRORS_RO); + clear_opt (*mount_options, ERRORS_PANIC); + set_opt (*mount_options, ERRORS_CONT); + } + else if (!strcmp (value, "remount-ro")) { + clear_opt (*mount_options, ERRORS_CONT); + clear_opt (*mount_options, ERRORS_PANIC); + set_opt (*mount_options, ERRORS_RO); + } + else if (!strcmp (value, "panic")) { + clear_opt (*mount_options, ERRORS_CONT); + clear_opt (*mount_options, ERRORS_RO); + set_opt (*mount_options, ERRORS_PANIC); + } + else { + printk (KERN_ERR + "EXT3-fs: Invalid errors option: %s\n", + value); + return 0; + } + } + else if (!strcmp (this_char, "grpid") || + !strcmp (this_char, "bsdgroups")) + set_opt (*mount_options, GRPID); + else if (!strcmp (this_char, "minixdf")) + set_opt (*mount_options, MINIX_DF); + else if (!strcmp (this_char, "nocheck")) + clear_opt (*mount_options, CHECK); + else if (!strcmp (this_char, "nogrpid") || + !strcmp (this_char, "sysvgroups")) + clear_opt (*mount_options, GRPID); + else if (!strcmp (this_char, "resgid")) { + unsigned long v; + if (want_numeric(value, "resgid", &v)) + return 0; + *resgid = v; + } + else if (!strcmp (this_char, "resuid")) { + unsigned long v; + if (want_numeric(value, "resuid", &v)) + return 0; + *resuid = v; + } + else if (!strcmp (this_char, "sb")) { + if (want_numeric(value, "sb", sb_block)) + return 0; + } +#ifdef CONFIG_JBD_DEBUG + else if (!strcmp (this_char, "ro-after")) { + unsigned long v; + if (want_numeric(value, "ro-after", &v)) + return 0; + ext3_ro_after = v; + } +#endif + /* Silently ignore the quota options */ + else if (!strcmp (this_char, "grpquota") + || !strcmp (this_char, "noquota") + || !strcmp (this_char, "quota") + || !strcmp (this_char, "usrquota")) + /* Don't do anything ;-) */ ; + else if (!strcmp (this_char, "journal")) { + /* @@@ FIXME */ + /* Eventually we will want to be able to create + a journal file here. For now, only allow the + user to specify an existing inode to be the + journal file. */ + if (is_remount) { + printk(KERN_ERR "EXT3-fs: cannot specify " + "journal on remount\n"); + return 0; + } + + if (want_value(value, "journal")) + return 0; + if (!strcmp (value, "update")) + set_opt (*mount_options, UPDATE_JOURNAL); + else if (want_numeric(value, "journal", inum)) + return 0; + } + else if (!strcmp (this_char, "noload")) + set_opt (*mount_options, NOLOAD); + else if (!strcmp (this_char, "data")) { + int data_opt = 0; + + if (want_value(value, "data")) + return 0; + if (!strcmp (value, "journal")) + data_opt = EXT3_MOUNT_JOURNAL_DATA; + else if (!strcmp (value, "ordered")) + data_opt = EXT3_MOUNT_ORDERED_DATA; + else if (!strcmp (value, "writeback")) + data_opt = EXT3_MOUNT_WRITEBACK_DATA; + else { + printk (KERN_ERR + "EXT3-fs: Invalid data option: %s\n", + value); + return 0; + } + if (is_remount) { + if ((*mount_options & EXT3_MOUNT_DATA_FLAGS) != + data_opt) { + printk(KERN_ERR + "EXT3-fs: cannot change data " + "mode on remount\n"); + return 0; + } + } else { + *mount_options &= ~EXT3_MOUNT_DATA_FLAGS; + *mount_options |= data_opt; + } + } else { + printk (KERN_ERR + "EXT3-fs: Unrecognized mount option %s\n", + this_char); + return 0; + } + } + return 1; +} + +static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, + int read_only) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + int res = 0; + + if (le32_to_cpu(es->s_rev_level) > EXT3_MAX_SUPP_REV) { + printk (KERN_ERR "EXT3-fs warning: revision level too high, " + "forcing read-only mode\n"); + res = MS_RDONLY; + } + if (read_only) + return res; + if (!(sbi->s_mount_state & EXT3_VALID_FS)) + printk (KERN_WARNING "EXT3-fs warning: mounting unchecked fs, " + "running e2fsck is recommended\n"); + else if ((sbi->s_mount_state & EXT3_ERROR_FS)) + printk (KERN_WARNING + "EXT3-fs warning: mounting fs with errors, " + "running e2fsck is recommended\n"); + else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && + le16_to_cpu(es->s_mnt_count) >= + (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) + printk (KERN_WARNING + "EXT3-fs warning: maximal mount count reached, " + "running e2fsck is recommended\n"); + else if (le32_to_cpu(es->s_checkinterval) && + (le32_to_cpu(es->s_lastcheck) + + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME)) + printk (KERN_WARNING + "EXT3-fs warning: checktime reached, " + "running e2fsck is recommended\n"); +#if 0 + /* @@@ We _will_ want to clear the valid bit if we find + inconsistencies, to force a fsck at reboot. But for + a plain journaled filesystem we can keep it set as + valid forever! :) */ + es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT3_VALID_FS); +#endif + if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) + es->s_max_mnt_count = + (__s16) cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT); + es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); + es->s_mtime = cpu_to_le32(CURRENT_TIME); + ext3_update_dynamic_rev(sb); + EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + ext3_commit_super (sb, es, 1); + if (test_opt (sb, DEBUG)) + printk (KERN_INFO + "[EXT3 FS %s, %s, bs=%lu, gc=%lu, " + "bpg=%lu, ipg=%lu, mo=%04lx]\n", + EXT3FS_VERSION, EXT3FS_DATE, sb->s_blocksize, + sbi->s_groups_count, + EXT3_BLOCKS_PER_GROUP(sb), + EXT3_INODES_PER_GROUP(sb), + sbi->s_mount_opt); + printk(KERN_INFO "EXT3 FS " EXT3FS_VERSION ", " EXT3FS_DATE " on %s, ", + bdevname(sb->s_dev)); + if (EXT3_SB(sb)->s_journal->j_inode == NULL) { + printk("external journal on %s\n", + bdevname(EXT3_SB(sb)->s_journal->j_dev)); + } else { + printk("internal journal\n"); + } +#ifdef CONFIG_EXT3_CHECK + if (test_opt (sb, CHECK)) { + ext3_check_blocks_bitmap (sb); + ext3_check_inodes_bitmap (sb); + } +#endif + setup_ro_after(sb); + return res; +} + +static int ext3_check_descriptors (struct super_block * sb) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + unsigned long block = le32_to_cpu(sbi->s_es->s_first_data_block); + struct ext3_group_desc * gdp = NULL; + int desc_block = 0; + int i; + + ext3_debug ("Checking group descriptors"); + + for (i = 0; i < sbi->s_groups_count; i++) + { + if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0) + gdp = (struct ext3_group_desc *) + sbi->s_group_desc[desc_block++]->b_data; + if (le32_to_cpu(gdp->bg_block_bitmap) < block || + le32_to_cpu(gdp->bg_block_bitmap) >= + block + EXT3_BLOCKS_PER_GROUP(sb)) + { + ext3_error (sb, "ext3_check_descriptors", + "Block bitmap for group %d" + " not in group (block %lu)!", + i, (unsigned long) + le32_to_cpu(gdp->bg_block_bitmap)); + return 0; + } + if (le32_to_cpu(gdp->bg_inode_bitmap) < block || + le32_to_cpu(gdp->bg_inode_bitmap) >= + block + EXT3_BLOCKS_PER_GROUP(sb)) + { + ext3_error (sb, "ext3_check_descriptors", + "Inode bitmap for group %d" + " not in group (block %lu)!", + i, (unsigned long) + le32_to_cpu(gdp->bg_inode_bitmap)); + return 0; + } + if (le32_to_cpu(gdp->bg_inode_table) < block || + le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >= + block + EXT3_BLOCKS_PER_GROUP(sb)) + { + ext3_error (sb, "ext3_check_descriptors", + "Inode table for group %d" + " not in group (block %lu)!", + i, (unsigned long) + le32_to_cpu(gdp->bg_inode_table)); + return 0; + } + block += EXT3_BLOCKS_PER_GROUP(sb); + gdp++; + } + return 1; +} + + +/* ext3_orphan_cleanup() walks a singly-linked list of inodes (starting at + * the superblock) which were deleted from all directories, but held open by + * a process at the time of a crash. We walk the list and try to delete these + * inodes at recovery time (only with a read-write filesystem). + * + * In order to keep the orphan inode chain consistent during traversal (in + * case of crash during recovery), we link each inode into the superblock + * orphan list_head and handle it the same way as an inode deletion during + * normal operation (which journals the operations for us). + * + * We only do an iget() and an iput() on each inode, which is very safe if we + * accidentally point at an in-use or already deleted inode. The worst that + * can happen in this case is that we get a "bit already cleared" message from + * ext3_free_inode(). The only reason we would point at a wrong inode is if + * e2fsck was run on this filesystem, and it must have already done the orphan + * inode cleanup for us, so we can safely abort without any further action. + */ +static void ext3_orphan_cleanup (struct super_block * sb, + struct ext3_super_block * es) +{ + unsigned int s_flags = sb->s_flags; + int nr_orphans = 0, nr_truncates = 0; + if (!es->s_last_orphan) { + jbd_debug(4, "no orphan inodes to clean up\n"); + return; + } + + if (s_flags & MS_RDONLY) { + printk(KERN_INFO "EXT3-fs: %s: orphan cleanup on readonly fs\n", + bdevname(sb->s_dev)); + sb->s_flags &= ~MS_RDONLY; + } + + if (sb->u.ext3_sb.s_mount_state & EXT3_ERROR_FS) { + if (es->s_last_orphan) + jbd_debug(1, "Errors on filesystem, " + "clearing orphan list.\n"); + es->s_last_orphan = 0; + jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); + return; + } + + while (es->s_last_orphan) { + struct inode *inode; + + if (!(inode = + ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) { + es->s_last_orphan = 0; + break; + } + + list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan); + if (inode->i_nlink) { + printk(KERN_DEBUG __FUNCTION__ + ": truncating inode %ld to %Ld bytes\n", + inode->i_ino, inode->i_size); + jbd_debug(2, "truncating inode %ld to %Ld bytes\n", + inode->i_ino, inode->i_size); + ext3_truncate(inode); + nr_truncates++; + } else { + printk(KERN_DEBUG __FUNCTION__ + ": deleting unreferenced inode %ld\n", + inode->i_ino); + jbd_debug(2, "deleting unreferenced inode %ld\n", + inode->i_ino); + nr_orphans++; + } + iput(inode); /* The delete magic happens here! */ + } + +#define PLURAL(x) (x), ((x)==1) ? "" : "s" + + if (nr_orphans) + printk(KERN_INFO "EXT3-fs: %s: %d orphan inode%s deleted\n", + bdevname(sb->s_dev), PLURAL(nr_orphans)); + if (nr_truncates) + printk(KERN_INFO "EXT3-fs: %s: %d truncate%s cleaned up\n", + bdevname(sb->s_dev), PLURAL(nr_truncates)); + sb->s_flags = s_flags; /* Restore MS_RDONLY status */ +} + +#define log2(n) ffz(~(n)) + +/* + * Maximal file size. There is a direct, and {,double-,triple-}indirect + * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. + * We need to be 1 filesystem block less than the 2^32 sector limit. + */ +static loff_t ext3_max_size(int bits) +{ + loff_t res = EXT3_NDIR_BLOCKS; + res += 1LL << (bits-2); + res += 1LL << (2*(bits-2)); + res += 1LL << (3*(bits-2)); + res <<= bits; + if (res > (512LL << 32) - (1 << bits)) + res = (512LL << 32) - (1 << bits); + return res; +} + +struct super_block * ext3_read_super (struct super_block * sb, void * data, + int silent) +{ + struct buffer_head * bh; + struct ext3_super_block *es = 0; + struct ext3_sb_info *sbi = EXT3_SB(sb); + unsigned long sb_block = 1; + unsigned long logic_sb_block = 1; + unsigned long offset = 0; + unsigned long journal_inum = 0; + kdev_t dev = sb->s_dev; + int blocksize; + int hblock; + int db_count; + int i; + int needs_recovery; + +#ifdef CONFIG_JBD_DEBUG + ext3_ro_after = 0; +#endif + /* + * See what the current blocksize for the device is, and + * use that as the blocksize. Otherwise (or if the blocksize + * is smaller than the default) use the default. + * This is important for devices that have a hardware + * sectorsize that is larger than the default. + */ + blocksize = EXT3_MIN_BLOCK_SIZE; + hblock = get_hardsect_size(dev); + if (blocksize < hblock) + blocksize = hblock; + + sbi->s_mount_opt = 0; + sbi->s_resuid = EXT3_DEF_RESUID; + sbi->s_resgid = EXT3_DEF_RESGID; + if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) { + sb->s_dev = 0; + goto out_fail; + } + + set_blocksize (dev, blocksize); + + /* + * The ext3 superblock will not be buffer aligned for other than 1kB + * block sizes. We need to calculate the offset from buffer start. + */ + if (blocksize != EXT3_MIN_BLOCK_SIZE) { + logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; + offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; + } + + if (!(bh = bread (dev, logic_sb_block, blocksize))) { + printk (KERN_ERR "EXT3-fs: unable to read superblock\n"); + goto out_fail; + } + /* + * Note: s_es must be initialized as soon as possible because + * some ext3 macro-instructions depend on its value + */ + es = (struct ext3_super_block *) (((char *)bh->b_data) + offset); + sbi->s_es = es; + sb->s_magic = le16_to_cpu(es->s_magic); + if (sb->s_magic != EXT3_SUPER_MAGIC) { + if (!silent) + printk(KERN_ERR + "VFS: Can't find ext3 filesystem on dev %s.\n", + bdevname(dev)); + goto failed_mount; + } + if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV && + (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) || + EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) || + EXT3_HAS_INCOMPAT_FEATURE(sb, ~0U))) + printk(KERN_WARNING + "EXT3-fs warning: feature flags set on rev 0 fs, " + "running e2fsck is recommended\n"); + /* + * Check feature flags regardless of the revision level, since we + * previously didn't change the revision level when setting the flags, + * so there is a chance incompat flags are set on a rev 0 filesystem. + */ + if ((i = EXT3_HAS_INCOMPAT_FEATURE(sb, ~EXT3_FEATURE_INCOMPAT_SUPP))) { + printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of " + "unsupported optional features (%x).\n", + bdevname(dev), i); + goto failed_mount; + } + if (!(sb->s_flags & MS_RDONLY) && + (i = EXT3_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP))){ + printk(KERN_ERR "EXT3-fs: %s: couldn't mount RDWR because of " + "unsupported optional features (%x).\n", + bdevname(dev), i); + goto failed_mount; + } + sb->s_blocksize_bits = le32_to_cpu(es->s_log_block_size) + 10; + sb->s_blocksize = 1 << sb->s_blocksize_bits; + + if (sb->s_blocksize < EXT3_MIN_BLOCK_SIZE || + sb->s_blocksize > EXT3_MAX_BLOCK_SIZE) { + printk(KERN_ERR + "EXT3-fs: Unsupported filesystem blocksize %d on %s.\n", + blocksize, bdevname(dev)); + goto failed_mount; + } + + sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits); + + if (sb->s_blocksize != blocksize) { + blocksize = sb->s_blocksize; + + /* + * Make sure the blocksize for the filesystem is larger + * than the hardware sectorsize for the machine. + */ + if (sb->s_blocksize < hblock) { + printk(KERN_ERR "EXT3-fs: blocksize %d too small for " + "device blocksize %d.\n", blocksize, hblock); + goto failed_mount; + } + + brelse (bh); + set_blocksize (dev, sb->s_blocksize); + logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; + offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; + bh = bread (dev, logic_sb_block, blocksize); + if (!bh) { + printk(KERN_ERR + "EXT3-fs: Can't read superblock on 2nd try.\n"); + return NULL; + } + es = (struct ext3_super_block *)(((char *)bh->b_data) + offset); + sbi->s_es = es; + if (es->s_magic != le16_to_cpu(EXT3_SUPER_MAGIC)) { + printk (KERN_ERR + "EXT3-fs: Magic mismatch, very weird !\n"); + goto failed_mount; + } + } + + if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV) { + sbi->s_inode_size = EXT3_GOOD_OLD_INODE_SIZE; + sbi->s_first_ino = EXT3_GOOD_OLD_FIRST_INO; + } else { + sbi->s_inode_size = le16_to_cpu(es->s_inode_size); + sbi->s_first_ino = le32_to_cpu(es->s_first_ino); + if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) { + printk (KERN_ERR + "EXT3-fs: unsupported inode size: %d\n", + sbi->s_inode_size); + goto failed_mount; + } + } + sbi->s_frag_size = EXT3_MIN_FRAG_SIZE << + le32_to_cpu(es->s_log_frag_size); + if (blocksize != sbi->s_frag_size) { + printk(KERN_ERR + "EXT3-fs: fragsize %lu != blocksize %u (unsupported)\n", + sbi->s_frag_size, blocksize); + goto failed_mount; + } + sbi->s_frags_per_block = 1; + sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); + sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); + sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); + sbi->s_inodes_per_block = blocksize / EXT3_INODE_SIZE(sb); + sbi->s_itb_per_group = sbi->s_inodes_per_group /sbi->s_inodes_per_block; + sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc); + sbi->s_sbh = bh; + if (sbi->s_resuid == EXT3_DEF_RESUID) + sbi->s_resuid = le16_to_cpu(es->s_def_resuid); + if (sbi->s_resgid == EXT3_DEF_RESGID) + sbi->s_resgid = le16_to_cpu(es->s_def_resgid); + sbi->s_mount_state = le16_to_cpu(es->s_state); + sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb)); + sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb)); + + if (sbi->s_blocks_per_group > blocksize * 8) { + printk (KERN_ERR + "EXT3-fs: #blocks per group too big: %lu\n", + sbi->s_blocks_per_group); + goto failed_mount; + } + if (sbi->s_frags_per_group > blocksize * 8) { + printk (KERN_ERR + "EXT3-fs: #fragments per group too big: %lu\n", + sbi->s_frags_per_group); + goto failed_mount; + } + if (sbi->s_inodes_per_group > blocksize * 8) { + printk (KERN_ERR + "EXT3-fs: #inodes per group too big: %lu\n", + sbi->s_inodes_per_group); + goto failed_mount; + } + + sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) - + le32_to_cpu(es->s_first_data_block) + + EXT3_BLOCKS_PER_GROUP(sb) - 1) / + EXT3_BLOCKS_PER_GROUP(sb); + db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) / + EXT3_DESC_PER_BLOCK(sb); + sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), + GFP_KERNEL); + if (sbi->s_group_desc == NULL) { + printk (KERN_ERR "EXT3-fs: not enough memory\n"); + goto failed_mount; + } + for (i = 0; i < db_count; i++) { + sbi->s_group_desc[i] = bread(dev, logic_sb_block + i + 1, + blocksize); + if (!sbi->s_group_desc[i]) { + printk (KERN_ERR "EXT3-fs: " + "can't read group descriptor %d\n", i); + db_count = i; + goto failed_mount2; + } + } + if (!ext3_check_descriptors (sb)) { + printk (KERN_ERR "EXT3-fs: group descriptors corrupted !\n"); + goto failed_mount2; + } + for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++) { + sbi->s_inode_bitmap_number[i] = 0; + sbi->s_inode_bitmap[i] = NULL; + sbi->s_block_bitmap_number[i] = 0; + sbi->s_block_bitmap[i] = NULL; + } + sbi->s_loaded_inode_bitmaps = 0; + sbi->s_loaded_block_bitmaps = 0; + sbi->s_gdb_count = db_count; + /* + * set up enough so that it can read an inode + */ + sb->s_op = &ext3_sops; + INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ + + sb->s_root = 0; + + needs_recovery = (es->s_last_orphan != 0 || + EXT3_HAS_INCOMPAT_FEATURE(sb, + EXT3_FEATURE_INCOMPAT_RECOVER)); + + /* + * The first inode we look at is the journal inode. Don't try + * root first: it may be modified in the journal! + */ + if (!test_opt(sb, NOLOAD) && + EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { + if (ext3_load_journal(sb, es)) + goto failed_mount2; + } else if (journal_inum) { + if (ext3_create_journal(sb, es, journal_inum)) + goto failed_mount2; + } else { + if (!silent) + printk (KERN_ERR + "ext3: No journal on filesystem on %s\n", + bdevname(dev)); + goto failed_mount2; + } + + /* We have now updated the journal if required, so we can + * validate the data journaling mode. */ + switch (test_opt(sb, DATA_FLAGS)) { + case 0: + /* No mode set, assume a default based on the journal + capabilities: ORDERED_DATA if the journal can + cope, else JOURNAL_DATA */ + if (journal_check_available_features + (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) + set_opt(sbi->s_mount_opt, ORDERED_DATA); + else + set_opt(sbi->s_mount_opt, JOURNAL_DATA); + break; + + case EXT3_MOUNT_ORDERED_DATA: + case EXT3_MOUNT_WRITEBACK_DATA: + if (!journal_check_available_features + (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) { + printk(KERN_ERR "EXT3-fs: Journal does not support " + "requested data journaling mode\n"); + goto failed_mount3; + } + default: + break; + } + + /* + * The journal_load will have done any necessary log recovery, + * so we can safely mount the rest of the filesystem now. + */ + + sb->s_root = d_alloc_root(iget(sb, EXT3_ROOT_INO)); + if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) || + !sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) { + if (sb->s_root) { + dput(sb->s_root); + sb->s_root = NULL; + printk(KERN_ERR + "EXT3-fs: corrupt root inode, run e2fsck\n"); + } else + printk(KERN_ERR "EXT3-fs: get root inode failed\n"); + goto failed_mount3; + } + + ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY); + /* + * akpm: core read_super() calls in here with the superblock locked. + * That deadlocks, because orphan cleanup needs to lock the superblock + * in numerous places. Here we just pop the lock - it's relatively + * harmless, because we are now ready to accept write_super() requests, + * and aviro says that's the only reason for hanging onto the + * superblock lock. + */ + EXT3_SB(sb)->s_mount_state |= EXT3_ORPHAN_FS; + unlock_super(sb); /* akpm: sigh */ + ext3_orphan_cleanup(sb, es); + lock_super(sb); + EXT3_SB(sb)->s_mount_state &= ~EXT3_ORPHAN_FS; + if (needs_recovery) + printk (KERN_INFO "EXT3-fs: recovery complete.\n"); + ext3_mark_recovery_complete(sb, es); + printk (KERN_INFO "EXT3-fs: mounted filesystem with %s data mode.\n", + test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal": + test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": + "writeback"); + + return sb; + +failed_mount3: + journal_destroy(sbi->s_journal); +failed_mount2: + for (i = 0; i < db_count; i++) + brelse(sbi->s_group_desc[i]); + kfree(sbi->s_group_desc); +failed_mount: + ext3_blkdev_remove(sbi); + brelse(bh); +out_fail: + return NULL; +} + +static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum) +{ + struct inode *journal_inode; + journal_t *journal; + + /* First, test for the existence of a valid inode on disk. Bad + * things happen if we iget() an unused inode, as the subsequent + * iput() will try to delete it. */ + + journal_inode = iget(sb, journal_inum); + if (!journal_inode) { + printk(KERN_ERR "EXT3-fs: no journal found.\n"); + return NULL; + } + if (!journal_inode->i_nlink) { + make_bad_inode(journal_inode); + iput(journal_inode); + printk(KERN_ERR "EXT3-fs: journal inode is deleted.\n"); + return NULL; + } + + jbd_debug(2, "Journal inode found at %p: %Ld bytes\n", + journal_inode, journal_inode->i_size); + if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) { + printk(KERN_ERR "EXT3-fs: invalid journal inode.\n"); + iput(journal_inode); + return NULL; + } + + journal = journal_init_inode(journal_inode); + if (!journal) + iput(journal_inode); + return journal; +} + +static journal_t *ext3_get_dev_journal(struct super_block *sb, + int dev) +{ + struct buffer_head * bh; + journal_t *journal; + int start; + int len; + int hblock, blocksize; + unsigned long sb_block; + unsigned long offset; + kdev_t journal_dev = to_kdev_t(dev); + struct ext3_super_block * es; + struct block_device *bdev; + + bdev = ext3_blkdev_get(journal_dev); + if (bdev == NULL) + return NULL; + + blocksize = sb->s_blocksize; + hblock = get_hardsect_size(journal_dev); + if (blocksize < hblock) { + printk(KERN_ERR + "EXT3-fs: blocksize too small for journal device.\n"); + goto out_bdev; + } + + sb_block = EXT3_MIN_BLOCK_SIZE / blocksize; + offset = EXT3_MIN_BLOCK_SIZE % blocksize; + set_blocksize(dev, blocksize); + if (!(bh = bread(dev, sb_block, blocksize))) { + printk(KERN_ERR "EXT3-fs: couldn't read superblock of " + "external journal\n"); + goto out_bdev; + } + + es = (struct ext3_super_block *) (((char *)bh->b_data) + offset); + if ((le16_to_cpu(es->s_magic) != EXT3_SUPER_MAGIC) || + !(le32_to_cpu(es->s_feature_incompat) & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { + printk(KERN_ERR "EXT3-fs: external journal has " + "bad superblock\n"); + brelse(bh); + goto out_bdev; + } + + if (memcmp(EXT3_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) { + printk(KERN_ERR "EXT3-fs: journal UUID does not match\n"); + brelse(bh); + goto out_bdev; + } + + len = le32_to_cpu(es->s_blocks_count); + start = sb_block + 1; + brelse(bh); /* we're done with the superblock */ + + journal = journal_init_dev(journal_dev, sb->s_dev, + start, len, blocksize); + if (!journal) { + printk(KERN_ERR "EXT3-fs: failed to create device journal\n"); + goto out_bdev; + } + ll_rw_block(READ, 1, &journal->j_sb_buffer); + wait_on_buffer(journal->j_sb_buffer); + if (!buffer_uptodate(journal->j_sb_buffer)) { + printk(KERN_ERR "EXT3-fs: I/O error on journal device\n"); + goto out_journal; + } + if (ntohl(journal->j_superblock->s_nr_users) != 1) { + printk(KERN_ERR "EXT3-fs: External journal has more than one " + "user (unsupported) - %d\n", + ntohl(journal->j_superblock->s_nr_users)); + goto out_journal; + } + EXT3_SB(sb)->journal_bdev = bdev; + return journal; +out_journal: + journal_destroy(journal); +out_bdev: + ext3_blkdev_put(bdev); + return NULL; +} + +static int ext3_load_journal(struct super_block * sb, + struct ext3_super_block * es) +{ + journal_t *journal; + int journal_inum = le32_to_cpu(es->s_journal_inum); + int journal_dev = le32_to_cpu(es->s_journal_dev); + int err; + int really_read_only; + + really_read_only = is_read_only(sb->s_dev); + + /* + * Are we loading a blank journal or performing recovery after a + * crash? For recovery, we need to check in advance whether we + * can get read-write access to the device. + */ + + if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) { + if (sb->s_flags & MS_RDONLY) { + printk(KERN_INFO "EXT3-fs: INFO: recovery " + "required on readonly filesystem.\n"); + if (really_read_only) { + printk(KERN_ERR "EXT3-fs: write access " + "unavailable, cannot proceed.\n"); + return -EROFS; + } + printk (KERN_INFO "EXT3-fs: write access will " + "be enabled during recovery.\n"); + } + } + + if (journal_inum && journal_dev) { + printk(KERN_ERR "EXT3-fs: filesystem has both journal " + "and inode journals!\n"); + return -EINVAL; + } + + if (journal_inum) { + if (!(journal = ext3_get_journal(sb, journal_inum))) + return -EINVAL; + } else { + if (!(journal = ext3_get_dev_journal(sb, journal_dev))) + return -EINVAL; + } + + + if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) { + err = journal_update_format(journal); + if (err) { + printk(KERN_ERR "EXT3-fs: error updating journal.\n"); + journal_destroy(journal); + return err; + } + } + + if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) + journal_wipe(journal, !really_read_only); + + err = journal_load(journal); + if (err) { + printk(KERN_ERR "EXT3-fs: error loading journal.\n"); + journal_destroy(journal); + return err; + } + + EXT3_SB(sb)->s_journal = journal; + ext3_clear_journal_err(sb, es); + return 0; +} + +static int ext3_create_journal(struct super_block * sb, + struct ext3_super_block * es, + int journal_inum) +{ + journal_t *journal; + + if (sb->s_flags & MS_RDONLY) { + printk(KERN_ERR "EXT3-fs: readonly filesystem when trying to " + "create journal.\n"); + return -EROFS; + } + + if (!(journal = ext3_get_journal(sb, journal_inum))) + return -EINVAL; + + printk(KERN_INFO "EXT3-fs: creating new journal on inode %d\n", + journal_inum); + + if (journal_create(journal)) { + printk(KERN_ERR "EXT3-fs: error creating journal.\n"); + journal_destroy(journal); + return -EIO; + } + + EXT3_SB(sb)->s_journal = journal; + + ext3_update_dynamic_rev(sb); + EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL); + + es->s_journal_inum = cpu_to_le32(journal_inum); + sb->s_dirt = 1; + + /* Make sure we flush the recovery flag to disk. */ + ext3_commit_super(sb, es, 1); + + return 0; +} + +static void ext3_commit_super (struct super_block * sb, + struct ext3_super_block * es, + int sync) +{ + es->s_wtime = cpu_to_le32(CURRENT_TIME); + BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "marking dirty"); + mark_buffer_dirty(sb->u.ext3_sb.s_sbh); + if (sync) { + ll_rw_block(WRITE, 1, &sb->u.ext3_sb.s_sbh); + wait_on_buffer(sb->u.ext3_sb.s_sbh); + } +} + + +/* + * Have we just finished recovery? If so, and if we are mounting (or + * remounting) the filesystem readonly, then we will end up with a + * consistent fs on disk. Record that fact. + */ +static void ext3_mark_recovery_complete(struct super_block * sb, + struct ext3_super_block * es) +{ + journal_flush(EXT3_SB(sb)->s_journal); + if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) && + sb->s_flags & MS_RDONLY) { + EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + sb->s_dirt = 0; + ext3_commit_super(sb, es, 1); + } +} + +/* + * If we are mounting (or read-write remounting) a filesystem whose journal + * has recorded an error from a previous lifetime, move that error to the + * main filesystem now. + */ +static void ext3_clear_journal_err(struct super_block * sb, + struct ext3_super_block * es) +{ + journal_t *journal; + int j_errno; + const char *errstr; + + journal = EXT3_SB(sb)->s_journal; + + /* + * Now check for any error status which may have been recorded in the + * journal by a prior ext3_error() or ext3_abort() + */ + + j_errno = journal_errno(journal); + if (j_errno) { + char nbuf[16]; + + errstr = ext3_decode_error(sb, j_errno, nbuf); + ext3_warning(sb, __FUNCTION__, "Filesystem error recorded " + "from previous mount: %s", errstr); + ext3_warning(sb, __FUNCTION__, "Marking fs in need of " + "filesystem check."); + + sb->u.ext3_sb.s_mount_state |= EXT3_ERROR_FS; + es->s_state |= cpu_to_le16(EXT3_ERROR_FS); + ext3_commit_super (sb, es, 1); + + journal_clear_err(journal); + } +} + +/* + * Force the running and committing transactions to commit, + * and wait on the commit. + */ +int ext3_force_commit(struct super_block *sb) +{ + journal_t *journal; + int ret; + + if (sb->s_flags & MS_RDONLY) + return 0; + + journal = EXT3_SB(sb)->s_journal; + sb->s_dirt = 0; + lock_kernel(); /* important: lock down j_running_transaction */ + ret = ext3_journal_force_commit(journal); + unlock_kernel(); + return ret; +} + +/* + * Ext3 always journals updates to the superblock itself, so we don't + * have to propagate any other updates to the superblock on disk at this + * point. Just start an async writeback to get the buffers on their way + * to the disk. + * + * This implicitly triggers the writebehind on sync(). + */ + +static int do_sync_supers = 0; +MODULE_PARM(do_sync_supers, "i"); +MODULE_PARM_DESC(do_sync_supers, "Write superblocks synchronously"); + +void ext3_write_super (struct super_block * sb) +{ + tid_t target; + + if (down_trylock(&sb->s_lock) == 0) + BUG(); /* aviro detector */ + sb->s_dirt = 0; + target = log_start_commit(EXT3_SB(sb)->s_journal, NULL); + + if (do_sync_supers) { + unlock_super(sb); + log_wait_commit(EXT3_SB(sb)->s_journal, target); + lock_super(sb); + } +} + +/* + * LVM calls this function before a (read-only) snapshot is created. This + * gives us a chance to flush the journal completely and mark the fs clean. + */ +void ext3_write_super_lockfs(struct super_block *sb) +{ + sb->s_dirt = 0; + + lock_kernel(); /* 2.4.5 forgot to do this for us */ + if (!(sb->s_flags & MS_RDONLY)) { + journal_t *journal = EXT3_SB(sb)->s_journal; + + /* Now we set up the journal barrier. */ + journal_lock_updates(journal); + journal_flush(journal); + + /* Journal blocked and flushed, clear needs_recovery flag. */ + EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); + } + unlock_kernel(); +} + +/* + * Called by LVM after the snapshot is done. We need to reset the RECOVER + * flag here, even though the filesystem is not technically dirty yet. + */ +void ext3_unlockfs(struct super_block *sb) +{ + if (!(sb->s_flags & MS_RDONLY)) { + lock_kernel(); + lock_super(sb); + /* Reser the needs_recovery flag before the fs is unlocked. */ + EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); + ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); + unlock_super(sb); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + unlock_kernel(); + } +} + +int ext3_remount (struct super_block * sb, int * flags, char * data) +{ + struct ext3_super_block * es; + struct ext3_sb_info *sbi = EXT3_SB(sb); + unsigned long tmp; + + clear_ro_after(sb); + + /* + * Allow the "check" option to be passed as a remount option. + */ + if (!parse_options(data, &tmp, sbi, &tmp, 1)) + return -EINVAL; + + if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) + ext3_abort(sb, __FUNCTION__, "Abort forced by user"); + + es = sbi->s_es; + + if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { + if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) + return -EROFS; + + if (*flags & MS_RDONLY) { + /* + * First of all, the unconditional stuff we have to do + * to disable replay of the journal when we next remount + */ + sb->s_flags |= MS_RDONLY; + + /* + * OK, test if we are remounting a valid rw partition + * readonly, and if so set the rdonly flag and then + * mark the partition as valid again. + */ + if (!(es->s_state & cpu_to_le16(EXT3_VALID_FS)) && + (sbi->s_mount_state & EXT3_VALID_FS)) + es->s_state = cpu_to_le16(sbi->s_mount_state); + + ext3_mark_recovery_complete(sb, es); + } else { + int ret; + if ((ret = EXT3_HAS_RO_COMPAT_FEATURE(sb, + ~EXT3_FEATURE_RO_COMPAT_SUPP))) { + printk(KERN_WARNING "EXT3-fs: %s: couldn't " + "remount RDWR because of unsupported " + "optional features (%x).\n", + bdevname(sb->s_dev), ret); + return -EROFS; + } + /* + * Mounting a RDONLY partition read-write, so reread + * and store the current valid flag. (It may have + * been changed by e2fsck since we originally mounted + * the partition.) + */ + ext3_clear_journal_err(sb, es); + sbi->s_mount_state = le16_to_cpu(es->s_state); + if (!ext3_setup_super (sb, es, 0)) + sb->s_flags &= ~MS_RDONLY; + } + } + setup_ro_after(sb); + return 0; +} + +int ext3_statfs (struct super_block * sb, struct statfs * buf) +{ + struct ext3_super_block *es = EXT3_SB(sb)->s_es; + unsigned long overhead; + int i; + + if (test_opt (sb, MINIX_DF)) + overhead = 0; + else { + /* + * Compute the overhead (FS structures) + */ + + /* + * All of the blocks before first_data_block are + * overhead + */ + overhead = le32_to_cpu(es->s_first_data_block); + + /* + * Add the overhead attributed to the superblock and + * block group descriptors. If the sparse superblocks + * feature is turned on, then not all groups have this. + */ + for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) + overhead += ext3_bg_has_super(sb, i) + + ext3_bg_num_gdb(sb, i); + + /* + * Every block group has an inode bitmap, a block + * bitmap, and an inode table. + */ + overhead += (EXT3_SB(sb)->s_groups_count * + (2 + EXT3_SB(sb)->s_itb_per_group)); + } + + buf->f_type = EXT3_SUPER_MAGIC; + buf->f_bsize = sb->s_blocksize; + buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead; + buf->f_bfree = ext3_count_free_blocks (sb); + buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count); + if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count)) + buf->f_bavail = 0; + buf->f_files = le32_to_cpu(es->s_inodes_count); + buf->f_ffree = ext3_count_free_inodes (sb); + buf->f_namelen = EXT3_NAME_LEN; + return 0; +} + +static DECLARE_FSTYPE_DEV(ext3_fs_type, "ext3", ext3_read_super); + +static int __init init_ext3_fs(void) +{ + return register_filesystem(&ext3_fs_type); +} + +static void __exit exit_ext3_fs(void) +{ + unregister_filesystem(&ext3_fs_type); +} + +EXPORT_NO_SYMBOLS; + +MODULE_LICENSE("GPL"); +module_init(init_ext3_fs) +module_exit(exit_ext3_fs) diff -u --recursive --new-file v2.4.14/linux/fs/ext3/symlink.c linux/fs/ext3/symlink.c --- v2.4.14/linux/fs/ext3/symlink.c Wed Dec 31 16:00:00 1969 +++ linux/fs/ext3/symlink.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,39 @@ +/* + * linux/fs/ext3/symlink.c + * + * Only fast symlinks left here - the rest is done by generic code. AV, 1999 + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/symlink.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext3 symlink handling code + */ + +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/ext3_fs.h> + +static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + char *s = (char *)dentry->d_inode->u.ext3_i.i_data; + return vfs_readlink(dentry, buffer, buflen, s); +} + +static int ext3_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + char *s = (char *)dentry->d_inode->u.ext3_i.i_data; + return vfs_follow_link(nd, s); +} + +struct inode_operations ext3_fast_symlink_inode_operations = { + readlink: ext3_readlink, /* BKL not held. Don't need */ + follow_link: ext3_follow_link, /* BKL not held. Don't need */ +}; diff -u --recursive --new-file v2.4.14/linux/fs/freevxfs/vxfs_subr.c linux/fs/freevxfs/vxfs_subr.c --- v2.4.14/linux/fs/freevxfs/vxfs_subr.c Mon May 21 12:31:06 2001 +++ linux/fs/freevxfs/vxfs_subr.c Fri Nov 9 14:25:35 2001 @@ -45,7 +45,8 @@ struct address_space_operations vxfs_aops = { .readpage = vxfs_readpage, - .bmap = vxfs_bmap + .bmap = vxfs_bmap, + .sync_page = block_sync_page, }; diff -u --recursive --new-file v2.4.14/linux/fs/isofs/compress.c linux/fs/isofs/compress.c --- v2.4.14/linux/fs/isofs/compress.c Mon Nov 5 15:55:33 2001 +++ linux/fs/isofs/compress.c Tue Nov 6 08:34:40 2001 @@ -44,9 +44,6 @@ #include "zisofs.h" -#define min(a,b) ((a)<(b)?(a):(b)) -#define max(a,b) ((a)>(b)?(a):(b)) - /* This should probably be global. */ static char zisofs_sink_page[PAGE_CACHE_SIZE]; diff -u --recursive --new-file v2.4.14/linux/fs/jbd/Makefile linux/fs/jbd/Makefile --- v2.4.14/linux/fs/jbd/Makefile Wed Dec 31 16:00:00 1969 +++ linux/fs/jbd/Makefile Fri Nov 9 14:25:04 2001 @@ -0,0 +1,15 @@ +# +# fs/jbd/Makefile +# +# Makefile for the linux journaling routines. +# + +export-objs := journal.o +O_TARGET := jbd.o + +obj-y := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o + +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make + diff -u --recursive --new-file v2.4.14/linux/fs/jbd/checkpoint.c linux/fs/jbd/checkpoint.c --- v2.4.14/linux/fs/jbd/checkpoint.c Wed Dec 31 16:00:00 1969 +++ linux/fs/jbd/checkpoint.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,608 @@ +/* + * linux/fs/checkpoint.c + * + * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 + * + * Copyright 1999 Red Hat Software --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Checkpoint routines for the generic filesystem journaling code. + * Part of the ext2fs journaling system. + * + * Checkpointing is the process of ensuring that a section of the log is + * committed fully to disk, so that that portion of the log can be + * reused. + */ + +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/locks.h> + +extern spinlock_t journal_datalist_lock; + +/* + * Unlink a buffer from a transaction. + * + * Called with journal_datalist_lock held. + */ + +static inline void __buffer_unlink(struct journal_head *jh) +{ + transaction_t *transaction; + + transaction = jh->b_cp_transaction; + jh->b_cp_transaction = NULL; + + jh->b_cpnext->b_cpprev = jh->b_cpprev; + jh->b_cpprev->b_cpnext = jh->b_cpnext; + if (transaction->t_checkpoint_list == jh) + transaction->t_checkpoint_list = jh->b_cpnext; + if (transaction->t_checkpoint_list == jh) + transaction->t_checkpoint_list = NULL; +} + +/* + * Try to release a checkpointed buffer from its transaction. + * Returns 1 if we released it. + * Requires journal_datalist_lock + */ +static int __try_to_free_cp_buf(struct journal_head *jh) +{ + int ret = 0; + struct buffer_head *bh = jh2bh(jh); + + if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) { + JBUFFER_TRACE(jh, "remove from checkpoint list"); + __journal_remove_checkpoint(jh); + __journal_remove_journal_head(bh); + BUFFER_TRACE(bh, "release"); + /* BUF_LOCKED -> BUF_CLEAN (fwiw) */ + refile_buffer(bh); + __brelse(bh); + ret = 1; + } + return ret; +} + +/* + * log_wait_for_space: wait until there is space in the journal. + * + * Called with the journal already locked, but it will be unlocked if we have + * to wait for a checkpoint to free up some space in the log. + */ + +void log_wait_for_space(journal_t *journal, int nblocks) +{ + while (log_space_left(journal) < nblocks) { + if (journal->j_flags & JFS_ABORT) + return; + unlock_journal(journal); + down(&journal->j_checkpoint_sem); + lock_journal(journal); + + /* Test again, another process may have checkpointed + * while we were waiting for the checkpoint lock */ + if (log_space_left(journal) < nblocks) { + log_do_checkpoint(journal, nblocks); + } + up(&journal->j_checkpoint_sem); + } +} + +/* + * Clean up a transaction's checkpoint list. + * + * We wait for any pending IO to complete and make sure any clean + * buffers are removed from the transaction. + * + * Return 1 if we performed any actions which might have destroyed the + * checkpoint. (journal_remove_checkpoint() deletes the transaction when + * the last checkpoint buffer is cleansed) + * + * Called with the journal locked. + * Called with journal_datalist_lock held. + */ +static int __cleanup_transaction(journal_t *journal, transaction_t *transaction) +{ + struct journal_head *jh, *next_jh, *last_jh; + struct buffer_head *bh; + int ret = 0; + + assert_spin_locked(&journal_datalist_lock); + jh = transaction->t_checkpoint_list; + if (!jh) + return 0; + + last_jh = jh->b_cpprev; + next_jh = jh; + do { + jh = next_jh; + bh = jh2bh(jh); + if (buffer_locked(bh)) { + atomic_inc(&bh->b_count); + spin_unlock(&journal_datalist_lock); + unlock_journal(journal); + wait_on_buffer(bh); + /* the journal_head may have gone by now */ + BUFFER_TRACE(bh, "brelse"); + __brelse(bh); + goto out_return_1; + } + + if (jh->b_transaction != NULL) { + transaction_t *transaction = jh->b_transaction; + tid_t tid = transaction->t_tid; + + spin_unlock(&journal_datalist_lock); + log_start_commit(journal, transaction); + unlock_journal(journal); + log_wait_commit(journal, tid); + goto out_return_1; + } + + /* + * We used to test for (jh->b_list != BUF_CLEAN) here. + * But unmap_underlying_metadata() can place buffer onto + * BUF_CLEAN. Since refile_buffer() no longer takes buffers + * off checkpoint lists, we cope with it here + */ + /* + * AKPM: I think the buffer_jdirty test is redundant - it + * shouldn't have NULL b_transaction? + */ + next_jh = jh->b_cpnext; + if (!buffer_dirty(bh) && !buffer_jdirty(bh)) { + BUFFER_TRACE(bh, "remove from checkpoint"); + __journal_remove_checkpoint(jh); + __journal_remove_journal_head(bh); + refile_buffer(bh); + __brelse(bh); + ret = 1; + } + + jh = next_jh; + } while (jh != last_jh); + + return ret; +out_return_1: + lock_journal(journal); + spin_lock(&journal_datalist_lock); + return 1; +} + +#define NR_BATCH 64 + +static void __flush_batch(struct buffer_head **bhs, int *batch_count) +{ + int i; + + spin_unlock(&journal_datalist_lock); + ll_rw_block(WRITE, *batch_count, bhs); + run_task_queue(&tq_disk); + spin_lock(&journal_datalist_lock); + for (i = 0; i < *batch_count; i++) { + struct buffer_head *bh = bhs[i]; + clear_bit(BH_JWrite, &bh->b_state); + BUFFER_TRACE(bh, "brelse"); + __brelse(bh); + } + *batch_count = 0; +} + +/* + * Try to flush one buffer from the checkpoint list to disk. + * + * Return 1 if something happened which requires us to abort the current + * scan of the checkpoint list. + * + * Called with journal_datalist_lock held. + */ +static int __flush_buffer(journal_t *journal, struct journal_head *jh, + struct buffer_head **bhs, int *batch_count, + int *drop_count) +{ + struct buffer_head *bh = jh2bh(jh); + int ret = 0; + + if (buffer_dirty(bh) && !buffer_locked(bh) && jh->b_jlist == BJ_None) { + J_ASSERT_JH(jh, jh->b_transaction == NULL); + + /* + * Important: we are about to write the buffer, and + * possibly block, while still holding the journal lock. + * We cannot afford to let the transaction logic start + * messing around with this buffer before we write it to + * disk, as that would break recoverability. + */ + BUFFER_TRACE(bh, "queue"); + atomic_inc(&bh->b_count); + J_ASSERT_BH(bh, !test_bit(BH_JWrite, &bh->b_state)); + set_bit(BH_JWrite, &bh->b_state); + bhs[*batch_count] = bh; + (*batch_count)++; + if (*batch_count == NR_BATCH) { + __flush_batch(bhs, batch_count); + ret = 1; + } + } else { + int last_buffer = 0; + if (jh->b_cpnext == jh) { + /* We may be about to drop the transaction. Tell the + * caller that the lists have changed. + */ + last_buffer = 1; + } + if (__try_to_free_cp_buf(jh)) { + (*drop_count)++; + ret = last_buffer; + } + } + return ret; +} + + +/* + * Perform an actual checkpoint. We don't write out only enough to + * satisfy the current blocked requests: rather we submit a reasonably + * sized chunk of the outstanding data to disk at once for + * efficiency. log_wait_for_space() will retry if we didn't free enough. + * + * However, we _do_ take into account the amount requested so that once + * the IO has been queued, we can return as soon as enough of it has + * completed to disk. + * + * The journal should be locked before calling this function. + */ + +/* @@@ `nblocks' is unused. Should it be used? */ +int log_do_checkpoint (journal_t *journal, int nblocks) +{ + transaction_t *transaction, *last_transaction, *next_transaction; + int result; + int target; + int batch_count = 0; + struct buffer_head *bhs[NR_BATCH]; + + jbd_debug(1, "Start checkpoint\n"); + + /* + * First thing: if there are any transactions in the log which + * don't need checkpointing, just eliminate them from the + * journal straight away. + */ + result = cleanup_journal_tail(journal); + jbd_debug(1, "cleanup_journal_tail returned %d\n", result); + if (result <= 0) + return result; + + /* + * OK, we need to start writing disk blocks. Try to free up a + * quarter of the log in a single checkpoint if we can. + */ + /* + * AKPM: check this code. I had a feeling a while back that it + * degenerates into a busy loop at unmount time. + */ + target = (journal->j_last - journal->j_first) / 4; + + spin_lock(&journal_datalist_lock); +repeat: + transaction = journal->j_checkpoint_transactions; + if (transaction == NULL) + goto done; + last_transaction = transaction->t_cpprev; + next_transaction = transaction; + + do { + struct journal_head *jh, *last_jh, *next_jh; + int drop_count = 0; + int cleanup_ret, retry = 0; + + transaction = next_transaction; + next_transaction = transaction->t_cpnext; + jh = transaction->t_checkpoint_list; + last_jh = jh->b_cpprev; + next_jh = jh; + do { + jh = next_jh; + next_jh = jh->b_cpnext; + retry = __flush_buffer(journal, jh, bhs, &batch_count, + &drop_count); + } while (jh != last_jh && !retry); + if (batch_count) { + __flush_batch(bhs, &batch_count); + goto repeat; + } + if (retry) + goto repeat; + /* + * We have walked the whole transaction list without + * finding anything to write to disk. We had better be + * able to make some progress or we are in trouble. + */ + cleanup_ret = __cleanup_transaction(journal, transaction); + J_ASSERT(drop_count != 0 || cleanup_ret != 0); + goto repeat; /* __cleanup may have dropped lock */ + } while (transaction != last_transaction); + +done: + spin_unlock(&journal_datalist_lock); + result = cleanup_journal_tail(journal); + if (result < 0) + return result; + + return 0; +} + +/* + * Check the list of checkpoint transactions for the journal to see if + * we have already got rid of any since the last update of the log tail + * in the journal superblock. If so, we can instantly roll the + * superblock forward to remove those transactions from the log. + * + * Return <0 on error, 0 on success, 1 if there was nothing to clean up. + * + * Called with the journal lock held. + * + * This is the only part of the journaling code which really needs to be + * aware of transaction aborts. Checkpointing involves writing to the + * main filesystem area rather than to the journal, so it can proceed + * even in abort state, but we must not update the journal superblock if + * we have an abort error outstanding. + */ + +int cleanup_journal_tail(journal_t *journal) +{ + transaction_t * transaction; + tid_t first_tid; + unsigned long blocknr, freed; + + /* OK, work out the oldest transaction remaining in the log, and + * the log block it starts at. + * + * If the log is now empty, we need to work out which is the + * next transaction ID we will write, and where it will + * start. */ + + /* j_checkpoint_transactions needs locking */ + spin_lock(&journal_datalist_lock); + transaction = journal->j_checkpoint_transactions; + if (transaction) { + first_tid = transaction->t_tid; + blocknr = transaction->t_log_start; + } else if ((transaction = journal->j_committing_transaction) != NULL) { + first_tid = transaction->t_tid; + blocknr = transaction->t_log_start; + } else if ((transaction = journal->j_running_transaction) != NULL) { + first_tid = transaction->t_tid; + blocknr = journal->j_head; + } else { + first_tid = journal->j_transaction_sequence; + blocknr = journal->j_head; + } + spin_unlock(&journal_datalist_lock); + J_ASSERT (blocknr != 0); + + /* If the oldest pinned transaction is at the tail of the log + already then there's not much we can do right now. */ + if (journal->j_tail_sequence == first_tid) + return 1; + + /* OK, update the superblock to recover the freed space. + * Physical blocks come first: have we wrapped beyond the end of + * the log? */ + freed = blocknr - journal->j_tail; + if (blocknr < journal->j_tail) + freed = freed + journal->j_last - journal->j_first; + + jbd_debug(1, + "Cleaning journal tail from %d to %d (offset %lu), " + "freeing %lu\n", + journal->j_tail_sequence, first_tid, blocknr, freed); + + journal->j_free += freed; + journal->j_tail_sequence = first_tid; + journal->j_tail = blocknr; + if (!(journal->j_flags & JFS_ABORT)) + journal_update_superblock(journal, 1); + return 0; +} + + +/* Checkpoint list management */ + +/* + * journal_clean_checkpoint_list + * + * Find all the written-back checkpoint buffers in the journal and release them. + * + * Called with the journal locked. + * Called with journal_datalist_lock held. + * Returns number of bufers reaped (for debug) + */ + +int __journal_clean_checkpoint_list(journal_t *journal) +{ + transaction_t *transaction, *last_transaction, *next_transaction; + int ret = 0; + + transaction = journal->j_checkpoint_transactions; + if (transaction == 0) + goto out; + + last_transaction = transaction->t_cpprev; + next_transaction = transaction; + do { + struct journal_head *jh; + + transaction = next_transaction; + next_transaction = transaction->t_cpnext; + jh = transaction->t_checkpoint_list; + if (jh) { + struct journal_head *last_jh = jh->b_cpprev; + struct journal_head *next_jh = jh; + do { + struct buffer_head *bh; + + jh = next_jh; + next_jh = jh->b_cpnext; + bh = jh2bh(jh); + ret += __try_to_free_cp_buf(jh); + } while (jh != last_jh); + } + } while (transaction != last_transaction); +out: + return ret; +} + +/* + * journal_remove_checkpoint: called after a buffer has been committed + * to disk (either by being write-back flushed to disk, or being + * committed to the log). + * + * We cannot safely clean a transaction out of the log until all of the + * buffer updates committed in that transaction have safely been stored + * elsewhere on disk. To achieve this, all of the buffers in a + * transaction need to be maintained on the transaction's checkpoint + * list until they have been rewritten, at which point this function is + * called to remove the buffer from the existing transaction's + * checkpoint list. + * + * This function is called with the journal locked. + * This function is called with journal_datalist_lock held. + */ + +void __journal_remove_checkpoint(struct journal_head *jh) +{ + transaction_t *transaction; + journal_t *journal; + + JBUFFER_TRACE(jh, "entry"); + + if ((transaction = jh->b_cp_transaction) == NULL) { + JBUFFER_TRACE(jh, "not on transaction"); + goto out; + } + + journal = transaction->t_journal; + + __buffer_unlink(jh); + + if (transaction->t_checkpoint_list != NULL) + goto out; + JBUFFER_TRACE(jh, "transaction has no more buffers"); + + /* There is one special case to worry about: if we have just + pulled the buffer off a committing transaction's forget list, + then even if the checkpoint list is empty, the transaction + obviously cannot be dropped! */ + + if (transaction == journal->j_committing_transaction) { + JBUFFER_TRACE(jh, "belongs to committing transaction"); + goto out; + } + + /* OK, that was the last buffer for the transaction: we can now + safely remove this transaction from the log */ + + __journal_drop_transaction(journal, transaction); + + /* Just in case anybody was waiting for more transactions to be + checkpointed... */ + wake_up(&journal->j_wait_logspace); +out: + JBUFFER_TRACE(jh, "exit"); +} + +void journal_remove_checkpoint(struct journal_head *jh) +{ + spin_lock(&journal_datalist_lock); + __journal_remove_checkpoint(jh); + spin_unlock(&journal_datalist_lock); +} + +/* + * journal_insert_checkpoint: put a committed buffer onto a checkpoint + * list so that we know when it is safe to clean the transaction out of + * the log. + * + * Called with the journal locked. + * Called with journal_datalist_lock held. + */ +void __journal_insert_checkpoint(struct journal_head *jh, + transaction_t *transaction) +{ + JBUFFER_TRACE(jh, "entry"); + J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jdirty(jh2bh(jh))); + J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); + + assert_spin_locked(&journal_datalist_lock); + jh->b_cp_transaction = transaction; + + if (!transaction->t_checkpoint_list) { + jh->b_cpnext = jh->b_cpprev = jh; + } else { + jh->b_cpnext = transaction->t_checkpoint_list; + jh->b_cpprev = transaction->t_checkpoint_list->b_cpprev; + jh->b_cpprev->b_cpnext = jh; + jh->b_cpnext->b_cpprev = jh; + } + transaction->t_checkpoint_list = jh; +} + +void journal_insert_checkpoint(struct journal_head *jh, + transaction_t *transaction) +{ + spin_lock(&journal_datalist_lock); + __journal_insert_checkpoint(jh, transaction); + spin_unlock(&journal_datalist_lock); +} + +/* + * We've finished with this transaction structure: adios... + * + * The transaction must have no links except for the checkpoint by this + * point. + * + * Called with the journal locked. + * Called with journal_datalist_lock held. + */ + +void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) +{ + assert_spin_locked(&journal_datalist_lock); + if (transaction->t_cpnext) { + transaction->t_cpnext->t_cpprev = transaction->t_cpprev; + transaction->t_cpprev->t_cpnext = transaction->t_cpnext; + if (journal->j_checkpoint_transactions == transaction) + journal->j_checkpoint_transactions = + transaction->t_cpnext; + if (journal->j_checkpoint_transactions == transaction) + journal->j_checkpoint_transactions = NULL; + } + + J_ASSERT (transaction->t_ilist == NULL); + J_ASSERT (transaction->t_buffers == NULL); + J_ASSERT (transaction->t_sync_datalist == NULL); + J_ASSERT (transaction->t_async_datalist == NULL); + J_ASSERT (transaction->t_forget == NULL); + J_ASSERT (transaction->t_iobuf_list == NULL); + J_ASSERT (transaction->t_shadow_list == NULL); + J_ASSERT (transaction->t_log_list == NULL); + J_ASSERT (transaction->t_checkpoint_list == NULL); + J_ASSERT (transaction->t_updates == 0); + + J_ASSERT (transaction->t_journal->j_committing_transaction != + transaction); + + jbd_debug (1, "Dropping transaction %d, all done\n", + transaction->t_tid); + kfree (transaction); +} + diff -u --recursive --new-file v2.4.14/linux/fs/jbd/commit.c linux/fs/jbd/commit.c --- v2.4.14/linux/fs/jbd/commit.c Wed Dec 31 16:00:00 1969 +++ linux/fs/jbd/commit.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,701 @@ +/* + * linux/fs/commit.c + * + * Written by Stephen C. Tweedie <sct@redhat.com>, 1998 + * + * Copyright 1998 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Journal commit routines for the generic filesystem journaling code; + * part of the ext2fs journaling system. + */ + +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/locks.h> +#include <linux/smp_lock.h> + +extern spinlock_t journal_datalist_lock; + +/* + * Default IO end handler for temporary BJ_IO buffer_heads. + */ +static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) +{ + BUFFER_TRACE(bh, ""); + mark_buffer_uptodate(bh, uptodate); + unlock_buffer(bh); +} + +/* + * journal_commit_transaction + * + * The primary function for committing a transaction to the log. This + * function is called by the journal thread to begin a complete commit. + */ +void journal_commit_transaction(journal_t *journal) +{ + transaction_t *commit_transaction; + struct journal_head *jh, *new_jh, *descriptor; + struct journal_head *next_jh, *last_jh; + struct buffer_head *wbuf[64]; + int bufs; + int flags; + int blocknr; + char *tagp = NULL; + journal_header_t *header; + journal_block_tag_t *tag = NULL; + int space_left = 0; + int first_tag = 0; + int tag_flag; + int i; + + /* + * First job: lock down the current transaction and wait for + * all outstanding updates to complete. + */ + + lock_journal(journal); /* Protect journal->j_running_transaction */ + +#ifdef COMMIT_STATS + spin_lock(&journal_datalist_lock); + summarise_journal_usage(journal); + spin_unlock(&journal_datalist_lock); +#endif + + lock_kernel(); + + J_ASSERT (journal->j_running_transaction != NULL); + J_ASSERT (journal->j_committing_transaction == NULL); + + commit_transaction = journal->j_running_transaction; + J_ASSERT (commit_transaction->t_state == T_RUNNING); + + jbd_debug (1, "JBD: starting commit of transaction %d\n", + commit_transaction->t_tid); + + commit_transaction->t_state = T_LOCKED; + while (commit_transaction->t_updates != 0) { + unlock_journal(journal); + sleep_on(&journal->j_wait_updates); + lock_journal(journal); + } + + J_ASSERT (commit_transaction->t_outstanding_credits <= + journal->j_max_transaction_buffers); + + /* Do we need to erase the effects of a prior journal_flush? */ + if (journal->j_flags & JFS_FLUSHED) { + jbd_debug(3, "super block updated\n"); + journal_update_superblock(journal, 1); + } else { + jbd_debug(3, "superblock not updated\n"); + } + + /* + * First thing we are allowed to do is to discard any remaining + * BJ_Reserved buffers. Note, it is _not_ permissible to assume + * that there are no such buffers: if a large filesystem + * operation like a truncate needs to split itself over multiple + * transactions, then it may try to do a journal_restart() while + * there are still BJ_Reserved buffers outstanding. These must + * be released cleanly from the current transaction. + * + * In this case, the filesystem must still reserve write access + * again before modifying the buffer in the new transaction, but + * we do not require it to remember exactly which old buffers it + * has reserved. This is consistent with the existing behaviour + * that multiple journal_get_write_access() calls to the same + * buffer are perfectly permissable. + */ + + while (commit_transaction->t_reserved_list) { + jh = commit_transaction->t_reserved_list; + JBUFFER_TRACE(jh, "reserved, unused: refile"); + journal_refile_buffer(jh); + } + + /* + * Now try to drop any written-back buffers from the journal's + * checkpoint lists. We do this *before* commit because it potentially + * frees some memory + */ + spin_lock(&journal_datalist_lock); + __journal_clean_checkpoint_list(journal); + spin_unlock(&journal_datalist_lock); + + /* First part of the commit: force the revoke list out to disk. + * The revoke code generates its own metadata blocks on disk for this. + * + * It is important that we do this while the transaction is + * still locked. Generating the revoke records should not + * generate any IO stalls, so this should be quick; and doing + * the work while we have the transaction locked means that we + * only ever have to maintain the revoke list for one + * transaction at a time. + */ + + jbd_debug (3, "JBD: commit phase 1\n"); + + journal_write_revoke_records(journal, commit_transaction); + + /* + * Now that we have built the revoke records, we can start + * reusing the revoke list for a new running transaction. We + * can now safely start committing the old transaction: time to + * get a new running transaction for incoming filesystem updates + */ + + commit_transaction->t_state = T_FLUSH; + + wake_up(&journal->j_wait_transaction_locked); + + journal->j_committing_transaction = commit_transaction; + journal->j_running_transaction = NULL; + + commit_transaction->t_log_start = journal->j_head; + + unlock_kernel(); + + jbd_debug (3, "JBD: commit phase 2\n"); + + /* + * Now start flushing things to disk, in the order they appear + * on the transaction lists. Data blocks go first. + */ + + /* + * Whenever we unlock the journal and sleep, things can get added + * onto ->t_datalist, so we have to keep looping back to write_out_data + * until we *know* that the list is empty. + */ +write_out_data: + + /* + * Cleanup any flushed data buffers from the data list. Even in + * abort mode, we want to flush this out as soon as possible. + * + * We take journal_datalist_lock to protect the lists from + * journal_try_to_free_buffers(). + */ + spin_lock(&journal_datalist_lock); + +write_out_data_locked: + bufs = 0; + next_jh = commit_transaction->t_sync_datalist; + if (next_jh == NULL) + goto sync_datalist_empty; + last_jh = next_jh->b_tprev; + + do { + struct buffer_head *bh; + + jh = next_jh; + next_jh = jh->b_tnext; + bh = jh2bh(jh); + if (!buffer_locked(bh)) { + if (buffer_dirty(bh)) { + BUFFER_TRACE(bh, "start journal writeout"); + atomic_inc(&bh->b_count); + wbuf[bufs++] = bh; + } else { + BUFFER_TRACE(bh, "writeout complete: unfile"); + __journal_unfile_buffer(jh); + jh->b_transaction = NULL; + __journal_remove_journal_head(bh); + refile_buffer(bh); + __brelse(bh); + } + } + if (bufs == ARRAY_SIZE(wbuf)) { + /* + * Major speedup: start here on the next scan + */ + J_ASSERT(commit_transaction->t_sync_datalist != 0); + commit_transaction->t_sync_datalist = jh; + break; + } + } while (jh != last_jh); + + if (bufs || current->need_resched) { + jbd_debug(2, "submit %d writes\n", bufs); + spin_unlock(&journal_datalist_lock); + unlock_journal(journal); + if (bufs) + ll_rw_block(WRITE, bufs, wbuf); + if (current->need_resched) + schedule(); + journal_brelse_array(wbuf, bufs); + lock_journal(journal); + spin_lock(&journal_datalist_lock); + if (bufs) + goto write_out_data_locked; + } + + /* + * Wait for all previously submitted IO on the data list to complete. + */ + jh = commit_transaction->t_sync_datalist; + if (jh == NULL) + goto sync_datalist_empty; + + do { + struct buffer_head *bh; + jh = jh->b_tprev; /* Wait on the last written */ + bh = jh2bh(jh); + if (buffer_locked(bh)) { + spin_unlock(&journal_datalist_lock); + unlock_journal(journal); + wait_on_buffer(bh); + /* the journal_head may have been removed now */ + lock_journal(journal); + goto write_out_data; + } else if (buffer_dirty(bh)) { + goto write_out_data_locked; + } + } while (jh != commit_transaction->t_sync_datalist); + goto write_out_data_locked; + +sync_datalist_empty: + /* + * Wait for all the async writepage data. As they become unlocked + * in end_buffer_io_async(), the only place where they can be + * reaped is in try_to_free_buffers(), and we're locked against + * that. + */ + while ((jh = commit_transaction->t_async_datalist)) { + struct buffer_head *bh = jh2bh(jh); + if (buffer_locked(bh)) { + spin_unlock(&journal_datalist_lock); + unlock_journal(journal); + wait_on_buffer(bh); + lock_journal(journal); + spin_lock(&journal_datalist_lock); + continue; /* List may have changed */ + } + if (jh->b_next_transaction) { + /* + * For writepage() buffers in journalled data mode: a + * later transaction may want the buffer for "metadata" + */ + __journal_refile_buffer(jh); + } else { + BUFFER_TRACE(bh, "finished async writeout: unfile"); + __journal_unfile_buffer(jh); + jh->b_transaction = NULL; + __journal_remove_journal_head(bh); + BUFFER_TRACE(bh, "finished async writeout: refile"); + /* It can sometimes be on BUF_LOCKED due to migration + * from syncdata to asyncdata */ + if (bh->b_list != BUF_CLEAN) + refile_buffer(bh); + __brelse(bh); + } + } + spin_unlock(&journal_datalist_lock); + + /* + * If we found any dirty or locked buffers, then we should have + * looped back up to the write_out_data label. If there weren't + * any then journal_clean_data_list should have wiped the list + * clean by now, so check that it is in fact empty. + */ + J_ASSERT (commit_transaction->t_sync_datalist == NULL); + J_ASSERT (commit_transaction->t_async_datalist == NULL); + + jbd_debug (3, "JBD: commit phase 3\n"); + + /* + * Way to go: we have now written out all of the data for a + * transaction! Now comes the tricky part: we need to write out + * metadata. Loop over the transaction's entire buffer list: + */ + commit_transaction->t_state = T_COMMIT; + + descriptor = 0; + bufs = 0; + while (commit_transaction->t_buffers) { + + /* Find the next buffer to be journaled... */ + + jh = commit_transaction->t_buffers; + + /* If we're in abort mode, we just un-journal the buffer and + release it for background writing. */ + + if (is_journal_aborted(journal)) { + JBUFFER_TRACE(jh, "journal is aborting: refile"); + journal_refile_buffer(jh); + /* If that was the last one, we need to clean up + * any descriptor buffers which may have been + * already allocated, even if we are now + * aborting. */ + if (!commit_transaction->t_buffers) + goto start_journal_io; + continue; + } + + /* Make sure we have a descriptor block in which to + record the metadata buffer. */ + + if (!descriptor) { + struct buffer_head *bh; + + J_ASSERT (bufs == 0); + + jbd_debug(4, "JBD: get descriptor\n"); + + descriptor = journal_get_descriptor_buffer(journal); + bh = jh2bh(descriptor); + jbd_debug(4, "JBD: got buffer %ld (%p)\n", + bh->b_blocknr, bh->b_data); + header = (journal_header_t *)&bh->b_data[0]; + header->h_magic = htonl(JFS_MAGIC_NUMBER); + header->h_blocktype = htonl(JFS_DESCRIPTOR_BLOCK); + header->h_sequence = htonl(commit_transaction->t_tid); + + tagp = &bh->b_data[sizeof(journal_header_t)]; + space_left = bh->b_size - sizeof(journal_header_t); + first_tag = 1; + set_bit(BH_JWrite, &bh->b_state); + wbuf[bufs++] = bh; + + /* Record it so that we can wait for IO + completion later */ + BUFFER_TRACE(bh, "ph3: file as descriptor"); + journal_file_buffer(descriptor, commit_transaction, + BJ_LogCtl); + } + + /* Where is the buffer to be written? */ + + blocknr = journal_next_log_block(journal); + + /* Bump b_count to prevent truncate from stumbling over + the shadowed buffer! @@@ This can go if we ever get + rid of the BJ_IO/BJ_Shadow pairing of buffers. */ + atomic_inc(&jh2bh(jh)->b_count); + + /* Make a temporary IO buffer with which to write it out + (this will requeue both the metadata buffer and the + temporary IO buffer). new_bh goes on BJ_IO*/ + + set_bit(BH_JWrite, &jh2bh(jh)->b_state); + /* + * akpm: journal_write_metadata_buffer() sets + * new_bh->b_transaction to commit_transaction. + * We need to clean this up before we release new_bh + * (which is of type BJ_IO) + */ + JBUFFER_TRACE(jh, "ph3: write metadata"); + flags = journal_write_metadata_buffer(commit_transaction, + jh, &new_jh, blocknr); + set_bit(BH_JWrite, &jh2bh(new_jh)->b_state); + wbuf[bufs++] = jh2bh(new_jh); + + /* Record the new block's tag in the current descriptor + buffer */ + + tag_flag = 0; + if (flags & 1) + tag_flag |= JFS_FLAG_ESCAPE; + if (!first_tag) + tag_flag |= JFS_FLAG_SAME_UUID; + + tag = (journal_block_tag_t *) tagp; + tag->t_blocknr = htonl(jh2bh(jh)->b_blocknr); + tag->t_flags = htonl(tag_flag); + tagp += sizeof(journal_block_tag_t); + space_left -= sizeof(journal_block_tag_t); + + if (first_tag) { + memcpy (tagp, journal->j_uuid, 16); + tagp += 16; + space_left -= 16; + first_tag = 0; + } + + /* If there's no more to do, or if the descriptor is full, + let the IO rip! */ + + if (bufs == ARRAY_SIZE(wbuf) || + commit_transaction->t_buffers == NULL || + space_left < sizeof(journal_block_tag_t) + 16) { + + jbd_debug(4, "JBD: Submit %d IOs\n", bufs); + + /* Write an end-of-descriptor marker before + submitting the IOs. "tag" still points to + the last tag we set up. */ + + tag->t_flags |= htonl(JFS_FLAG_LAST_TAG); + +start_journal_io: + unlock_journal(journal); + for (i=0; i<bufs; i++) { + struct buffer_head *bh = wbuf[i]; + set_bit(BH_Lock, &bh->b_state); + clear_bit(BH_Dirty, &bh->b_state); + bh->b_end_io = journal_end_buffer_io_sync; + submit_bh(WRITE, bh); + } + if (current->need_resched) + schedule(); + lock_journal(journal); + + /* Force a new descriptor to be generated next + time round the loop. */ + descriptor = NULL; + bufs = 0; + } + } + + /* Lo and behold: we have just managed to send a transaction to + the log. Before we can commit it, wait for the IO so far to + complete. Control buffers being written are on the + transaction's t_log_list queue, and metadata buffers are on + the t_iobuf_list queue. + + Wait for the transactions in reverse order. That way we are + less likely to be woken up until all IOs have completed, and + so we incur less scheduling load. + */ + + jbd_debug(3, "JBD: commit phase 4\n"); + + /* akpm: these are BJ_IO, and journal_datalist_lock is not needed */ + wait_for_iobuf: + while (commit_transaction->t_iobuf_list != NULL) { + struct buffer_head *bh; + jh = commit_transaction->t_iobuf_list->b_tprev; + bh = jh2bh(jh); + if (buffer_locked(bh)) { + unlock_journal(journal); + wait_on_buffer(bh); + lock_journal(journal); + goto wait_for_iobuf; + } + + clear_bit(BH_JWrite, &jh2bh(jh)->b_state); + + JBUFFER_TRACE(jh, "ph4: unfile after journal write"); + journal_unfile_buffer(jh); + + /* + * akpm: don't put back a buffer_head with stale pointers + * dangling around. + */ + J_ASSERT_JH(jh, jh->b_transaction != NULL); + jh->b_transaction = NULL; + + /* + * ->t_iobuf_list should contain only dummy buffer_heads + * which were created by journal_write_metadata_buffer(). + */ + bh = jh2bh(jh); + BUFFER_TRACE(bh, "dumping temporary bh"); + journal_unlock_journal_head(jh); + __brelse(bh); + J_ASSERT_BH(bh, atomic_read(&bh->b_count) == 0); + put_unused_buffer_head(bh); + + /* We also have to unlock and free the corresponding + shadowed buffer */ + jh = commit_transaction->t_shadow_list->b_tprev; + bh = jh2bh(jh); + clear_bit(BH_JWrite, &bh->b_state); + J_ASSERT_BH(bh, buffer_jdirty(bh)); + + /* The metadata is now released for reuse, but we need + to remember it against this transaction so that when + we finally commit, we can do any checkpointing + required. */ + JBUFFER_TRACE(jh, "file as BJ_Forget"); + journal_file_buffer(jh, commit_transaction, BJ_Forget); + /* Wake up any transactions which were waiting for this + IO to complete */ + wake_up(&bh->b_wait); + JBUFFER_TRACE(jh, "brelse shadowed buffer"); + __brelse(bh); + } + + J_ASSERT (commit_transaction->t_shadow_list == NULL); + + jbd_debug(3, "JBD: commit phase 5\n"); + + /* Here we wait for the revoke record and descriptor record buffers */ + wait_for_ctlbuf: + while (commit_transaction->t_log_list != NULL) { + struct buffer_head *bh; + + jh = commit_transaction->t_log_list->b_tprev; + bh = jh2bh(jh); + if (buffer_locked(bh)) { + unlock_journal(journal); + wait_on_buffer(bh); + lock_journal(journal); + goto wait_for_ctlbuf; + } + + BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile"); + clear_bit(BH_JWrite, &bh->b_state); + journal_unfile_buffer(jh); + jh->b_transaction = NULL; + journal_unlock_journal_head(jh); + __brelse(bh); /* One for getblk */ + /* AKPM: bforget here */ + } + + jbd_debug(3, "JBD: commit phase 6\n"); + + /* Done it all: now write the commit record. We should have + * cleaned up our previous buffers by now, so if we are in abort + * mode we can now just skip the rest of the journal write + * entirely. */ + + if (is_journal_aborted(journal)) + goto skip_commit; + + descriptor = journal_get_descriptor_buffer(journal); + + /* AKPM: buglet - add `i' to tmp! */ + for (i = 0; i < jh2bh(descriptor)->b_size; i += 512) { + journal_header_t *tmp = + (journal_header_t*)jh2bh(descriptor)->b_data; + tmp->h_magic = htonl(JFS_MAGIC_NUMBER); + tmp->h_blocktype = htonl(JFS_COMMIT_BLOCK); + tmp->h_sequence = htonl(commit_transaction->t_tid); + } + + unlock_journal(journal); + JBUFFER_TRACE(descriptor, "write commit block"); + { + struct buffer_head *bh = jh2bh(descriptor); + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + __brelse(bh); /* One for getblk() */ + journal_unlock_journal_head(descriptor); + } + lock_journal(journal); + + /* End of a transaction! Finally, we can do checkpoint + processing: any buffers committed as a result of this + transaction can be removed from any checkpoint list it was on + before. */ + +skip_commit: + + jbd_debug(3, "JBD: commit phase 7\n"); + + J_ASSERT(commit_transaction->t_sync_datalist == NULL); + J_ASSERT(commit_transaction->t_async_datalist == NULL); + J_ASSERT(commit_transaction->t_buffers == NULL); + J_ASSERT(commit_transaction->t_checkpoint_list == NULL); + J_ASSERT(commit_transaction->t_iobuf_list == NULL); + J_ASSERT(commit_transaction->t_shadow_list == NULL); + J_ASSERT(commit_transaction->t_log_list == NULL); + + while (commit_transaction->t_forget) { + transaction_t *cp_transaction; + struct buffer_head *bh; + + jh = commit_transaction->t_forget; + J_ASSERT_JH(jh, jh->b_transaction == commit_transaction || + jh->b_transaction == journal->j_running_transaction); + + /* + * If there is undo-protected committed data against + * this buffer, then we can remove it now. If it is a + * buffer needing such protection, the old frozen_data + * field now points to a committed version of the + * buffer, so rotate that field to the new committed + * data. + * + * Otherwise, we can just throw away the frozen data now. + */ + if (jh->b_committed_data) { + kfree(jh->b_committed_data); + jh->b_committed_data = NULL; + if (jh->b_frozen_data) { + jh->b_committed_data = jh->b_frozen_data; + jh->b_frozen_data = NULL; + } + } else if (jh->b_frozen_data) { + kfree(jh->b_frozen_data); + jh->b_frozen_data = NULL; + } + + spin_lock(&journal_datalist_lock); + cp_transaction = jh->b_cp_transaction; + if (cp_transaction) { + JBUFFER_TRACE(jh, "remove from old cp transaction"); + J_ASSERT_JH(jh, commit_transaction != cp_transaction); + __journal_remove_checkpoint(jh); + } + + /* Only re-checkpoint the buffer_head if it is marked + * dirty. If the buffer was added to the BJ_Forget list + * by journal_forget, it may no longer be dirty and + * there's no point in keeping a checkpoint record for + * it. */ + bh = jh2bh(jh); + if (buffer_jdirty(bh)) { + JBUFFER_TRACE(jh, "add to new checkpointing trans"); + __journal_insert_checkpoint(jh, commit_transaction); + JBUFFER_TRACE(jh, "refile for checkpoint writeback"); + __journal_refile_buffer(jh); + } else { + J_ASSERT_BH(bh, !buffer_dirty(bh)); + J_ASSERT_JH(jh, jh->b_next_transaction == NULL); + __journal_unfile_buffer(jh); + jh->b_transaction = 0; + __journal_remove_journal_head(bh); + __brelse(bh); + } + spin_unlock(&journal_datalist_lock); + } + + /* Done with this transaction! */ + + jbd_debug(3, "JBD: commit phase 8\n"); + + J_ASSERT (commit_transaction->t_state == T_COMMIT); + commit_transaction->t_state = T_FINISHED; + + J_ASSERT (commit_transaction == journal->j_committing_transaction); + journal->j_commit_sequence = commit_transaction->t_tid; + journal->j_committing_transaction = NULL; + + spin_lock(&journal_datalist_lock); + if (commit_transaction->t_checkpoint_list == NULL) { + __journal_drop_transaction(journal, commit_transaction); + } else { + if (journal->j_checkpoint_transactions == NULL) { + journal->j_checkpoint_transactions = commit_transaction; + commit_transaction->t_cpnext = commit_transaction; + commit_transaction->t_cpprev = commit_transaction; + } else { + commit_transaction->t_cpnext = + journal->j_checkpoint_transactions; + commit_transaction->t_cpprev = + commit_transaction->t_cpnext->t_cpprev; + commit_transaction->t_cpnext->t_cpprev = + commit_transaction; + commit_transaction->t_cpprev->t_cpnext = + commit_transaction; + } + } + spin_unlock(&journal_datalist_lock); + + jbd_debug(1, "JBD: commit %d complete, head %d\n", + journal->j_commit_sequence, journal->j_tail_sequence); + + unlock_journal(journal); + wake_up(&journal->j_wait_done_commit); +} diff -u --recursive --new-file v2.4.14/linux/fs/jbd/journal.c linux/fs/jbd/journal.c --- v2.4.14/linux/fs/jbd/journal.c Wed Dec 31 16:00:00 1969 +++ linux/fs/jbd/journal.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,1813 @@ +/* + * linux/fs/journal.c + * + * Written by Stephen C. Tweedie <sct@redhat.com>, 1998 + * + * Copyright 1998 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Generic filesystem journal-writing code; part of the ext2fs + * journaling system. + * + * This file manages journals: areas of disk reserved for logging + * transactional updates. This includes the kernel journaling thread + * which is responsible for scheduling updates to the log. + * + * We do not actually manage the physical storage of the journal in this + * file: that is left to a per-journal policy function, which allows us + * to store the journal within a filesystem-specified area for ext2 + * journaling (ext2 can use a reserved inode for storing the log). + */ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/locks.h> +#include <linux/smp_lock.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <asm/uaccess.h> +#include <linux/proc_fs.h> + +EXPORT_SYMBOL(journal_start); +EXPORT_SYMBOL(journal_try_start); +EXPORT_SYMBOL(journal_restart); +EXPORT_SYMBOL(journal_extend); +EXPORT_SYMBOL(journal_stop); +EXPORT_SYMBOL(journal_lock_updates); +EXPORT_SYMBOL(journal_unlock_updates); +EXPORT_SYMBOL(journal_get_write_access); +EXPORT_SYMBOL(journal_get_create_access); +EXPORT_SYMBOL(journal_get_undo_access); +EXPORT_SYMBOL(journal_dirty_data); +EXPORT_SYMBOL(journal_dirty_metadata); +#if 0 +EXPORT_SYMBOL(journal_release_buffer); +#endif +EXPORT_SYMBOL(journal_forget); +#if 0 +EXPORT_SYMBOL(journal_sync_buffer); +#endif +EXPORT_SYMBOL(journal_flush); +EXPORT_SYMBOL(journal_revoke); + +EXPORT_SYMBOL(journal_init_dev); +EXPORT_SYMBOL(journal_init_inode); +EXPORT_SYMBOL(journal_update_format); +EXPORT_SYMBOL(journal_check_used_features); +EXPORT_SYMBOL(journal_check_available_features); +EXPORT_SYMBOL(journal_set_features); +EXPORT_SYMBOL(journal_create); +EXPORT_SYMBOL(journal_load); +EXPORT_SYMBOL(journal_destroy); +EXPORT_SYMBOL(journal_recover); +EXPORT_SYMBOL(journal_update_superblock); +EXPORT_SYMBOL(__journal_abort); +EXPORT_SYMBOL(journal_abort); +EXPORT_SYMBOL(journal_errno); +EXPORT_SYMBOL(journal_ack_err); +EXPORT_SYMBOL(journal_clear_err); +EXPORT_SYMBOL(log_wait_commit); +EXPORT_SYMBOL(log_start_commit); +EXPORT_SYMBOL(journal_wipe); +EXPORT_SYMBOL(journal_blocks_per_page); +EXPORT_SYMBOL(journal_flushpage); +EXPORT_SYMBOL(journal_try_to_free_buffers); +EXPORT_SYMBOL(journal_bmap); +EXPORT_SYMBOL(journal_force_commit); + +static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); + +/* + * journal_datalist_lock is used to protect data buffers: + * + * bh->b_transaction + * bh->b_tprev + * bh->b_tnext + * + * journal_free_buffer() is called from journal_try_to_free_buffer(), and is + * async wrt everything else. + * + * It is also used for checkpoint data, also to protect against + * journal_try_to_free_buffer(): + * + * bh->b_cp_transaction + * bh->b_cpnext + * bh->b_cpprev + * transaction->t_checkpoint_list + * transaction->t_cpnext + * transaction->t_cpprev + * journal->j_checkpoint_transactions + * + * It is global at this time rather than per-journal because it's + * impossible for __journal_free_buffer to go from a buffer_head + * back to a journal_t unracily (well, not true. Fix later) + * + * + * The `datalist' and `checkpoint list' functions are quite + * separate and we could use two spinlocks here. + * + * lru_list_lock nests inside journal_datalist_lock. + */ +spinlock_t journal_datalist_lock = SPIN_LOCK_UNLOCKED; + +/* + * jh_splice_lock needs explantion. + * + * In a number of places we want to do things like: + * + * if (buffer_jbd(bh) && bh2jh(bh)->foo) + * + * This is racy on SMP, because another CPU could remove the journal_head + * in the middle of this expression. We need locking. + * + * But we can greatly optimise the locking cost by testing BH_JBD + * outside the lock. So, effectively: + * + * ret = 0; + * if (buffer_jbd(bh)) { + * spin_lock(&jh_splice_lock); + * if (buffer_jbd(bh)) { (* Still there? *) + * ret = bh2jh(bh)->foo; + * } + * spin_unlock(&jh_splice_lock); + * } + * return ret; + * + * Now, that protects us from races where another CPU can remove the + * journal_head. But it doesn't defend us from the situation where another + * CPU can *add* a journal_head. This is a correctness issue. But it's not + * a problem because a) the calling code was *already* racy and b) it often + * can't happen at the call site and c) the places where we add journal_heads + * tend to be under external locking. + */ +spinlock_t jh_splice_lock = SPIN_LOCK_UNLOCKED; + +/* + * List of all journals in the system. Protected by the BKL. + */ +static LIST_HEAD(all_journals); + +/* + * Helper function used to manage commit timeouts + */ + +static void commit_timeout(unsigned long __data) +{ + struct task_struct * p = (struct task_struct *) __data; + + wake_up_process(p); +} + +/* Static check for data structure consistency. There's no code + * invoked --- we'll just get a linker failure if things aren't right. + */ +void __journal_internal_check(void) +{ + extern void journal_bad_superblock_size(void); + if (sizeof(struct journal_superblock_s) != 1024) + journal_bad_superblock_size(); +} + +/* + * kjournald: The main thread function used to manage a logging device + * journal. + * + * This kernel thread is responsible for two things: + * + * 1) COMMIT: Every so often we need to commit the current state of the + * filesystem to disk. The journal thread is responsible for writing + * all of the metadata buffers to disk. + * + * 2) CHECKPOINT: We cannot reuse a used section of the log file until all + * of the data in that part of the log has been rewritten elsewhere on + * the disk. Flushing these old buffers to reclaim space in the log is + * known as checkpointing, and this thread is responsible for that job. + */ + +journal_t *current_journal; // AKPM: debug + +int kjournald(void *arg) +{ + journal_t *journal = (journal_t *) arg; + transaction_t *transaction; + struct timer_list timer; + + current_journal = journal; + + lock_kernel(); + daemonize(); + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + sprintf(current->comm, "kjournald"); + + /* Set up an interval timer which can be used to trigger a + commit wakeup after the commit interval expires */ + init_timer(&timer); + timer.data = (unsigned long) current; + timer.function = commit_timeout; + journal->j_commit_timer = &timer; + + /* Record that the journal thread is running */ + journal->j_task = current; + wake_up(&journal->j_wait_done_commit); + + printk(KERN_INFO "kjournald starting. Commit interval %ld seconds\n", + journal->j_commit_interval / HZ); + list_add(&journal->j_all_journals, &all_journals); + + /* And now, wait forever for commit wakeup events. */ + while (1) { + if (journal->j_flags & JFS_UNMOUNT) + break; + + jbd_debug(1, "commit_sequence=%d, commit_request=%d\n", + journal->j_commit_sequence, journal->j_commit_request); + + if (journal->j_commit_sequence != journal->j_commit_request) { + jbd_debug(1, "OK, requests differ\n"); + if (journal->j_commit_timer_active) { + journal->j_commit_timer_active = 0; + del_timer(journal->j_commit_timer); + } + + journal_commit_transaction(journal); + continue; + } + + wake_up(&journal->j_wait_done_commit); + interruptible_sleep_on(&journal->j_wait_commit); + + jbd_debug(1, "kjournald wakes\n"); + + /* Were we woken up by a commit wakeup event? */ + if ((transaction = journal->j_running_transaction) != NULL && + time_after_eq(jiffies, transaction->t_expires)) { + journal->j_commit_request = transaction->t_tid; + jbd_debug(1, "woke because of timeout\n"); + } + } + + if (journal->j_commit_timer_active) { + journal->j_commit_timer_active = 0; + del_timer_sync(journal->j_commit_timer); + } + + list_del(&journal->j_all_journals); + + journal->j_task = NULL; + wake_up(&journal->j_wait_done_commit); + jbd_debug(1, "Journal thread exiting.\n"); + return 0; +} + +static void journal_start_thread(journal_t *journal) +{ + kernel_thread(kjournald, (void *) journal, + CLONE_VM | CLONE_FS | CLONE_FILES); + while (!journal->j_task) + sleep_on(&journal->j_wait_done_commit); +} + +static void journal_kill_thread(journal_t *journal) +{ + journal->j_flags |= JFS_UNMOUNT; + + while (journal->j_task) { + wake_up(&journal->j_wait_commit); + sleep_on(&journal->j_wait_done_commit); + } +} + +#if 0 + +This is no longer needed - we do it in commit quite efficiently. +Note that if this function is resurrected, the loop needs to +be reorganised into the next_jh/last_jh algorithm. + +/* + * journal_clean_data_list: cleanup after data IO. + * + * Once the IO system has finished writing the buffers on the transaction's + * data list, we can remove those buffers from the list. This function + * scans the list for such buffers and removes them cleanly. + * + * We assume that the journal is already locked. + * We are called with journal_datalist_lock held. + * + * AKPM: This function looks inefficient. Approximately O(n^2) + * for potentially thousands of buffers. It no longer shows on profiles + * because these buffers are mainly dropped in journal_commit_transaction(). + */ + +void __journal_clean_data_list(transaction_t *transaction) +{ + struct journal_head *jh, *next; + + assert_spin_locked(&journal_datalist_lock); + +restart: + jh = transaction->t_sync_datalist; + if (!jh) + goto out; + do { + next = jh->b_tnext; + if (!buffer_locked(jh2bh(jh)) && !buffer_dirty(jh2bh(jh))) { + struct buffer_head *bh = jh2bh(jh); + BUFFER_TRACE(bh, "data writeout complete: unfile"); + __journal_unfile_buffer(jh); + jh->b_transaction = NULL; + __journal_remove_journal_head(bh); + refile_buffer(bh); + __brelse(bh); + goto restart; + } + jh = next; + } while (transaction->t_sync_datalist && + jh != transaction->t_sync_datalist); +out: + return; +} +#endif + +/* + * journal_write_metadata_buffer: write a metadata buffer to the journal. + * + * Writes a metadata buffer to a given disk block. The actual IO is not + * performed but a new buffer_head is constructed which labels the data + * to be written with the correct destination disk block. + * + * Any magic-number escaping which needs to be done will cause a + * copy-out here. If the buffer happens to start with the + * JFS_MAGIC_NUMBER, then we can't write it to the log directly: the + * magic number is only written to the log for descripter blocks. In + * this case, we copy the data and replace the first word with 0, and we + * return a result code which indicates that this buffer needs to be + * marked as an escaped buffer in the corresponding log descriptor + * block. The missing word can then be restored when the block is read + * during recovery. + * + * If the source buffer has already been modified by a new transaction + * since we took the last commit snapshot, we use the frozen copy of + * that data for IO. If we end up using the existing buffer_head's data + * for the write, then we *have* to lock the buffer to prevent anyone + * else from using and possibly modifying it while the IO is in + * progress. + * + * The function returns a pointer to the buffer_heads to be used for IO. + * + * We assume that the journal has already been locked in this function. + * + * Return value: + * <0: Error + * >=0: Finished OK + * + * On success: + * Bit 0 set == escape performed on the data + * Bit 1 set == buffer copy-out performed (kfree the data after IO) + */ + +static inline unsigned long virt_to_offset(void *p) +{return ((unsigned long) p) & ~PAGE_MASK;} + +int journal_write_metadata_buffer(transaction_t *transaction, + struct journal_head *jh_in, + struct journal_head **jh_out, + int blocknr) +{ + int need_copy_out = 0; + int done_copy_out = 0; + int do_escape = 0; + char *mapped_data; + struct buffer_head *new_bh; + struct journal_head * new_jh; + struct page *new_page; + unsigned int new_offset; + + /* + * The buffer really shouldn't be locked: only the current committing + * transaction is allowed to write it, so nobody else is allowed + * to do any IO. + * + * akpm: except if we're journalling data, and write() output is + * also part of a shared mapping, and another thread has + * decided to launch a writepage() against this buffer. + */ + J_ASSERT_JH(jh_in, buffer_jdirty(jh2bh(jh_in))); + + /* + * If a new transaction has already done a buffer copy-out, then + * we use that version of the data for the commit. + */ + + if (jh_in->b_frozen_data) { + done_copy_out = 1; + new_page = virt_to_page(jh_in->b_frozen_data); + new_offset = virt_to_offset(jh_in->b_frozen_data); + } else { + new_page = jh2bh(jh_in)->b_page; + new_offset = virt_to_offset(jh2bh(jh_in)->b_data); + } + + mapped_data = ((char *) kmap(new_page)) + new_offset; + + /* + * Check for escaping + */ + if (* ((unsigned int *) mapped_data) == htonl(JFS_MAGIC_NUMBER)) { + need_copy_out = 1; + do_escape = 1; + } + + /* + * Do we need to do a data copy? + */ + + if (need_copy_out && !done_copy_out) { + char *tmp; + tmp = jbd_rep_kmalloc(jh2bh(jh_in)->b_size, GFP_NOFS); + + jh_in->b_frozen_data = tmp; + memcpy (tmp, mapped_data, jh2bh(jh_in)->b_size); + + /* If we get to this path, we'll always need the new + address kmapped so that we can clear the escaped + magic number below. */ + kunmap(new_page); + new_page = virt_to_page(tmp); + new_offset = virt_to_offset(tmp); + mapped_data = ((char *) kmap(new_page)) + new_offset; + + done_copy_out = 1; + } + + /* + * Right, time to make up the new buffer_head. + */ + do { + new_bh = get_unused_buffer_head(0); + if (!new_bh) { + printk (KERN_NOTICE __FUNCTION__ + ": ENOMEM at get_unused_buffer_head, " + "trying again.\n"); + current->policy |= SCHED_YIELD; + schedule(); + } + } while (!new_bh); + /* keep subsequent assertions sane */ + new_bh->b_prev_free = 0; + new_bh->b_next_free = 0; + new_bh->b_state = 0; + init_buffer(new_bh, NULL, NULL); + atomic_set(&new_bh->b_count, 1); + new_jh = journal_add_journal_head(new_bh); + + set_bh_page(new_bh, new_page, new_offset); + + new_jh->b_transaction = NULL; + new_bh->b_size = jh2bh(jh_in)->b_size; + new_bh->b_dev = transaction->t_journal->j_dev; + new_bh->b_blocknr = blocknr; + new_bh->b_state |= (1 << BH_Mapped) | (1 << BH_Dirty); + + *jh_out = new_jh; + + /* + * Did we need to do an escaping? Now we've done all the + * copying, we can finally do so. + */ + + if (do_escape) + * ((unsigned int *) mapped_data) = 0; + kunmap(new_page); + + /* + * The to-be-written buffer needs to get moved to the io queue, + * and the original buffer whose contents we are shadowing or + * copying is moved to the transaction's shadow queue. + */ + JBUFFER_TRACE(jh_in, "file as BJ_Shadow"); + journal_file_buffer(jh_in, transaction, BJ_Shadow); + JBUFFER_TRACE(new_jh, "file as BJ_IO"); + journal_file_buffer(new_jh, transaction, BJ_IO); + + return do_escape | (done_copy_out << 1); +} + +/* + * Allocation code for the journal file. Manage the space left in the + * journal, so that we can begin checkpointing when appropriate. + */ + +/* + * log_space_left: Return the number of free blocks left in the journal. + * + * Called with the journal already locked. + */ + +int log_space_left (journal_t *journal) +{ + int left = journal->j_free; + + /* Be pessimistic here about the number of those free blocks + * which might be required for log descriptor control blocks. */ + +#define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */ + + left -= MIN_LOG_RESERVED_BLOCKS; + + if (left <= 0) + return 0; + left -= (left >> 3); + return left; +} + +/* + * This function must be non-allocating for PF_MEMALLOC tasks + */ +tid_t log_start_commit (journal_t *journal, transaction_t *transaction) +{ + tid_t target = journal->j_commit_request; + + lock_kernel(); /* Protect journal->j_running_transaction */ + + /* + * A NULL transaction asks us to commit the currently running + * transaction, if there is one. + */ + if (transaction) + target = transaction->t_tid; + else { + transaction = journal->j_running_transaction; + if (!transaction) + goto out; + target = transaction->t_tid; + } + + /* + * Are we already doing a recent enough commit? + */ + if (tid_geq(journal->j_commit_request, target)) + goto out; + + /* + * We want a new commit: OK, mark the request and wakup the + * commit thread. We do _not_ do the commit ourselves. + */ + + journal->j_commit_request = target; + jbd_debug(1, "JBD: requesting commit %d/%d\n", + journal->j_commit_request, + journal->j_commit_sequence); + wake_up(&journal->j_wait_commit); + +out: + unlock_kernel(); + return target; +} + +/* + * Wait for a specified commit to complete. + * The caller may not hold the journal lock. + */ +void log_wait_commit (journal_t *journal, tid_t tid) +{ + lock_kernel(); +#ifdef CONFIG_JBD_DEBUG + lock_journal(journal); + if (!tid_geq(journal->j_commit_request, tid)) { + printk(KERN_EMERG __FUNCTION__ + ": error: j_commit_request=%d, tid=%d\n", + journal->j_commit_request, tid); + } + unlock_journal(journal); +#endif + while (tid_gt(tid, journal->j_commit_sequence)) { + jbd_debug(1, "JBD: want %d, j_commit_sequence=%d\n", + tid, journal->j_commit_sequence); + wake_up(&journal->j_wait_commit); + sleep_on(&journal->j_wait_done_commit); + } + unlock_kernel(); +} + +/* + * Log buffer allocation routines: + */ + +unsigned long journal_next_log_block(journal_t *journal) +{ + unsigned long blocknr; + + J_ASSERT(journal->j_free > 1); + + blocknr = journal->j_head; + journal->j_head++; + journal->j_free--; + if (journal->j_head == journal->j_last) + journal->j_head = journal->j_first; + return journal_bmap(journal, blocknr); +} + +/* + * Conversion of logical to physical block numbers for the journal + * + * On external journals the journal blocks are identity-mapped, so + * this is a no-op. If needed, we can use j_blk_offset - everything is + * ready. + */ +unsigned long journal_bmap(journal_t *journal, unsigned long blocknr) +{ + unsigned long ret; + + if (journal->j_inode) { + ret = bmap(journal->j_inode, blocknr); + J_ASSERT(ret != 0); + } else { + ret = blocknr; /* +journal->j_blk_offset */ + } + return ret; +} + +/* + * We play buffer_head aliasing tricks to write data/metadata blocks to + * the journal without copying their contents, but for journal + * descriptor blocks we do need to generate bona fide buffers. + */ + +struct journal_head * journal_get_descriptor_buffer(journal_t *journal) +{ + struct buffer_head *bh; + unsigned long blocknr = journal_next_log_block(journal); + + bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); + bh->b_state |= (1 << BH_Dirty); + BUFFER_TRACE(bh, "return this buffer"); + return journal_add_journal_head(bh); +} + +/* + * Management for journal control blocks: functions to create and + * destroy journal_t structures, and to initialise and read existing + * journal blocks from disk. */ + +/* First: create and setup a journal_t object in memory. We initialise + * very few fields yet: that has to wait until we have created the + * journal structures from from scratch, or loaded them from disk. */ + +static journal_t * journal_init_common (void) +{ + journal_t *journal; + int err; + + MOD_INC_USE_COUNT; + + journal = jbd_kmalloc(sizeof(*journal), GFP_KERNEL); + if (!journal) + goto fail; + memset(journal, 0, sizeof(*journal)); + + init_waitqueue_head(&journal->j_wait_transaction_locked); + init_waitqueue_head(&journal->j_wait_logspace); + init_waitqueue_head(&journal->j_wait_done_commit); + init_waitqueue_head(&journal->j_wait_checkpoint); + init_waitqueue_head(&journal->j_wait_commit); + init_waitqueue_head(&journal->j_wait_updates); + init_MUTEX(&journal->j_barrier); + init_MUTEX(&journal->j_checkpoint_sem); + init_MUTEX(&journal->j_sem); + + journal->j_commit_interval = (HZ * 5); + + /* The journal is marked for error until we succeed with recovery! */ + journal->j_flags = JFS_ABORT; + + /* Set up a default-sized revoke table for the new mount. */ + err = journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH); + if (err) { + kfree(journal); + goto fail; + } + return journal; +fail: + MOD_DEC_USE_COUNT; + return NULL; +} + +/* journal_init_dev and journal_init_inode: + * + * Create a journal structure assigned some fixed set of disk blocks to + * the journal. We don't actually touch those disk blocks yet, but we + * need to set up all of the mapping information to tell the journaling + * system where the journal blocks are. + * + * journal_init_dev creates a journal which maps a fixed contiguous + * range of blocks on an arbitrary block device. + * + * journal_init_inode creates a journal which maps an on-disk inode as + * the journal. The inode must exist already, must support bmap() and + * must have all data blocks preallocated. + */ + +journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev, + int start, int len, int blocksize) +{ + journal_t *journal = journal_init_common(); + struct buffer_head *bh; + + if (!journal) + return NULL; + + journal->j_dev = dev; + journal->j_fs_dev = fs_dev; + journal->j_blk_offset = start; + journal->j_maxlen = len; + journal->j_blocksize = blocksize; + + bh = getblk(journal->j_dev, start, journal->j_blocksize); + J_ASSERT(bh != NULL); + journal->j_sb_buffer = bh; + journal->j_superblock = (journal_superblock_t *)bh->b_data; + + return journal; +} + +journal_t * journal_init_inode (struct inode *inode) +{ + struct buffer_head *bh; + journal_t *journal = journal_init_common(); + int blocknr; + + if (!journal) + return NULL; + + journal->j_dev = inode->i_dev; + journal->j_fs_dev = inode->i_dev; + journal->j_inode = inode; + jbd_debug(1, + "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n", + journal, bdevname(inode->i_dev), inode->i_ino, inode->i_size, + inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize); + + journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits; + journal->j_blocksize = inode->i_sb->s_blocksize; + + blocknr = journal_bmap(journal, 0); + bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); + J_ASSERT(bh != NULL); + journal->j_sb_buffer = bh; + journal->j_superblock = (journal_superblock_t *)bh->b_data; + + return journal; +} + +/* + * Given a journal_t structure, initialise the various fields for + * startup of a new journaling session. We use this both when creating + * a journal, and after recovering an old journal to reset it for + * subsequent use. + */ + +static int journal_reset (journal_t *journal) +{ + journal_superblock_t *sb = journal->j_superblock; + unsigned int first, last; + + first = ntohl(sb->s_first); + last = ntohl(sb->s_maxlen); + + journal->j_first = first; + journal->j_last = last; + + journal->j_head = first; + journal->j_tail = first; + journal->j_free = last - first; + + journal->j_tail_sequence = journal->j_transaction_sequence; + journal->j_commit_sequence = journal->j_transaction_sequence - 1; + journal->j_commit_request = journal->j_commit_sequence; + + journal->j_max_transaction_buffers = journal->j_maxlen / 4; + + /* Add the dynamic fields and write it to disk. */ + journal_update_superblock(journal, 1); + + lock_journal(journal); + journal_start_thread(journal); + unlock_journal(journal); + + return 0; +} + +/* + * Given a journal_t structure which tells us which disk blocks we can + * use, create a new journal superblock and initialise all of the + * journal fields from scratch. */ + +int journal_create (journal_t *journal) +{ + int blocknr; + struct buffer_head *bh; + journal_superblock_t *sb; + int i; + + if (journal->j_maxlen < JFS_MIN_JOURNAL_BLOCKS) { + printk (KERN_ERR "Journal length (%d blocks) too short.\n", + journal->j_maxlen); + return -EINVAL; + } + + if (journal->j_inode == NULL) { + /* + * We don't know what block to start at! + */ + printk(KERN_EMERG __FUNCTION__ + ": creation of journal on external device!\n"); + BUG(); + } + + /* Zero out the entire journal on disk. We cannot afford to + have any blocks on disk beginning with JFS_MAGIC_NUMBER. */ + jbd_debug(1, "JBD: Zeroing out journal blocks...\n"); + for (i = 0; i < journal->j_maxlen; i++) { + blocknr = journal_bmap(journal, i); + bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); + wait_on_buffer(bh); + memset (bh->b_data, 0, journal->j_blocksize); + BUFFER_TRACE(bh, "marking dirty"); + mark_buffer_dirty(bh); + BUFFER_TRACE(bh, "marking uptodate"); + mark_buffer_uptodate(bh, 1); + __brelse(bh); + } + sync_dev(journal->j_dev); + jbd_debug(1, "JBD: journal cleared.\n"); + + /* OK, fill in the initial static fields in the new superblock */ + sb = journal->j_superblock; + + sb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); + sb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); + + sb->s_blocksize = htonl(journal->j_blocksize); + sb->s_maxlen = htonl(journal->j_maxlen); + sb->s_first = htonl(1); + + journal->j_transaction_sequence = 1; + + journal->j_flags &= ~JFS_ABORT; + journal->j_format_version = 2; + + return journal_reset(journal); +} + +/* + * Update a journal's dynamic superblock fields and write it to disk, + * optionally waiting for the IO to complete. +*/ + +void journal_update_superblock(journal_t *journal, int wait) +{ + journal_superblock_t *sb = journal->j_superblock; + struct buffer_head *bh = journal->j_sb_buffer; + + jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n", + journal->j_tail, journal->j_tail_sequence, journal->j_errno); + + sb->s_sequence = htonl(journal->j_tail_sequence); + sb->s_start = htonl(journal->j_tail); + sb->s_errno = htonl(journal->j_errno); + + BUFFER_TRACE(bh, "marking dirty"); + mark_buffer_dirty(bh); + ll_rw_block(WRITE, 1, &bh); + if (wait) + wait_on_buffer(bh); + + /* If we have just flushed the log (by marking s_start==0), then + * any future commit will have to be careful to update the + * superblock again to re-record the true start of the log. */ + + if (sb->s_start) + journal->j_flags &= ~JFS_FLUSHED; + else + journal->j_flags |= JFS_FLUSHED; +} + + +/* + * Read the superblock for a given journal, performing initial + * validation of the format. + */ + +static int journal_get_superblock(journal_t *journal) +{ + struct buffer_head *bh; + journal_superblock_t *sb; + + bh = journal->j_sb_buffer; + + J_ASSERT(bh != NULL); + if (!buffer_uptodate(bh)) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) { + printk (KERN_ERR + "JBD: IO error reading journal superblock\n"); + return -EIO; + } + } + + sb = journal->j_superblock; + + if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) || + sb->s_blocksize != htonl(journal->j_blocksize)) { + printk(KERN_WARNING "JBD: no valid journal superblock found\n"); + return -EINVAL; + } + + switch(ntohl(sb->s_header.h_blocktype)) { + case JFS_SUPERBLOCK_V1: + journal->j_format_version = 1; + break; + case JFS_SUPERBLOCK_V2: + journal->j_format_version = 2; + break; + default: + printk(KERN_WARNING "JBD: unrecognised superblock format ID\n"); + return -EINVAL; + } + + if (ntohl(sb->s_maxlen) < journal->j_maxlen) + journal->j_maxlen = ntohl(sb->s_maxlen); + else if (ntohl(sb->s_maxlen) > journal->j_maxlen) { + printk (KERN_WARNING "JBD: journal file too short\n"); + return -EINVAL; + } + + return 0; +} + +/* + * Load the on-disk journal superblock and read the key fields into the + * journal_t. + */ + +static int load_superblock(journal_t *journal) +{ + int err; + journal_superblock_t *sb; + + err = journal_get_superblock(journal); + if (err) + return err; + + sb = journal->j_superblock; + + journal->j_tail_sequence = ntohl(sb->s_sequence); + journal->j_tail = ntohl(sb->s_start); + journal->j_first = ntohl(sb->s_first); + journal->j_last = ntohl(sb->s_maxlen); + journal->j_errno = ntohl(sb->s_errno); + + return 0; +} + + +/* + * Given a journal_t structure which tells us which disk blocks contain + * a journal, read the journal from disk to initialise the in-memory + * structures. + */ + +int journal_load(journal_t *journal) +{ + int err; + + err = load_superblock(journal); + if (err) + return err; + + /* If this is a V2 superblock, then we have to check the + * features flags on it. */ + + if (journal->j_format_version >= 2) { + journal_superblock_t *sb = journal->j_superblock; + + if ((sb->s_feature_ro_compat & + ~cpu_to_be32(JFS_KNOWN_ROCOMPAT_FEATURES)) || + (sb->s_feature_incompat & + ~cpu_to_be32(JFS_KNOWN_INCOMPAT_FEATURES))) { + printk (KERN_WARNING + "JBD: Unrecognised features on journal\n"); + return -EINVAL; + } + } + + /* Let the recovery code check whether it needs to recover any + * data from the journal. */ + if (journal_recover(journal)) + goto recovery_error; + + /* OK, we've finished with the dynamic journal bits: + * reinitialise the dynamic contents of the superblock in memory + * and reset them on disk. */ + if (journal_reset(journal)) + goto recovery_error; + + journal->j_flags &= ~JFS_ABORT; + journal->j_flags |= JFS_LOADED; + return 0; + +recovery_error: + printk (KERN_WARNING "JBD: recovery failed\n"); + return -EIO; +} + +/* + * Release a journal_t structure once it is no longer in use by the + * journaled object. + */ + +void journal_destroy (journal_t *journal) +{ + /* Wait for the commit thread to wake up and die. */ + journal_kill_thread(journal); + + /* Force a final log commit */ + if (journal->j_running_transaction) + journal_commit_transaction(journal); + + /* Force any old transactions to disk */ + lock_journal(journal); + while (journal->j_checkpoint_transactions != NULL) + log_do_checkpoint(journal, 1); + + J_ASSERT(journal->j_running_transaction == NULL); + J_ASSERT(journal->j_committing_transaction == NULL); + J_ASSERT(journal->j_checkpoint_transactions == NULL); + + /* We can now mark the journal as empty. */ + journal->j_tail = 0; + journal->j_tail_sequence = ++journal->j_transaction_sequence; + journal_update_superblock(journal, 1); + + if (journal->j_inode) + iput(journal->j_inode); + if (journal->j_revoke) + journal_destroy_revoke(journal); + + unlock_journal(journal); + brelse(journal->j_sb_buffer); + kfree(journal); + MOD_DEC_USE_COUNT; +} + + +/* Published API: Check whether the journal uses all of a given set of + * features. Return true (non-zero) if it does. */ + +int journal_check_used_features (journal_t *journal, unsigned long compat, + unsigned long ro, unsigned long incompat) +{ + journal_superblock_t *sb; + + if (!compat && !ro && !incompat) + return 1; + if (journal->j_format_version == 1) + return 0; + + sb = journal->j_superblock; + + if (((be32_to_cpu(sb->s_feature_compat) & compat) == compat) && + ((be32_to_cpu(sb->s_feature_ro_compat) & ro) == ro) && + ((be32_to_cpu(sb->s_feature_incompat) & incompat) == incompat)) + return 1; + + return 0; +} + +/* Published API: Check whether the journaling code supports the use of + * all of a given set of features on this journal. Return true + * (non-zero) if it can. */ + +int journal_check_available_features (journal_t *journal, unsigned long compat, + unsigned long ro, unsigned long incompat) +{ + journal_superblock_t *sb; + + if (!compat && !ro && !incompat) + return 1; + + sb = journal->j_superblock; + + /* We can support any known requested features iff the + * superblock is in version 2. Otherwise we fail to support any + * extended sb features. */ + + if (journal->j_format_version != 2) + return 0; + + if ((compat & JFS_KNOWN_COMPAT_FEATURES) == compat && + (ro & JFS_KNOWN_ROCOMPAT_FEATURES) == ro && + (incompat & JFS_KNOWN_INCOMPAT_FEATURES) == incompat) + return 1; + + return 0; +} + +/* Published API: Mark a given journal feature as present on the + * superblock. Returns true if the requested features could be set. */ + +int journal_set_features (journal_t *journal, unsigned long compat, + unsigned long ro, unsigned long incompat) +{ + journal_superblock_t *sb; + + if (journal_check_used_features(journal, compat, ro, incompat)) + return 1; + + if (!journal_check_available_features(journal, compat, ro, incompat)) + return 0; + + jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n", + compat, ro, incompat); + + sb = journal->j_superblock; + + sb->s_feature_compat |= cpu_to_be32(compat); + sb->s_feature_ro_compat |= cpu_to_be32(ro); + sb->s_feature_incompat |= cpu_to_be32(incompat); + + return 1; +} + + +/* + * Published API: + * Given an initialised but unloaded journal struct, poke about in the + * on-disk structure to update it to the most recent supported version. + */ + +int journal_update_format (journal_t *journal) +{ + journal_superblock_t *sb; + int err; + + err = journal_get_superblock(journal); + if (err) + return err; + + sb = journal->j_superblock; + + switch (ntohl(sb->s_header.h_blocktype)) { + case JFS_SUPERBLOCK_V2: + return 0; + case JFS_SUPERBLOCK_V1: + return journal_convert_superblock_v1(journal, sb); + default: + break; + } + return -EINVAL; +} + +static int journal_convert_superblock_v1(journal_t *journal, + journal_superblock_t *sb) +{ + int offset, blocksize; + struct buffer_head *bh; + + printk(KERN_WARNING + "JBD: Converting superblock from version 1 to 2.\n"); + + /* Pre-initialise new fields to zero */ + offset = ((char *) &(sb->s_feature_compat)) - ((char *) sb); + blocksize = ntohl(sb->s_blocksize); + memset(&sb->s_feature_compat, 0, blocksize-offset); + + sb->s_nr_users = cpu_to_be32(1); + sb->s_header.h_blocktype = cpu_to_be32(JFS_SUPERBLOCK_V2); + journal->j_format_version = 2; + + bh = journal->j_sb_buffer; + BUFFER_TRACE(bh, "marking dirty"); + mark_buffer_dirty(bh); + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + return 0; +} + + +/* + * Flush all data for a given journal to disk and empty the journal. + * Filesystems can use this when remounting readonly to ensure that + * recovery does not need to happen on remount. + */ + +int journal_flush (journal_t *journal) +{ + int err = 0; + transaction_t *transaction = NULL; + unsigned long old_tail; + + lock_kernel(); + + /* Force everything buffered to the log... */ + if (journal->j_running_transaction) { + transaction = journal->j_running_transaction; + log_start_commit(journal, transaction); + } else if (journal->j_committing_transaction) + transaction = journal->j_committing_transaction; + + /* Wait for the log commit to complete... */ + if (transaction) + log_wait_commit(journal, transaction->t_tid); + + /* ...and flush everything in the log out to disk. */ + lock_journal(journal); + while (!err && journal->j_checkpoint_transactions != NULL) + err = log_do_checkpoint(journal, journal->j_maxlen); + cleanup_journal_tail(journal); + + /* Finally, mark the journal as really needing no recovery. + * This sets s_start==0 in the underlying superblock, which is + * the magic code for a fully-recovered superblock. Any future + * commits of data to the journal will restore the current + * s_start value. */ + old_tail = journal->j_tail; + journal->j_tail = 0; + journal_update_superblock(journal, 1); + journal->j_tail = old_tail; + + unlock_journal(journal); + + J_ASSERT(!journal->j_running_transaction); + J_ASSERT(!journal->j_committing_transaction); + J_ASSERT(!journal->j_checkpoint_transactions); + J_ASSERT(journal->j_head == journal->j_tail); + J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence); + + unlock_kernel(); + + return err; +} + +/* + * Wipe out all of the contents of a journal, safely. This will produce + * a warning if the journal contains any valid recovery information. + * Must be called between journal_init_*() and journal_load(). + * + * If (write) is non-zero, then we wipe out the journal on disk; otherwise + * we merely suppress recovery. + */ + +int journal_wipe (journal_t *journal, int write) +{ + journal_superblock_t *sb; + int err = 0; + + J_ASSERT (!(journal->j_flags & JFS_LOADED)); + + err = load_superblock(journal); + if (err) + return err; + + sb = journal->j_superblock; + + if (!journal->j_tail) + goto no_recovery; + + printk (KERN_WARNING "JBD: %s recovery information on journal\n", + write ? "Clearing" : "Ignoring"); + + err = journal_skip_recovery(journal); + if (write) + journal_update_superblock(journal, 1); + + no_recovery: + return err; +} + +/* + * journal_dev_name: format a character string to describe on what + * device this journal is present. + */ + +const char * journal_dev_name(journal_t *journal) +{ + kdev_t dev; + + if (journal->j_inode) + dev = journal->j_inode->i_dev; + else + dev = journal->j_dev; + + return bdevname(dev); +} + +/* + * journal_abort: perform a complete, immediate shutdown of the ENTIRE + * journal (not of a single transaction). This operation cannot be + * undone without closing and reopening the journal. + * + * The journal_abort function is intended to support higher level error + * recovery mechanisms such as the ext2/ext3 remount-readonly error + * mode. + * + * Journal abort has very specific semantics. Any existing dirty, + * unjournaled buffers in the main filesystem will still be written to + * disk by bdflush, but the journaling mechanism will be suspended + * immediately and no further transaction commits will be honoured. + * + * Any dirty, journaled buffers will be written back to disk without + * hitting the journal. Atomicity cannot be guaranteed on an aborted + * filesystem, but we _do_ attempt to leave as much data as possible + * behind for fsck to use for cleanup. + * + * Any attempt to get a new transaction handle on a journal which is in + * ABORT state will just result in an -EROFS error return. A + * journal_stop on an existing handle will return -EIO if we have + * entered abort state during the update. + * + * Recursive transactions are not disturbed by journal abort until the + * final journal_stop, which will receive the -EIO error. + * + * Finally, the journal_abort call allows the caller to supply an errno + * which will be recored (if possible) in the journal superblock. This + * allows a client to record failure conditions in the middle of a + * transaction without having to complete the transaction to record the + * failure to disk. ext3_error, for example, now uses this + * functionality. + * + * Errors which originate from within the journaling layer will NOT + * supply an errno; a null errno implies that absolutely no further + * writes are done to the journal (unless there are any already in + * progress). + */ + +/* Quick version for internal journal use (doesn't lock the journal) */ +void __journal_abort (journal_t *journal) +{ + transaction_t *transaction; + + printk (KERN_ERR "Aborting journal on device %s.\n", + journal_dev_name(journal)); + + journal->j_flags |= JFS_ABORT; + transaction = journal->j_running_transaction; + if (transaction) + log_start_commit(journal, transaction); +} + +/* Full version for external use */ +void journal_abort (journal_t *journal, int errno) +{ + lock_journal(journal); + + if (journal->j_flags & JFS_ABORT) + goto out; + + if (!journal->j_errno) + journal->j_errno = errno; + + __journal_abort(journal); + + if (errno) + journal_update_superblock(journal, 1); + + out: + unlock_journal(journal); +} + +int journal_errno (journal_t *journal) +{ + int err; + + lock_journal(journal); + if (journal->j_flags & JFS_ABORT) + err = -EROFS; + else + err = journal->j_errno; + unlock_journal(journal); + return err; +} + +int journal_clear_err (journal_t *journal) +{ + int err = 0; + + lock_journal(journal); + if (journal->j_flags & JFS_ABORT) + err = -EROFS; + else + journal->j_errno = 0; + unlock_journal(journal); + return err; +} + +void journal_ack_err (journal_t *journal) +{ + lock_journal(journal); + if (journal->j_errno) + journal->j_flags |= JFS_ACK_ERR; + unlock_journal(journal); +} + +int journal_blocks_per_page(struct inode *inode) +{ + return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); +} + +/* + * shrink_journal_memory(). + * Called when we're under memory pressure. Free up all the written-back + * checkpointed metadata buffers. + */ +void shrink_journal_memory(void) +{ + struct list_head *list; + + lock_kernel(); + list_for_each(list, &all_journals) { + journal_t *journal = + list_entry(list, journal_t, j_all_journals); + spin_lock(&journal_datalist_lock); + __journal_clean_checkpoint_list(journal); + spin_unlock(&journal_datalist_lock); + } + unlock_kernel(); +} + +/* + * Simple support for retying memory allocations. Introduced to help to + * debug different VM deadlock avoidance strategies. + */ +/* + * Simple support for retying memory allocations. Introduced to help to + * debug different VM deadlock avoidance strategies. + */ +void * __jbd_kmalloc (char *where, size_t size, int flags, int retry) +{ + void *p; + static unsigned long last_warning; + + while (1) { + p = kmalloc(size, flags); + if (p) + return p; + if (!retry) + return NULL; + /* Log every retry for debugging. Also log them to the + * syslog, but do rate-limiting on the non-debugging + * messages. */ + jbd_debug(1, "ENOMEM in %s, retrying.\n", where); + + if (time_after(jiffies, last_warning + 5*HZ)) { + printk(KERN_NOTICE + "ENOMEM in %s, retrying.\n", where); + last_warning = jiffies; + } + + current->policy |= SCHED_YIELD; + schedule(); + } +} + +/* + * Journal_head storage management + */ +static kmem_cache_t *journal_head_cache; +#ifdef CONFIG_JBD_DEBUG +static atomic_t nr_journal_heads = ATOMIC_INIT(0); +#endif + +static int journal_init_journal_head_cache(void) +{ + int retval; + + J_ASSERT(journal_head_cache == 0); + journal_head_cache = kmem_cache_create("journal_head", + sizeof(struct journal_head), + 0, /* offset */ + 0, /* flags */ + NULL, /* ctor */ + NULL); /* dtor */ + retval = 0; + if (journal_head_cache == 0) { + retval = -ENOMEM; + printk(KERN_EMERG "JBD: no memory for journal_head cache\n"); + } + return retval; +} + +static void journal_destroy_journal_head_cache(void) +{ + J_ASSERT(journal_head_cache != NULL); + kmem_cache_destroy(journal_head_cache); + journal_head_cache = 0; +} + +/* + * journal_head splicing and dicing + */ +static struct journal_head *journal_alloc_journal_head(void) +{ + struct journal_head *ret; + static unsigned long last_warning; + +#ifdef CONFIG_JBD_DEBUG + atomic_inc(&nr_journal_heads); +#endif + ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); + if (ret == 0) { + jbd_debug(1, "out of memory for journal_head\n"); + if (time_after(jiffies, last_warning + 5*HZ)) { + printk(KERN_NOTICE "ENOMEM in " __FUNCTION__ + ", retrying.\n"); + last_warning = jiffies; + } + while (ret == 0) { + current->policy |= SCHED_YIELD; + schedule(); + ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); + } + } + return ret; +} + +static void journal_free_journal_head(struct journal_head *jh) +{ +#ifdef CONFIG_JBD_DEBUG + atomic_dec(&nr_journal_heads); + memset(jh, 0x5b, sizeof(*jh)); +#endif + kmem_cache_free(journal_head_cache, jh); +} + +/* + * A journal_head is attached to a buffer_head whenever JBD has an + * interest in the buffer. + * + * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit + * is set. This bit is tested in core kernel code where we need to take + * JBD-specific actions. Testing the zeroness of ->b_private is not reliable + * there. + * + * When a buffer has its BH_JBD bit set, its ->b_count is elevated by one. + * + * When a buffer has its BH_JBD bit set it is immune from being released by + * core kernel code, mainly via ->b_count. + * + * A journal_head may be detached from its buffer_head when the journal_head's + * b_transaction, b_cp_transaction and b_next_transaction pointers are NULL. + * Various places in JBD call journal_remove_journal_head() to indicate that the + * journal_head can be dropped if needed. + * + * Various places in the kernel want to attach a journal_head to a buffer_head + * _before_ attaching the journal_head to a transaction. To protect the + * journal_head in this situation, journal_add_journal_head elevates the + * journal_head's b_jcount refcount by one. The caller must call + * journal_unlock_journal_head() to undo this. + * + * So the typical usage would be: + * + * (Attach a journal_head if needed. Increments b_jcount) + * struct journal_head *jh = journal_add_journal_head(bh); + * ... + * jh->b_transaction = xxx; + * journal_unlock_journal_head(jh); + * + * Now, the journal_head's b_jcount is zero, but it is safe from being released + * because it has a non-zero b_transaction. + */ + +/* + * Give a buffer_head a journal_head. + * + * Doesn't need the journal lock. + * May sleep. + * Cannot be called with journal_datalist_lock held. + */ +struct journal_head *journal_add_journal_head(struct buffer_head *bh) +{ + struct journal_head *jh; + + spin_lock(&journal_datalist_lock); + if (buffer_jbd(bh)) { + jh = bh2jh(bh); + } else { + J_ASSERT_BH(bh, + (atomic_read(&bh->b_count) > 0) || + (bh->b_page && bh->b_page->mapping)); + spin_unlock(&journal_datalist_lock); + jh = journal_alloc_journal_head(); + memset(jh, 0, sizeof(*jh)); + spin_lock(&journal_datalist_lock); + + if (buffer_jbd(bh)) { + /* Someone did it for us! */ + J_ASSERT_BH(bh, bh->b_private != NULL); + journal_free_journal_head(jh); + jh = bh->b_private; + } else { + /* + * We actually don't need jh_splice_lock when + * adding a journal_head - only on removal. + */ + spin_lock(&jh_splice_lock); + set_bit(BH_JBD, &bh->b_state); + bh->b_private = jh; + jh->b_bh = bh; + atomic_inc(&bh->b_count); + spin_unlock(&jh_splice_lock); + BUFFER_TRACE(bh, "added journal_head"); + } + } + jh->b_jcount++; + spin_unlock(&journal_datalist_lock); + return bh->b_private; +} + +/* + * journal_remove_journal_head(): if the buffer isn't attached to a transaction + * and has a zero b_jcount then remove and release its journal_head. If we did + * see that the buffer is not used by any transaction we also "logically" + * decrement ->b_count. + * + * We in fact take an additional increment on ->b_count as a convenience, + * because the caller usually wants to do additional things with the bh + * after calling here. + * The caller of journal_remove_journal_head() *must* run __brelse(bh) at some + * time. Once the caller has run __brelse(), the buffer is eligible for + * reaping by try_to_free_buffers(). + * + * Requires journal_datalist_lock. + */ +void __journal_remove_journal_head(struct buffer_head *bh) +{ + struct journal_head *jh = bh2jh(bh); + + assert_spin_locked(&journal_datalist_lock); + J_ASSERT_JH(jh, jh->b_jcount >= 0); + atomic_inc(&bh->b_count); + if (jh->b_jcount == 0) { + if (jh->b_transaction == NULL && + jh->b_next_transaction == NULL && + jh->b_cp_transaction == NULL) { + J_ASSERT_BH(bh, buffer_jbd(bh)); + J_ASSERT_BH(bh, jh2bh(jh) == bh); + BUFFER_TRACE(bh, "remove journal_head"); + spin_lock(&jh_splice_lock); + bh->b_private = NULL; + jh->b_bh = NULL; /* debug, really */ + clear_bit(BH_JBD, &bh->b_state); + __brelse(bh); + spin_unlock(&jh_splice_lock); + journal_free_journal_head(jh); + } else { + BUFFER_TRACE(bh, "journal_head was locked"); + } + } +} + +void journal_unlock_journal_head(struct journal_head *jh) +{ + spin_lock(&journal_datalist_lock); + J_ASSERT_JH(jh, jh->b_jcount > 0); + --jh->b_jcount; + if (!jh->b_jcount && !jh->b_transaction) { + struct buffer_head *bh; + bh = jh2bh(jh); + __journal_remove_journal_head(bh); + __brelse(bh); + } + + spin_unlock(&journal_datalist_lock); +} + +void journal_remove_journal_head(struct buffer_head *bh) +{ + spin_lock(&journal_datalist_lock); + __journal_remove_journal_head(bh); + spin_unlock(&journal_datalist_lock); +} + +/* + * /proc tunables + */ +#if defined(CONFIG_JBD_DEBUG) +int journal_enable_debug; +EXPORT_SYMBOL(journal_enable_debug); +#endif + +#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS) + +static struct proc_dir_entry *proc_jbd_debug; + +int read_jbd_debug(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int ret; + + ret = sprintf(page + off, "%d\n", journal_enable_debug); + *eof = 1; + return ret; +} + +int write_jbd_debug(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char buf[32]; + + if (count > ARRAY_SIZE(buf) - 1) + count = ARRAY_SIZE(buf) - 1; + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + buf[ARRAY_SIZE(buf) - 1] = '\0'; + journal_enable_debug = simple_strtoul(buf, NULL, 10); + return count; +} + +#define JBD_PROC_NAME "sys/fs/jbd-debug" + +static void __init create_jbd_proc_entry(void) +{ + proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL); + if (proc_jbd_debug) { + /* Why is this so hard? */ + proc_jbd_debug->read_proc = read_jbd_debug; + proc_jbd_debug->write_proc = write_jbd_debug; + } +} + +static void __exit remove_jbd_proc_entry(void) +{ + if (proc_jbd_debug) + remove_proc_entry(JBD_PROC_NAME, NULL); +} + +#else + +#define create_jbd_proc_entry() do {} while (0) +#define remove_jbd_proc_entry() do {} while (0) + +#endif + +/* + * Module startup and shutdown + */ + +static int __init journal_init_caches(void) +{ + int ret; + + ret = journal_init_revoke_caches(); + if (ret == 0) + ret = journal_init_journal_head_cache(); + return ret; +} + +static void journal_destroy_caches(void) +{ + journal_destroy_revoke_caches(); + journal_destroy_journal_head_cache(); +} + +static int __init journal_init(void) +{ + int ret; + + printk(KERN_INFO "Journalled Block Device driver loaded\n"); + ret = journal_init_caches(); + if (ret != 0) + journal_destroy_caches(); + create_jbd_proc_entry(); + return ret; +} + +static void __exit journal_exit(void) +{ +#ifdef CONFIG_JBD_DEBUG + int n = atomic_read(&nr_journal_heads); + if (n) + printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n); +#endif + remove_jbd_proc_entry(); + journal_destroy_caches(); +} + +MODULE_LICENSE("GPL"); +module_init(journal_init); +module_exit(journal_exit); + diff -u --recursive --new-file v2.4.14/linux/fs/jbd/recovery.c linux/fs/jbd/recovery.c --- v2.4.14/linux/fs/jbd/recovery.c Wed Dec 31 16:00:00 1969 +++ linux/fs/jbd/recovery.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,586 @@ +/* + * linux/fs/recovery.c + * + * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 + * + * Copyright 1999-2000 Red Hat Software --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Journal recovery routines for the generic filesystem journaling code; + * part of the ext2fs journaling system. + */ + +#ifndef __KERNEL__ +#include "jfs_user.h" +#else +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/locks.h> +#endif + +/* + * Maintain information about the progress of the recovery job, so that + * the different passes can carry information between them. + */ +struct recovery_info +{ + tid_t start_transaction; + tid_t end_transaction; + + int nr_replays; + int nr_revokes; + int nr_revoke_hits; +}; + +enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY}; +static int do_one_pass(journal_t *journal, + struct recovery_info *info, enum passtype pass); +static int scan_revoke_records(journal_t *, struct buffer_head *, + tid_t, struct recovery_info *); + +#ifdef __KERNEL__ + +/* Release readahead buffers after use */ +void journal_brelse_array(struct buffer_head *b[], int n) +{ + while (--n >= 0) + brelse (b[n]); +} + + +/* + * When reading from the journal, we are going through the block device + * layer directly and so there is no readahead being done for us. We + * need to implement any readahead ourselves if we want it to happen at + * all. Recovery is basically one long sequential read, so make sure we + * do the IO in reasonably large chunks. + * + * This is not so critical that we need to be enormously clever about + * the readahead size, though. 128K is a purely arbitrary, good-enough + * fixed value. + */ + +#define MAXBUF 8 +static int do_readahead(journal_t *journal, unsigned int start) +{ + int err; + unsigned int max, nbufs, next, blocknr; + struct buffer_head *bh; + + struct buffer_head * bufs[MAXBUF]; + + /* Do up to 128K of readahead */ + max = start + (128 * 1024 / journal->j_blocksize); + if (max > journal->j_maxlen) + max = journal->j_maxlen; + + /* Do the readahead itself. We'll submit MAXBUF buffer_heads at + * a time to the block device IO layer. */ + + nbufs = 0; + + for (next = start; next < max; next++) { + blocknr = journal_bmap(journal, next); + + if (!blocknr) { + printk (KERN_ERR "JBD: bad block at offset %u\n", + next); + err = -EIO; + goto failed; + } + + bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); + if (!bh) { + err = -ENOMEM; + goto failed; + } + + if (!buffer_uptodate(bh) && !buffer_locked(bh)) { + bufs[nbufs++] = bh; + if (nbufs == MAXBUF) { + ll_rw_block(READ, nbufs, bufs); + journal_brelse_array(bufs, nbufs); + nbufs = 0; + } + } else + brelse(bh); + } + + if (nbufs) + ll_rw_block(READ, nbufs, bufs); + err = 0; + +failed: + if (nbufs) + journal_brelse_array(bufs, nbufs); + return err; +} + +#endif /* __KERNEL__ */ + + +/* + * Read a block from the journal + */ + +static int jread(struct buffer_head **bhp, journal_t *journal, + unsigned int offset) +{ + unsigned int blocknr; + struct buffer_head *bh; + + *bhp = NULL; + + J_ASSERT (offset < journal->j_maxlen); + + blocknr = journal_bmap(journal, offset); + + if (!blocknr) { + printk (KERN_ERR "JBD: bad block at offset %u\n", + offset); + return -EIO; + } + + bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); + if (!bh) + return -ENOMEM; + + if (!buffer_uptodate(bh)) { + /* If this is a brand new buffer, start readahead. + Otherwise, we assume we are already reading it. */ + if (!buffer_req(bh)) + do_readahead(journal, offset); + wait_on_buffer(bh); + } + + if (!buffer_uptodate(bh)) { + printk (KERN_ERR "JBD: Failed to read block at offset %u\n", + offset); + brelse(bh); + return -EIO; + } + + *bhp = bh; + return 0; +} + + +/* + * Count the number of in-use tags in a journal descriptor block. + */ + +static int count_tags(struct buffer_head *bh, int size) +{ + char * tagp; + journal_block_tag_t * tag; + int nr = 0; + + tagp = &bh->b_data[sizeof(journal_header_t)]; + + while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) { + tag = (journal_block_tag_t *) tagp; + + nr++; + tagp += sizeof(journal_block_tag_t); + if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID))) + tagp += 16; + + if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG)) + break; + } + + return nr; +} + + +/* Make sure we wrap around the log correctly! */ +#define wrap(journal, var) \ +do { \ + if (var >= (journal)->j_last) \ + var -= ((journal)->j_last - (journal)->j_first); \ +} while (0) + +/* + * journal_recover + * + * The primary function for recovering the log contents when mounting a + * journaled device. + * + * Recovery is done in three passes. In the first pass, we look for the + * end of the log. In the second, we assemble the list of revoke + * blocks. In the third and final pass, we replay any un-revoked blocks + * in the log. + */ + +int journal_recover(journal_t *journal) +{ + int err; + journal_superblock_t * sb; + + struct recovery_info info; + + memset(&info, 0, sizeof(info)); + sb = journal->j_superblock; + + /* + * The journal superblock's s_start field (the current log head) + * is always zero if, and only if, the journal was cleanly + * unmounted. + */ + + if (!sb->s_start) { + jbd_debug(1, "No recovery required, last transaction %d\n", + ntohl(sb->s_sequence)); + journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1; + return 0; + } + + + err = do_one_pass(journal, &info, PASS_SCAN); + if (!err) + err = do_one_pass(journal, &info, PASS_REVOKE); + if (!err) + err = do_one_pass(journal, &info, PASS_REPLAY); + + jbd_debug(0, "JBD: recovery, exit status %d, " + "recovered transactions %u to %u\n", + err, info.start_transaction, info.end_transaction); + jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n", + info.nr_replays, info.nr_revoke_hits, info.nr_revokes); + + /* Restart the log at the next transaction ID, thus invalidating + * any existing commit records in the log. */ + journal->j_transaction_sequence = ++info.end_transaction; + + journal_clear_revoke(journal); + fsync_no_super(journal->j_fs_dev); + return err; +} + +/* + * journal_skip_recovery + * + * Locate any valid recovery information from the journal and set up the + * journal structures in memory to ignore it (presumably because the + * caller has evidence that it is out of date). + * + * We perform one pass over the journal to allow us to tell the user how + * much recovery information is being erased, and to let us initialise + * the journal transaction sequence numbers to the next unused ID. + */ + +int journal_skip_recovery(journal_t *journal) +{ + int err; + journal_superblock_t * sb; + + struct recovery_info info; + + memset (&info, 0, sizeof(info)); + sb = journal->j_superblock; + + err = do_one_pass(journal, &info, PASS_SCAN); + + if (err) { + printk(KERN_ERR "JBD: error %d scanning journal\n", err); + ++journal->j_transaction_sequence; + } else { +#ifdef CONFIG_JBD_DEBUG + int dropped = info.end_transaction - ntohl(sb->s_sequence); +#endif + + jbd_debug(0, + "JBD: ignoring %d transaction%s from the journal.\n", + dropped, (dropped == 1) ? "" : "s"); + journal->j_transaction_sequence = ++info.end_transaction; + } + + journal->j_tail = 0; + + return err; +} + +static int do_one_pass(journal_t *journal, + struct recovery_info *info, enum passtype pass) +{ + + unsigned int first_commit_ID, next_commit_ID; + unsigned long next_log_block; + int err, success = 0; + journal_superblock_t * sb; + journal_header_t * tmp; + struct buffer_head * bh; + unsigned int sequence; + int blocktype; + + /* Precompute the maximum metadata descriptors in a descriptor block */ + int MAX_BLOCKS_PER_DESC; + MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t)) + / sizeof(journal_block_tag_t)); + + /* + * First thing is to establish what we expect to find in the log + * (in terms of transaction IDs), and where (in terms of log + * block offsets): query the superblock. + */ + + sb = journal->j_superblock; + next_commit_ID = ntohl(sb->s_sequence); + next_log_block = ntohl(sb->s_start); + + first_commit_ID = next_commit_ID; + if (pass == PASS_SCAN) + info->start_transaction = first_commit_ID; + + jbd_debug(1, "Starting recovery pass %d\n", pass); + + /* + * Now we walk through the log, transaction by transaction, + * making sure that each transaction has a commit block in the + * expected place. Each complete transaction gets replayed back + * into the main filesystem. + */ + + while (1) { + int flags; + char * tagp; + journal_block_tag_t * tag; + struct buffer_head * obh; + struct buffer_head * nbh; + + /* If we already know where to stop the log traversal, + * check right now that we haven't gone past the end of + * the log. */ + + if (pass != PASS_SCAN) + if (tid_geq(next_commit_ID, info->end_transaction)) + break; + + jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n", + next_commit_ID, next_log_block, journal->j_last); + + /* Skip over each chunk of the transaction looking + * either the next descriptor block or the final commit + * record. */ + + jbd_debug(3, "JBD: checking block %ld\n", next_log_block); + err = jread(&bh, journal, next_log_block); + if (err) + goto failed; + + next_log_block++; + wrap(journal, next_log_block); + + /* What kind of buffer is it? + * + * If it is a descriptor block, check that it has the + * expected sequence number. Otherwise, we're all done + * here. */ + + tmp = (journal_header_t *)bh->b_data; + + if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) { + brelse(bh); + break; + } + + blocktype = ntohl(tmp->h_blocktype); + sequence = ntohl(tmp->h_sequence); + jbd_debug(3, "Found magic %d, sequence %d\n", + blocktype, sequence); + + if (sequence != next_commit_ID) { + brelse(bh); + break; + } + + /* OK, we have a valid descriptor block which matches + * all of the sequence number checks. What are we going + * to do with it? That depends on the pass... */ + + switch(blocktype) { + case JFS_DESCRIPTOR_BLOCK: + /* If it is a valid descriptor block, replay it + * in pass REPLAY; otherwise, just skip over the + * blocks it describes. */ + if (pass != PASS_REPLAY) { + next_log_block += + count_tags(bh, journal->j_blocksize); + wrap(journal, next_log_block); + brelse(bh); + continue; + } + + /* A descriptor block: we can now write all of + * the data blocks. Yay, useful work is finally + * getting done here! */ + + tagp = &bh->b_data[sizeof(journal_header_t)]; + while ((tagp - bh->b_data +sizeof(journal_block_tag_t)) + <= journal->j_blocksize) { + unsigned long io_block; + + tag = (journal_block_tag_t *) tagp; + flags = ntohl(tag->t_flags); + + io_block = next_log_block++; + wrap(journal, next_log_block); + err = jread(&obh, journal, io_block); + if (err) { + /* Recover what we can, but + * report failure at the end. */ + success = err; + printk (KERN_ERR + "JBD: IO error %d recovering " + "block %ld in log\n", + err, io_block); + } else { + unsigned long blocknr; + + J_ASSERT(obh != NULL); + blocknr = ntohl(tag->t_blocknr); + + /* If the block has been + * revoked, then we're all done + * here. */ + if (journal_test_revoke + (journal, blocknr, + next_commit_ID)) { + brelse(obh); + ++info->nr_revoke_hits; + goto skip_write; + } + + /* Find a buffer for the new + * data being restored */ + nbh = getblk(journal->j_fs_dev, blocknr, + journal->j_blocksize); + if (nbh == NULL) { + printk(KERN_ERR + "JBD: Out of memory " + "during recovery.\n"); + err = -ENOMEM; + brelse(bh); + brelse(obh); + goto failed; + } + + memcpy(nbh->b_data, obh->b_data, + journal->j_blocksize); + if (flags & JFS_FLAG_ESCAPE) { + *((unsigned int *)bh->b_data) = + htonl(JFS_MAGIC_NUMBER); + } + + BUFFER_TRACE(nbh, "marking dirty"); + mark_buffer_dirty(nbh); + BUFFER_TRACE(nbh, "marking uptodate"); + mark_buffer_uptodate(nbh, 1); + ++info->nr_replays; + /* ll_rw_block(WRITE, 1, &nbh); */ + brelse(obh); + brelse(nbh); + } + + skip_write: + tagp += sizeof(journal_block_tag_t); + if (!(flags & JFS_FLAG_SAME_UUID)) + tagp += 16; + + if (flags & JFS_FLAG_LAST_TAG) + break; + } + + brelse(bh); + continue; + + case JFS_COMMIT_BLOCK: + /* Found an expected commit block: not much to + * do other than move on to the next sequence + * number. */ + brelse(bh); + next_commit_ID++; + continue; + + case JFS_REVOKE_BLOCK: + /* If we aren't in the REVOKE pass, then we can + * just skip over this block. */ + if (pass != PASS_REVOKE) { + brelse(bh); + continue; + } + + err = scan_revoke_records(journal, bh, + next_commit_ID, info); + brelse(bh); + if (err) + goto failed; + continue; + + default: + jbd_debug(3, "Unrecognised magic %d, end of scan.\n", + blocktype); + goto done; + } + } + + done: + /* + * We broke out of the log scan loop: either we came to the + * known end of the log or we found an unexpected block in the + * log. If the latter happened, then we know that the "current" + * transaction marks the end of the valid log. + */ + + if (pass == PASS_SCAN) + info->end_transaction = next_commit_ID; + else { + /* It's really bad news if different passes end up at + * different places (but possible due to IO errors). */ + if (info->end_transaction != next_commit_ID) { + printk (KERN_ERR "JBD: recovery pass %d ended at " + "transaction %u, expected %u\n", + pass, next_commit_ID, info->end_transaction); + if (!success) + success = -EIO; + } + } + + return success; + + failed: + return err; +} + + +/* Scan a revoke record, marking all blocks mentioned as revoked. */ + +static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, + tid_t sequence, struct recovery_info *info) +{ + journal_revoke_header_t *header; + int offset, max; + + header = (journal_revoke_header_t *) bh->b_data; + offset = sizeof(journal_revoke_header_t); + max = ntohl(header->r_count); + + while (offset < max) { + unsigned long blocknr; + int err; + + blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset))); + offset += 4; + err = journal_set_revoke(journal, blocknr, sequence); + if (err) + return err; + ++info->nr_revokes; + } + return 0; +} diff -u --recursive --new-file v2.4.14/linux/fs/jbd/revoke.c linux/fs/jbd/revoke.c --- v2.4.14/linux/fs/jbd/revoke.c Wed Dec 31 16:00:00 1969 +++ linux/fs/jbd/revoke.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,631 @@ +/* + * linux/fs/revoke.c + * + * Written by Stephen C. Tweedie <sct@redhat.com>, 2000 + * + * Copyright 2000 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Journal revoke routines for the generic filesystem journaling code; + * part of the ext2fs journaling system. + * + * Revoke is the mechanism used to prevent old log records for deleted + * metadata from being replayed on top of newer data using the same + * blocks. The revoke mechanism is used in two separate places: + * + * + Commit: during commit we write the entire list of the current + * transaction's revoked blocks to the journal + * + * + Recovery: during recovery we record the transaction ID of all + * revoked blocks. If there are multiple revoke records in the log + * for a single block, only the last one counts, and if there is a log + * entry for a block beyond the last revoke, then that log entry still + * gets replayed. + * + * We can get interactions between revokes and new log data within a + * single transaction: + * + * Block is revoked and then journaled: + * The desired end result is the journaling of the new block, so we + * cancel the revoke before the transaction commits. + * + * Block is journaled and then revoked: + * The revoke must take precedence over the write of the block, so we + * need either to cancel the journal entry or to write the revoke + * later in the log than the log block. In this case, we choose the + * latter: journaling a block cancels any revoke record for that block + * in the current transaction, so any revoke for that block in the + * transaction must have happened after the block was journaled and so + * the revoke must take precedence. + * + * Block is revoked and then written as data: + * The data write is allowed to succeed, but the revoke is _not_ + * cancelled. We still need to prevent old log records from + * overwriting the new data. We don't even need to clear the revoke + * bit here. + * + * Revoke information on buffers is a tri-state value: + * + * RevokeValid clear: no cached revoke status, need to look it up + * RevokeValid set, Revoked clear: + * buffer has not been revoked, and cancel_revoke + * need do nothing. + * RevokeValid set, Revoked set: + * buffer has been revoked. + */ + +#ifndef __KERNEL__ +#include "jfs_user.h" +#else +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/locks.h> +#include <linux/list.h> +#include <linux/smp_lock.h> +#include <linux/init.h> +#endif + +static kmem_cache_t *revoke_record_cache; +static kmem_cache_t *revoke_table_cache; + +/* Each revoke record represents one single revoked block. During + journal replay, this involves recording the transaction ID of the + last transaction to revoke this block. */ + +struct jbd_revoke_record_s +{ + struct list_head hash; + tid_t sequence; /* Used for recovery only */ + unsigned long blocknr; +}; + + +/* The revoke table is just a simple hash table of revoke records. */ +struct jbd_revoke_table_s +{ + /* It is conceivable that we might want a larger hash table + * for recovery. Must be a power of two. */ + int hash_size; + int hash_shift; + struct list_head *hash_table; +}; + + +#ifdef __KERNEL__ +static void write_one_revoke_record(journal_t *, transaction_t *, + struct journal_head **, int *, + struct jbd_revoke_record_s *); +static void flush_descriptor(journal_t *, struct journal_head *, int); +#endif + +/* Utility functions to maintain the revoke table */ + +/* Borrowed from buffer.c: this is a tried and tested block hash function */ +static inline int hash(journal_t *journal, unsigned long block) +{ + struct jbd_revoke_table_s *table = journal->j_revoke; + int hash_shift = table->hash_shift; + + return ((block << (hash_shift - 6)) ^ + (block >> 13) ^ + (block << (hash_shift - 12))) & (table->hash_size - 1); +} + +int insert_revoke_hash(journal_t *journal, unsigned long blocknr, tid_t seq) +{ + struct list_head *hash_list; + struct jbd_revoke_record_s *record; + +repeat: + record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS); + if (!record) + goto oom; + + record->sequence = seq; + record->blocknr = blocknr; + hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; + list_add(&record->hash, hash_list); + return 0; + +oom: + if (!journal_oom_retry) + return -ENOMEM; + jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n"); + current->policy |= SCHED_YIELD; + schedule(); + goto repeat; +} + +/* Find a revoke record in the journal's hash table. */ + +static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, + unsigned long blocknr) +{ + struct list_head *hash_list; + struct jbd_revoke_record_s *record; + + hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; + + record = (struct jbd_revoke_record_s *) hash_list->next; + while (&(record->hash) != hash_list) { + if (record->blocknr == blocknr) + return record; + record = (struct jbd_revoke_record_s *) record->hash.next; + } + return NULL; +} + +int __init journal_init_revoke_caches(void) +{ + revoke_record_cache = kmem_cache_create("revoke_record", + sizeof(struct jbd_revoke_record_s), + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + if (revoke_record_cache == 0) + return -ENOMEM; + + revoke_table_cache = kmem_cache_create("revoke_table", + sizeof(struct jbd_revoke_table_s), + 0, 0, NULL, NULL); + if (revoke_table_cache == 0) { + kmem_cache_destroy(revoke_record_cache); + revoke_record_cache = NULL; + return -ENOMEM; + } + return 0; +} + +void journal_destroy_revoke_caches(void) +{ + kmem_cache_destroy(revoke_record_cache); + revoke_record_cache = 0; + kmem_cache_destroy(revoke_table_cache); + revoke_table_cache = 0; +} + +/* Initialise the revoke table for a given journal to a given size. */ + +int journal_init_revoke(journal_t *journal, int hash_size) +{ + int shift, tmp; + + J_ASSERT (journal->j_revoke == NULL); + + journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); + if (!journal->j_revoke) + return -ENOMEM; + + /* Check that the hash_size is a power of two */ + J_ASSERT ((hash_size & (hash_size-1)) == 0); + + journal->j_revoke->hash_size = hash_size; + + shift = 0; + tmp = hash_size; + while((tmp >>= 1UL) != 0UL) + shift++; + journal->j_revoke->hash_shift = shift; + + journal->j_revoke->hash_table = + kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); + if (!journal->j_revoke->hash_table) { + kmem_cache_free(revoke_table_cache, journal->j_revoke); + journal->j_revoke = NULL; + return -ENOMEM; + } + + for (tmp = 0; tmp < hash_size; tmp++) + INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); + + return 0; +} + +/* Destoy a journal's revoke table. The table must already be empty! */ + +void journal_destroy_revoke(journal_t *journal) +{ + struct jbd_revoke_table_s *table; + struct list_head *hash_list; + int i; + + table = journal->j_revoke; + if (!table) + return; + + for (i=0; i<table->hash_size; i++) { + hash_list = &table->hash_table[i]; + J_ASSERT (list_empty(hash_list)); + } + + kfree(table->hash_table); + kmem_cache_free(revoke_table_cache, table); + journal->j_revoke = NULL; +} + + +#ifdef __KERNEL__ + +/* + * journal_revoke: revoke a given buffer_head from the journal. This + * prevents the block from being replayed during recovery if we take a + * crash after this current transaction commits. Any subsequent + * metadata writes of the buffer in this transaction cancel the + * revoke. + * + * Note that this call may block --- it is up to the caller to make + * sure that there are no further calls to journal_write_metadata + * before the revoke is complete. In ext3, this implies calling the + * revoke before clearing the block bitmap when we are deleting + * metadata. + * + * Revoke performs a journal_forget on any buffer_head passed in as a + * parameter, but does _not_ forget the buffer_head if the bh was only + * found implicitly. + * + * bh_in may not be a journalled buffer - it may have come off + * the hash tables without an attached journal_head. + * + * If bh_in is non-zero, journal_revoke() will decrement its b_count + * by one. + */ + +int journal_revoke(handle_t *handle, unsigned long blocknr, + struct buffer_head *bh_in) +{ + struct buffer_head *bh = NULL; + journal_t *journal; + kdev_t dev; + int err; + + if (bh_in) + BUFFER_TRACE(bh_in, "enter"); + + journal = handle->h_transaction->t_journal; + if (!journal_set_features(journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)){ + J_ASSERT (!"Cannot set revoke feature!"); + return -EINVAL; + } + + dev = journal->j_fs_dev; + bh = bh_in; + + if (!bh) { + bh = get_hash_table(dev, blocknr, journal->j_blocksize); + if (bh) + BUFFER_TRACE(bh, "found on hash"); + } +#ifdef JBD_EXPENSIVE_CHECKING + else { + struct buffer_head *bh2; + + /* If there is a different buffer_head lying around in + * memory anywhere... */ + bh2 = get_hash_table(dev, blocknr, journal->j_blocksize); + if (bh2) { + /* ... and it has RevokeValid status... */ + if ((bh2 != bh) && + test_bit(BH_RevokeValid, &bh2->b_state)) + /* ...then it better be revoked too, + * since it's illegal to create a revoke + * record against a buffer_head which is + * not marked revoked --- that would + * risk missing a subsequent revoke + * cancel. */ + J_ASSERT_BH(bh2, test_bit(BH_Revoked, & + bh2->b_state)); + __brelse(bh2); + } + } +#endif + + /* We really ought not ever to revoke twice in a row without + first having the revoke cancelled: it's illegal to free a + block twice without allocating it in between! */ + if (bh) { + J_ASSERT_BH(bh, !test_bit(BH_Revoked, &bh->b_state)); + set_bit(BH_Revoked, &bh->b_state); + set_bit(BH_RevokeValid, &bh->b_state); + if (bh_in) { + BUFFER_TRACE(bh_in, "call journal_forget"); + journal_forget(handle, bh_in); + } else { + BUFFER_TRACE(bh, "call brelse"); + __brelse(bh); + } + } + + lock_journal(journal); + jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in); + err = insert_revoke_hash(journal, blocknr, + handle->h_transaction->t_tid); + unlock_journal(journal); + BUFFER_TRACE(bh_in, "exit"); + return err; +} + +/* + * Cancel an outstanding revoke. For use only internally by the + * journaling code (called from journal_get_write_access). + * + * We trust the BH_Revoked bit on the buffer if the buffer is already + * being journaled: if there is no revoke pending on the buffer, then we + * don't do anything here. + * + * This would break if it were possible for a buffer to be revoked and + * discarded, and then reallocated within the same transaction. In such + * a case we would have lost the revoked bit, but when we arrived here + * the second time we would still have a pending revoke to cancel. So, + * do not trust the Revoked bit on buffers unless RevokeValid is also + * set. + * + * The caller must have the journal locked. + */ +int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) +{ + struct jbd_revoke_record_s *record; + journal_t *journal = handle->h_transaction->t_journal; + int need_cancel; + int did_revoke = 0; /* akpm: debug */ + struct buffer_head *bh = jh2bh(jh); + + jbd_debug(4, "journal_head %p, cancelling revoke\n", jh); + + /* Is the existing Revoke bit valid? If so, we trust it, and + * only perform the full cancel if the revoke bit is set. If + * not, we can't trust the revoke bit, and we need to do the + * full search for a revoke record. */ + if (test_and_set_bit(BH_RevokeValid, &bh->b_state)) + need_cancel = (test_and_clear_bit(BH_Revoked, &bh->b_state)); + else { + need_cancel = 1; + clear_bit(BH_Revoked, &bh->b_state); + } + + if (need_cancel) { + record = find_revoke_record(journal, bh->b_blocknr); + if (record) { + jbd_debug(4, "cancelled existing revoke on " + "blocknr %lu\n", bh->b_blocknr); + list_del(&record->hash); + kmem_cache_free(revoke_record_cache, record); + did_revoke = 1; + } + } + +#ifdef JBD_EXPENSIVE_CHECKING + /* There better not be one left behind by now! */ + record = find_revoke_record(journal, bh->b_blocknr); + J_ASSERT_JH(jh, record == NULL); +#endif + + /* Finally, have we just cleared revoke on an unhashed + * buffer_head? If so, we'd better make sure we clear the + * revoked status on any hashed alias too, otherwise the revoke + * state machine will get very upset later on. */ + if (need_cancel && !bh->b_pprev) { + struct buffer_head *bh2; + bh2 = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size); + if (bh2) { + clear_bit(BH_Revoked, &bh2->b_state); + __brelse(bh2); + } + } + + return did_revoke; +} + + +/* + * Write revoke records to the journal for all entries in the current + * revoke hash, deleting the entries as we go. + * + * Called with the journal lock held. + */ + +void journal_write_revoke_records(journal_t *journal, + transaction_t *transaction) +{ + struct journal_head *descriptor; + struct jbd_revoke_record_s *record; + struct jbd_revoke_table_s *revoke; + struct list_head *hash_list; + int i, offset, count; + + descriptor = NULL; + offset = 0; + count = 0; + revoke = journal->j_revoke; + + for (i = 0; i < revoke->hash_size; i++) { + hash_list = &revoke->hash_table[i]; + + while (!list_empty(hash_list)) { + record = (struct jbd_revoke_record_s *) + hash_list->next; + write_one_revoke_record(journal, transaction, + &descriptor, &offset, + record); + count++; + list_del(&record->hash); + kmem_cache_free(revoke_record_cache, record); + } + } + if (descriptor) + flush_descriptor(journal, descriptor, offset); + jbd_debug(1, "Wrote %d revoke records\n", count); +} + +/* + * Write out one revoke record. We need to create a new descriptor + * block if the old one is full or if we have not already created one. + */ + +static void write_one_revoke_record(journal_t *journal, + transaction_t *transaction, + struct journal_head **descriptorp, + int *offsetp, + struct jbd_revoke_record_s *record) +{ + struct journal_head *descriptor; + int offset; + journal_header_t *header; + + /* If we are already aborting, this all becomes a noop. We + still need to go round the loop in + journal_write_revoke_records in order to free all of the + revoke records: only the IO to the journal is omitted. */ + if (is_journal_aborted(journal)) + return; + + descriptor = *descriptorp; + offset = *offsetp; + + /* Make sure we have a descriptor with space left for the record */ + if (descriptor) { + if (offset == journal->j_blocksize) { + flush_descriptor(journal, descriptor, offset); + descriptor = NULL; + } + } + + if (!descriptor) { + descriptor = journal_get_descriptor_buffer(journal); + header = (journal_header_t *) &jh2bh(descriptor)->b_data[0]; + header->h_magic = htonl(JFS_MAGIC_NUMBER); + header->h_blocktype = htonl(JFS_REVOKE_BLOCK); + header->h_sequence = htonl(transaction->t_tid); + + /* Record it so that we can wait for IO completion later */ + JBUFFER_TRACE(descriptor, "file as BJ_LogCtl"); + journal_file_buffer(descriptor, transaction, BJ_LogCtl); + + offset = sizeof(journal_revoke_header_t); + *descriptorp = descriptor; + } + + * ((unsigned int *)(&jh2bh(descriptor)->b_data[offset])) = + htonl(record->blocknr); + offset += 4; + *offsetp = offset; +} + +/* + * Flush a revoke descriptor out to the journal. If we are aborting, + * this is a noop; otherwise we are generating a buffer which needs to + * be waited for during commit, so it has to go onto the appropriate + * journal buffer list. + */ + +static void flush_descriptor(journal_t *journal, + struct journal_head *descriptor, + int offset) +{ + journal_revoke_header_t *header; + + if (is_journal_aborted(journal)) { + JBUFFER_TRACE(descriptor, "brelse"); + __brelse(jh2bh(descriptor)); + return; + } + + header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data; + header->r_count = htonl(offset); + set_bit(BH_JWrite, &jh2bh(descriptor)->b_state); + { + struct buffer_head *bh = jh2bh(descriptor); + BUFFER_TRACE(bh, "write"); + ll_rw_block (WRITE, 1, &bh); + } +} + +#endif + +/* + * Revoke support for recovery. + * + * Recovery needs to be able to: + * + * record all revoke records, including the tid of the latest instance + * of each revoke in the journal + * + * check whether a given block in a given transaction should be replayed + * (ie. has not been revoked by a revoke record in that or a subsequent + * transaction) + * + * empty the revoke table after recovery. + */ + +/* + * First, setting revoke records. We create a new revoke record for + * every block ever revoked in the log as we scan it for recovery, and + * we update the existing records if we find multiple revokes for a + * single block. + */ + +int journal_set_revoke(journal_t *journal, + unsigned long blocknr, + tid_t sequence) +{ + struct jbd_revoke_record_s *record; + + record = find_revoke_record(journal, blocknr); + if (record) { + /* If we have multiple occurences, only record the + * latest sequence number in the hashed record */ + if (tid_gt(sequence, record->sequence)) + record->sequence = sequence; + return 0; + } + return insert_revoke_hash(journal, blocknr, sequence); +} + +/* + * Test revoke records. For a given block referenced in the log, has + * that block been revoked? A revoke record with a given transaction + * sequence number revokes all blocks in that transaction and earlier + * ones, but later transactions still need replayed. + */ + +int journal_test_revoke(journal_t *journal, + unsigned long blocknr, + tid_t sequence) +{ + struct jbd_revoke_record_s *record; + + record = find_revoke_record(journal, blocknr); + if (!record) + return 0; + if (tid_gt(sequence, record->sequence)) + return 0; + return 1; +} + +/* + * Finally, once recovery is over, we need to clear the revoke table so + * that it can be reused by the running filesystem. + */ + +void journal_clear_revoke(journal_t *journal) +{ + int i; + struct list_head *hash_list; + struct jbd_revoke_record_s *record; + struct jbd_revoke_table_s *revoke; + + revoke = journal->j_revoke; + + for (i = 0; i < revoke->hash_size; i++) { + hash_list = &revoke->hash_table[i]; + while (!list_empty(hash_list)) { + record = (struct jbd_revoke_record_s*) hash_list->next; + list_del(&record->hash); + kmem_cache_free(revoke_record_cache, record); + } + } +} + diff -u --recursive --new-file v2.4.14/linux/fs/jbd/transaction.c linux/fs/jbd/transaction.c --- v2.4.14/linux/fs/jbd/transaction.c Wed Dec 31 16:00:00 1969 +++ linux/fs/jbd/transaction.c Fri Nov 9 14:25:04 2001 @@ -0,0 +1,2070 @@ +/* + * linux/fs/transaction.c + * + * Written by Stephen C. Tweedie <sct@redhat.com>, 1998 + * + * Copyright 1998 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Generic filesystem transaction handling code; part of the ext2fs + * journaling system. + * + * This file manages transactions (compound commits managed by the + * journaling code) and handles (individual atomic operations by the + * filesystem). + */ + +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/locks.h> +#include <linux/timer.h> +#include <linux/smp_lock.h> +#include <linux/mm.h> + +extern spinlock_t journal_datalist_lock; + +/* + * get_transaction: obtain a new transaction_t object. + * + * Simply allocate and initialise a new transaction. Create it in + * RUNNING state and add it to the current journal (which should not + * have an existing running transaction: we only make a new transaction + * once we have started to commit the old one). + * + * Preconditions: + * The journal MUST be locked. We don't perform atomic mallocs on the + * new transaction and we can't block without protecting against other + * processes trying to touch the journal while it is in transition. + */ + +static transaction_t * get_transaction (journal_t * journal, int is_try) +{ + transaction_t * transaction; + + transaction = jbd_kmalloc (sizeof (transaction_t), GFP_NOFS); + if (!transaction) + return NULL; + + memset (transaction, 0, sizeof (transaction_t)); + + transaction->t_journal = journal; + transaction->t_state = T_RUNNING; + transaction->t_tid = journal->j_transaction_sequence++; + transaction->t_expires = jiffies + journal->j_commit_interval; + + /* Set up the commit timer for the new transaction. */ + J_ASSERT (!journal->j_commit_timer_active); + journal->j_commit_timer_active = 1; + journal->j_commit_timer->expires = transaction->t_expires; + add_timer(journal->j_commit_timer); + + J_ASSERT (journal->j_running_transaction == NULL); + journal->j_running_transaction = transaction; + + return transaction; +} + +/* + * Handle management. + * + * A handle_t is an object which represents a single atomic update to a + * filesystem, and which tracks all of the modifications which form part + * of that one update. + */ + +/* + * start_this_handle: Given a handle, deal with any locking or stalling + * needed to make sure that there is enough journal space for the handle + * to begin. Attach the handle to a transaction and set up the + * transaction's buffer credits. + */ + +static int start_this_handle(journal_t *journal, handle_t *handle) +{ + transaction_t *transaction; + int needed; + int nblocks = handle->h_buffer_credits; + + jbd_debug(3, "New handle %p going live.\n", handle); + +repeat: + + lock_journal(journal); + + if (is_journal_aborted(journal) || + (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) { + unlock_journal(journal); + return -EROFS; + } + + /* Wait on the journal's transaction barrier if necessary */ + if (journal->j_barrier_count) { + unlock_journal(journal); + sleep_on(&journal->j_wait_transaction_locked); + goto repeat; + } + +repeat_locked: + if (!journal->j_running_transaction) + get_transaction(journal, 0); + /* @@@ Error? */ + J_ASSERT(journal->j_running_transaction); + + transaction = journal->j_running_transaction; + + /* If the current transaction is locked down for commit, wait + * for the lock to be released. */ + + if (transaction->t_state == T_LOCKED) { + unlock_journal(journal); + jbd_debug(3, "Handle %p stalling...\n", handle); + sleep_on(&journal->j_wait_transaction_locked); + goto repeat; + } + + /* If there is not enough space left in the log to write all + * potential buffers requested by this operation, we need to + * stall pending a log checkpoint to free some more log + * space. */ + + needed = transaction->t_outstanding_credits + nblocks; + + if (needed > journal->j_max_transaction_buffers) { + /* If the current transaction is already too large, then + * start to commit it: we can then go back and attach + * this handle to a new transaction. */ + + jbd_debug(2, "Handle %p starting new commit...\n", handle); + log_start_commit(journal, transaction); + unlock_journal(journal); + sleep_on(&journal->j_wait_transaction_locked); + lock_journal(journal); + goto repeat_locked; + } + + /* + * The commit code assumes that it can get enough log space + * without forcing a checkpoint. This is *critical* for + * correctness: a checkpoint of a buffer which is also + * associated with a committing transaction creates a deadlock, + * so commit simply cannot force through checkpoints. + * + * We must therefore ensure the necessary space in the journal + * *before* starting to dirty potentially checkpointed buffers + * in the new transaction. + * + * The worst part is, any transaction currently committing can + * reduce the free space arbitrarily. Be careful to account for + * those buffers when checkpointing. + */ + + /* + * @@@ AKPM: This seems rather over-defensive. We're giving commit + * a _lot_ of headroom: 1/4 of the journal plus the size of + * the committing transaction. Really, we only need to give it + * committing_transaction->t_outstanding_credits plus "enough" for + * the log control blocks. + * Also, this test is inconsitent with the matching one in + * journal_extend(). + */ + needed = journal->j_max_transaction_buffers; + if (journal->j_committing_transaction) + needed += journal->j_committing_transaction-> + t_outstanding_credits; + + if (log_space_left(journal) < needed) { + jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); + log_wait_for_space(journal, needed); + goto repeat_locked; + } + + /* OK, account for the buffers that this operation expects to + * use and add the handle to the running transaction. */ + + handle->h_transaction = transaction; + transaction->t_outstanding_credits += nblocks; + transaction->t_updates++; + transaction->t_handle_count++; + jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", + handle, nblocks, transaction->t_outstanding_credits, + log_space_left(journal)); + + unlock_journal(journal); + + return 0; +} + +/* + * Obtain a new handle. + * + * We make sure that the transaction can guarantee at least nblocks of + * modified buffers in the log. We block until the log can guarantee + * that much space. + * + * This function is visible to journal users (like ext2fs), so is not + * called with the journal already locked. + * + * Return a pointer to a newly allocated handle, or NULL on failure + */ + +handle_t *journal_start(journal_t *journal, int nblocks) +{ + handle_t *handle = journal_current_handle(); + int err; + + if (!journal) + return ERR_PTR(-EROFS); + + if (handle) { + J_ASSERT(handle->h_transaction->t_journal == journal); + handle->h_ref++; + return handle; + } + + handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS); + if (!handle) + return ERR_PTR(-ENOMEM); + memset (handle, 0, sizeof (handle_t)); + + handle->h_buffer_credits = nblocks; + handle->h_ref = 1; + current->journal_info = handle; + + err = start_this_handle(journal, handle); + if (err < 0) { + kfree(handle); + current->journal_info = NULL; + return ERR_PTR(err); + } + + return handle; +} + +/* + * Return zero on success + */ +static int try_start_this_handle(journal_t *journal, handle_t *handle) +{ + transaction_t *transaction; + int needed; + int nblocks = handle->h_buffer_credits; + int ret = 0; + + jbd_debug(3, "New handle %p maybe going live.\n", handle); + + lock_journal(journal); + + if (is_journal_aborted(journal) || + (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) { + ret = -EROFS; + goto fail_unlock; + } + + if (journal->j_barrier_count) + goto fail_unlock; + + if (!journal->j_running_transaction && get_transaction(journal, 1) == 0) + goto fail_unlock; + + transaction = journal->j_running_transaction; + if (transaction->t_state == T_LOCKED) + goto fail_unlock; + + needed = transaction->t_outstanding_credits + nblocks; + /* We could run log_start_commit here */ + if (needed > journal->j_max_transaction_buffers) + goto fail_unlock; + + needed = journal->j_max_transaction_buffers; + if (journal->j_committing_transaction) + needed += journal->j_committing_transaction-> + t_outstanding_credits; + + if (log_space_left(journal) < needed) + goto fail_unlock; + + handle->h_transaction = transaction; + transaction->t_outstanding_credits += nblocks; + transaction->t_updates++; + jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", + handle, nblocks, transaction->t_outstanding_credits, + log_space_left(journal)); + unlock_journal(journal); + return 0; + +fail_unlock: + unlock_journal(journal); + if (ret >= 0) + ret = -1; + return ret; +} + +/* + * Try to start a handle, but non-blockingly. If we weren't able + * to, return an ERR_PTR value. + */ +handle_t *journal_try_start(journal_t *journal, int nblocks) +{ + handle_t *handle = journal_current_handle(); + int err; + + if (!journal) + return ERR_PTR(-EROFS); + + if (handle) { + jbd_debug(4, "h_ref %d -> %d\n", + handle->h_ref, + handle->h_ref + 1); + J_ASSERT(handle->h_transaction->t_journal == journal); + if (is_handle_aborted(handle)) + return ERR_PTR(-EIO); + handle->h_ref++; + return handle; + } else { + jbd_debug(4, "no current transaction\n"); + } + + if (is_journal_aborted(journal)) + return ERR_PTR(-EIO); + + handle = jbd_kmalloc(sizeof (handle_t), GFP_NOFS); + if (!handle) + return ERR_PTR(-ENOMEM); + memset (handle, 0, sizeof (handle_t)); + + handle->h_buffer_credits = nblocks; + handle->h_ref = 1; + current->journal_info = handle; + + err = try_start_this_handle(journal, handle); + if (err < 0) { + kfree(handle); + current->journal_info = NULL; + return ERR_PTR(err); + } + + return handle; +} + +/* + * journal_extend: extend buffer credits. + * + * Some transactions, such as large extends and truncates, can be done + * atomically all at once or in several stages. The operation requests + * a credit for a number of buffer modications in advance, but can + * extend its credit if it needs more. + * + * journal_extend tries to give the running handle more buffer credits. + * It does not guarantee that allocation: this is a best-effort only. + * The calling process MUST be able to deal cleanly with a failure to + * extend here. + * + * Return 0 on success, non-zero on failure. + * + * return code < 0 implies an error + * return code > 0 implies normal transaction-full status. + */ + +int journal_extend (handle_t *handle, int nblocks) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + int result; + int wanted; + + lock_journal (journal); + + result = -EIO; + if (is_handle_aborted(handle)) + goto error_out; + + result = 1; + + /* Don't extend a locked-down transaction! */ + if (handle->h_transaction->t_state != T_RUNNING) { + jbd_debug(3, "denied handle %p %d blocks: " + "transaction not running\n", handle, nblocks); + goto error_out; + } + + wanted = transaction->t_outstanding_credits + nblocks; + + if (wanted > journal->j_max_transaction_buffers) { + jbd_debug(3, "denied handle %p %d blocks: " + "transaction too large\n", handle, nblocks); + goto error_out; + } + + if (wanted > log_space_left(journal)) { + jbd_debug(3, "denied handle %p %d blocks: " + "insufficient log space\n", handle, nblocks); + goto error_out; + } + + handle->h_buffer_credits += nblocks; + transaction->t_outstanding_credits += nblocks; + result = 0; + + jbd_debug(3, "extended handle %p by %d\n", handle, nblocks); + +error_out: + unlock_journal (journal); + return result; +} + + +/* + * journal_restart: restart a handle for a multi-transaction filesystem + * operation. + * + * If the journal_extend() call above fails to grant new buffer credits + * to a running handle, a call to journal_restart will commit the + * handle's transaction so far and reattach the handle to a new + * transaction capabable of guaranteeing the requested number of + * credits. + */ + +int journal_restart(handle_t *handle, int nblocks) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + int ret; + + /* If we've had an abort of any type, don't even think about + * actually doing the restart! */ + if (is_handle_aborted(handle)) + return 0; + + /* First unlink the handle from its current transaction, and + * start the commit on that. */ + + J_ASSERT (transaction->t_updates > 0); + J_ASSERT (journal_current_handle() == handle); + + transaction->t_outstanding_credits -= handle->h_buffer_credits; + transaction->t_updates--; + + if (!transaction->t_updates) + wake_up(&journal->j_wait_updates); + + jbd_debug(2, "restarting handle %p\n", handle); + log_start_commit(journal, transaction); + + handle->h_buffer_credits = nblocks; + ret = start_this_handle(journal, handle); + return ret; +} + + +/* + * Barrier operation: establish a transaction barrier. + * + * This locks out any further updates from being started, and blocks + * until all existing updates have completed, returning only once the + * journal is in a quiescent state with no updates running. + * + * The journal lock should not be held on entry. + */ + +void journal_lock_updates (journal_t *journal) +{ + lock_journal(journal); + ++journal->j_barrier_count; + + /* Wait until there are no running updates */ + while (1) { + transaction_t *transaction = journal->j_running_transaction; + if (!transaction) + break; + if (!transaction->t_updates) + break; + + unlock_journal(journal); + sleep_on(&journal->j_wait_updates); + lock_journal(journal); + } + + unlock_journal(journal); + + /* We have now established a barrier against other normal + * updates, but we also need to barrier against other + * journal_lock_updates() calls to make sure that we serialise + * special journal-locked operations too. */ + down(&journal->j_barrier); +} + +/* + * Release a transaction barrier obtained with journal_lock_updates(). + * + * Should be called without the journal lock held. + */ + +void journal_unlock_updates (journal_t *journal) +{ + lock_journal(journal); + + J_ASSERT (journal->j_barrier_count != 0); + + up(&journal->j_barrier); + --journal->j_barrier_count; + wake_up(&journal->j_wait_transaction_locked); + unlock_journal(journal); +} + +/* + * journal_get_write_access: notify intent to modify a buffer for metadata + * (not data) update. + * + * If the buffer is already part of the current transaction, then there + * is nothing we need to do. If it is already part of a prior + * transaction which we are still committing to disk, then we need to + * make sure that we do not overwrite the old copy: we do copy-out to + * preserve the copy going to disk. We also account the buffer against + * the handle's metadata buffer credits (unless the buffer is already + * part of the transaction, that is). + * + * Returns an error code or 0 on success. + * + * In full data journalling mode the buffer may be of type BJ_AsyncData, + * because we're write()ing a buffer which is also part of a shared mapping. + */ + +static int +do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + int error; + char *frozen_buffer = NULL; + int need_copy = 0; + + jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy); + + JBUFFER_TRACE(jh, "entry"); +repeat: + /* @@@ Need to check for errors here at some point. */ + + /* + * AKPM: neither bdflush nor kupdate run with the BKL. There's + * nothing we can do to prevent them from starting writeout of a + * BUF_DIRTY buffer at any time. And checkpointing buffers are on + * BUF_DIRTY. So. We no longer assert that the buffer is unlocked. + * + * However. It is very wrong for us to allow ext3 to start directly + * altering the ->b_data of buffers which may at that very time be + * undergoing writeout to the client filesystem. This can leave + * the filesystem in an inconsistent, transient state if we crash. + * So what we do is to steal the buffer if it is in checkpoint + * mode and dirty. The journal lock will keep out checkpoint-mode + * state transitions within journal_remove_checkpoint() and the buffer + * is locked to keep bdflush/kupdate/whoever away from it as well. + * + * AKPM: we have replaced all the lock_journal_bh_wait() stuff with a + * simple lock_journal(). This code here will care for locked buffers. + */ + /* + * The buffer_locked() || buffer_dirty() tests here are simply an + * optimisation tweak. If anyone else in the system decides to + * lock this buffer later on, we'll blow up. There doesn't seem + * to be a good reason why they should do this. + */ + if (jh->b_cp_transaction && + (buffer_locked(jh2bh(jh)) || buffer_dirty(jh2bh(jh)))) { + unlock_journal(journal); + lock_buffer(jh2bh(jh)); + spin_lock(&journal_datalist_lock); + if (jh->b_cp_transaction && buffer_dirty(jh2bh(jh))) { + /* OK, we need to steal it */ + JBUFFER_TRACE(jh, "stealing from checkpoint mode"); + J_ASSERT_JH(jh, jh->b_next_transaction == NULL); + J_ASSERT_JH(jh, jh->b_frozen_data == NULL); + + J_ASSERT(handle->h_buffer_credits > 0); + handle->h_buffer_credits--; + + /* This will clear BH_Dirty and set BH_JBDDirty. */ + JBUFFER_TRACE(jh, "file as BJ_Reserved"); + __journal_file_buffer(jh, transaction, BJ_Reserved); + + /* And pull it off BUF_DIRTY, onto BUF_CLEAN */ + refile_buffer(jh2bh(jh)); + + /* + * The buffer is now hidden from bdflush. It is + * metadata against the current transaction. + */ + JBUFFER_TRACE(jh, "steal from cp mode is complete"); + } + spin_unlock(&journal_datalist_lock); + unlock_buffer(jh2bh(jh)); + lock_journal(journal); + } + + J_ASSERT_JH(jh, !buffer_locked(jh2bh(jh))); + + error = -EROFS; + if (is_handle_aborted(handle)) + goto out_unlocked; + error = 0; + + spin_lock(&journal_datalist_lock); + + /* The buffer is already part of this transaction if + * b_transaction or b_next_transaction points to it. */ + + if (jh->b_transaction == transaction || + jh->b_next_transaction == transaction) + goto done_locked; + + /* If there is already a copy-out version of this buffer, then + * we don't need to make another one. */ + + if (jh->b_frozen_data) { + JBUFFER_TRACE(jh, "has frozen data"); + J_ASSERT_JH(jh, jh->b_next_transaction == NULL); + jh->b_next_transaction = transaction; + + J_ASSERT_JH(jh, handle->h_buffer_credits > 0); + handle->h_buffer_credits--; + goto done_locked; + } + + /* Is there data here we need to preserve? */ + + if (jh->b_transaction && jh->b_transaction != transaction) { + JBUFFER_TRACE(jh, "owned by older transaction"); + J_ASSERT_JH(jh, jh->b_next_transaction == NULL); + J_ASSERT_JH(jh, jh->b_transaction == + journal->j_committing_transaction); + + /* There is one case we have to be very careful about. + * If the committing transaction is currently writing + * this buffer out to disk and has NOT made a copy-out, + * then we cannot modify the buffer contents at all + * right now. The essence of copy-out is that it is the + * extra copy, not the primary copy, which gets + * journaled. If the primary copy is already going to + * disk then we cannot do copy-out here. */ + + if (jh->b_jlist == BJ_Shadow) { + JBUFFER_TRACE(jh, "on shadow: sleep"); + spin_unlock(&journal_datalist_lock); + unlock_journal(journal); + /* commit wakes up all shadow buffers after IO */ + sleep_on(&jh2bh(jh)->b_wait); + lock_journal(journal); + goto repeat; + } + + /* Only do the copy if the currently-owning transaction + * still needs it. If it is on the Forget list, the + * committing transaction is past that stage. The + * buffer had better remain locked during the kmalloc, + * but that should be true --- we hold the journal lock + * still and the buffer is already on the BUF_JOURNAL + * list so won't be flushed. + * + * Subtle point, though: if this is a get_undo_access, + * then we will be relying on the frozen_data to contain + * the new value of the committed_data record after the + * transaction, so we HAVE to force the frozen_data copy + * in that case. */ + + if (jh->b_jlist != BJ_Forget || force_copy) { + JBUFFER_TRACE(jh, "generate frozen data"); + if (!frozen_buffer) { + JBUFFER_TRACE(jh, "allocate memory for buffer"); + spin_unlock(&journal_datalist_lock); + unlock_journal(journal); + frozen_buffer = jbd_kmalloc(jh2bh(jh)->b_size, + GFP_NOFS); + lock_journal(journal); + if (!frozen_buffer) { + printk(KERN_EMERG __FUNCTION__ + "OOM for frozen_buffer\n"); + JBUFFER_TRACE(jh, "oom!"); + error = -ENOMEM; + spin_lock(&journal_datalist_lock); + goto done_locked; + } + goto repeat; + } + + jh->b_frozen_data = frozen_buffer; + frozen_buffer = NULL; + need_copy = 1; + } + jh->b_next_transaction = transaction; + } + + J_ASSERT(handle->h_buffer_credits > 0); + handle->h_buffer_credits--; + + /* Finally, if the buffer is not journaled right now, we need to + * make sure it doesn't get written to disk before the caller + * actually commits the new data. */ + + if (!jh->b_transaction) { + JBUFFER_TRACE(jh, "no transaction"); + J_ASSERT_JH(jh, !jh->b_next_transaction); + jh->b_transaction = transaction; + JBUFFER_TRACE(jh, "file as BJ_Reserved"); + __journal_file_buffer(jh, transaction, BJ_Reserved); + } + +done_locked: + spin_unlock(&journal_datalist_lock); + if (need_copy) { + struct page *page; + int offset; + char *source; + + J_ASSERT_JH(jh, buffer_uptodate(jh2bh(jh))); + page = jh2bh(jh)->b_page; + offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK; + source = kmap(page); + memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size); + kunmap(page); + } + + + /* If we are about to journal a buffer, then any revoke pending + on it is no longer valid. */ + journal_cancel_revoke(handle, jh); + +out_unlocked: + if (frozen_buffer) + kfree(frozen_buffer); + + JBUFFER_TRACE(jh, "exit"); + return error; +} + +int journal_get_write_access (handle_t *handle, struct buffer_head *bh) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + struct journal_head *jh = journal_add_journal_head(bh); + int rc; + + /* We do not want to get caught playing with fields which the + * log thread also manipulates. Make sure that the buffer + * completes any outstanding IO before proceeding. */ + lock_journal(journal); + rc = do_get_write_access(handle, jh, 0); + journal_unlock_journal_head(jh); + unlock_journal(journal); + return rc; +} + + +/* + * When the user wants to journal a newly created buffer_head + * (ie. getblk() returned a new buffer and we are going to populate it + * manually rather than reading off disk), then we need to keep the + * buffer_head locked until it has been completely filled with new + * data. In this case, we should be able to make the assertion that + * the bh is not already part of an existing transaction. + * + * The buffer should already be locked by the caller by this point. + * There is no lock ranking violation: it was a newly created, + * unlocked buffer beforehand. */ + +int journal_get_create_access (handle_t *handle, struct buffer_head *bh) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + struct journal_head *jh = journal_add_journal_head(bh); + int err; + + jbd_debug(5, "journal_head %p\n", jh); + lock_journal(journal); + err = -EROFS; + if (is_handle_aborted(handle)) + goto out; + err = 0; + + JBUFFER_TRACE(jh, "entry"); + /* The buffer may already belong to this transaction due to + * pre-zeroing in the filesystem's new_block code. It may also + * be on the previous, committing transaction's lists, but it + * HAS to be in Forget state in that case: the transaction must + * have deleted the buffer for it to be reused here. */ + J_ASSERT_JH(jh, (jh->b_transaction == transaction || + jh->b_transaction == NULL || + (jh->b_transaction == journal->j_committing_transaction && + jh->b_jlist == BJ_Forget))); + + J_ASSERT_JH(jh, jh->b_next_transaction == NULL); + J_ASSERT_JH(jh, buffer_locked(jh2bh(jh))); + + J_ASSERT_JH(jh, handle->h_buffer_credits > 0); + handle->h_buffer_credits--; + + spin_lock(&journal_datalist_lock); + if (jh->b_transaction == NULL) { + jh->b_transaction = transaction; + JBUFFER_TRACE(jh, "file as BJ_Reserved"); + __journal_file_buffer(jh, transaction, BJ_Reserved); + JBUFFER_TRACE(jh, "refile"); + refile_buffer(jh2bh(jh)); + } else if (jh->b_transaction == journal->j_committing_transaction) { + JBUFFER_TRACE(jh, "set next transaction"); + jh->b_next_transaction = transaction; + } + spin_unlock(&journal_datalist_lock); + + /* + * akpm: I added this. ext3_alloc_branch can pick up new indirect + * blocks which contain freed but then revoked metadata. We need + * to cancel the revoke in case we end up freeing it yet again + * and the reallocating as data - this would cause a second revoke, + * which hits an assertion error. + */ + JBUFFER_TRACE(jh, "cancelling revoke"); + journal_cancel_revoke(handle, jh); + journal_unlock_journal_head(jh); +out: + unlock_journal(journal); + return err; +} + + + +/* + * journal_get_undo_access: Notify intent to modify metadata with non- + * rewindable consequences + * + * Sometimes there is a need to distinguish between metadata which has + * been committed to disk and that which has not. The ext3fs code uses + * this for freeing and allocating space: we have to make sure that we + * do not reuse freed space until the deallocation has been committed, + * since if we overwrote that space we would make the delete + * un-rewindable in case of a crash. + * + * To deal with that, journal_get_undo_access requests write access to a + * buffer for parts of non-rewindable operations such as delete + * operations on the bitmaps. The journaling code must keep a copy of + * the buffer's contents prior to the undo_access call until such time + * as we know that the buffer has definitely been committed to disk. + * + * We never need to know which transaction the committed data is part + * of: buffers touched here are guaranteed to be dirtied later and so + * will be committed to a new transaction in due course, at which point + * we can discard the old committed data pointer. + * + * Returns error number or 0 on success. + */ + +int journal_get_undo_access (handle_t *handle, struct buffer_head *bh) +{ + journal_t *journal = handle->h_transaction->t_journal; + int err; + struct journal_head *jh = journal_add_journal_head(bh); + + JBUFFER_TRACE(jh, "entry"); + lock_journal(journal); + + /* Do this first --- it can drop the journal lock, so we want to + * make sure that obtaining the committed_data is done + * atomically wrt. completion of any outstanding commits. */ + err = do_get_write_access (handle, jh, 1); + if (err) + goto out; + + if (!jh->b_committed_data) { + /* Copy out the current buffer contents into the + * preserved, committed copy. */ + JBUFFER_TRACE(jh, "generate b_committed data"); + jh->b_committed_data = jbd_kmalloc(jh2bh(jh)->b_size, + GFP_NOFS); + if (!jh->b_committed_data) { + printk(KERN_EMERG __FUNCTION__ + ": No memory for committed data!\n"); + err = -ENOMEM; + goto out; + } + + memcpy (jh->b_committed_data, jh2bh(jh)->b_data, + jh2bh(jh)->b_size); + } + +out: + if (!err) + J_ASSERT_JH(jh, jh->b_committed_data); + journal_unlock_journal_head(jh); + unlock_journal(journal); + return err; +} + +/* + * journal_dirty_data: mark a buffer as containing dirty data which + * needs to be flushed before we can commit the current transaction. + * + * The buffer is placed on the transaction's data list and is marked as + * belonging to the transaction. + * + * If `async' is set then the writebask will be initiated by the caller + * using submit_bh -> end_buffer_io_async. We put the buffer onto + * t_async_datalist. + * + * Returns error number or 0 on success. + * + * journal_dirty_data() can be called via page_launder->ext3_writepage + * by kswapd. So it cannot block. Happily, there's nothing here + * which needs lock_journal if `async' is set. + * + * When the buffer is on the current transaction we freely move it + * between BJ_AsyncData and BJ_SyncData according to who tried to + * change its state last. + */ + +int journal_dirty_data (handle_t *handle, struct buffer_head *bh, int async) +{ + journal_t *journal = handle->h_transaction->t_journal; + int need_brelse = 0; + int wanted_jlist = async ? BJ_AsyncData : BJ_SyncData; + struct journal_head *jh; + + if (is_handle_aborted(handle)) + return 0; + + jh = journal_add_journal_head(bh); + JBUFFER_TRACE(jh, "entry"); + + /* + * The buffer could *already* be dirty. Writeout can start + * at any time. + */ + jbd_debug(4, "jh: %p, tid:%d\n", jh, handle->h_transaction->t_tid); + + /* + * What if the buffer is already part of a running transaction? + * + * There are two cases: + * 1) It is part of the current running transaction. Refile it, + * just in case we have allocated it as metadata, deallocated + * it, then reallocated it as data. + * 2) It is part of the previous, still-committing transaction. + * If all we want to do is to guarantee that the buffer will be + * written to disk before this new transaction commits, then + * being sure that the *previous* transaction has this same + * property is sufficient for us! Just leave it on its old + * transaction. + * + * In case (2), the buffer must not already exist as metadata + * --- that would violate write ordering (a transaction is free + * to write its data at any point, even before the previous + * committing transaction has committed). The caller must + * never, ever allow this to happen: there's nothing we can do + * about it in this layer. + */ + spin_lock(&journal_datalist_lock); + if (jh->b_transaction) { + JBUFFER_TRACE(jh, "has transaction"); + if (jh->b_transaction != handle->h_transaction) { + JBUFFER_TRACE(jh, "belongs to older transaction"); + J_ASSERT_JH(jh, jh->b_transaction == + journal->j_committing_transaction); + + /* @@@ IS THIS TRUE ? */ + /* + * Not any more. Scenario: someone does a write() + * in data=journal mode. The buffer's transaction has + * moved into commit. Then someone does another + * write() to the file. We do the frozen data copyout + * and set b_next_transaction to point to j_running_t. + * And while we're in that state, someone does a + * writepage() in an attempt to pageout the same area + * of the file via a shared mapping. At present that + * calls journal_dirty_data(), and we get right here. + * It may be too late to journal the data. Simply + * falling through to the next test will suffice: the + * data will be dirty and wil be checkpointed. The + * ordering comments in the next comment block still + * apply. + */ + //J_ASSERT_JH(jh, jh->b_next_transaction == NULL); + + /* + * If we're journalling data, and this buffer was + * subject to a write(), it could be metadata, forget + * or shadow against the committing transaction. Now, + * someone has dirtied the same darn page via a mapping + * and it is being writepage()'d. + * We *could* just steal the page from commit, with some + * fancy locking there. Instead, we just skip it - + * don't tie the page's buffers to the new transaction + * at all. + * Implication: if we crash before the writepage() data + * is written into the filesystem, recovery will replay + * the write() data. + */ + if (jh->b_jlist != BJ_None && + jh->b_jlist != BJ_SyncData && + jh->b_jlist != BJ_AsyncData) { + JBUFFER_TRACE(jh, "Not stealing"); + goto no_journal; + } + + /* + * This buffer may be undergoing writeout in commit. We + * can't return from here and let the caller dirty it + * again because that can cause the write-out loop in + * commit to never terminate. + */ + if (!async && buffer_dirty(bh)) { + atomic_inc(&bh->b_count); + spin_unlock(&journal_datalist_lock); + need_brelse = 1; + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + spin_lock(&journal_datalist_lock); + /* The buffer may become locked again at any + time if it is redirtied */ + } + + /* journal_clean_data_list() may have got there first */ + if (jh->b_transaction != NULL) { + JBUFFER_TRACE(jh, "unfile from commit"); + __journal_unfile_buffer(jh); + jh->b_transaction = NULL; + } + /* The buffer will be refiled below */ + + } + /* + * Special case --- the buffer might actually have been + * allocated and then immediately deallocated in the previous, + * committing transaction, so might still be left on that + * transaction's metadata lists. + */ + if (jh->b_jlist != wanted_jlist) { + JBUFFER_TRACE(jh, "not on correct data list: unfile"); + J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow); + __journal_unfile_buffer(jh); + jh->b_transaction = NULL; + JBUFFER_TRACE(jh, "file as data"); + __journal_file_buffer(jh, handle->h_transaction, + wanted_jlist); + } + } else { + JBUFFER_TRACE(jh, "not on a transaction"); + __journal_file_buffer(jh, handle->h_transaction, wanted_jlist); + } + /* + * We need to mark the buffer dirty and refile it inside the lock to + * protect it from release by journal_try_to_free_buffer() + * + * We set ->b_flushtime to something small enough to typically keep + * kupdate away from the buffer. + * + * We don't need to do a balance_dirty() - __block_commit_write() + * does that. + */ + if (!async && !atomic_set_buffer_dirty(jh2bh(jh))) { + jh2bh(jh)->b_flushtime = + jiffies + journal->j_commit_interval + 1 * HZ; + refile_buffer(jh2bh(jh)); + } +no_journal: + spin_unlock(&journal_datalist_lock); + if (need_brelse) { + BUFFER_TRACE(bh, "brelse"); + __brelse(bh); + } + JBUFFER_TRACE(jh, "exit"); + journal_unlock_journal_head(jh); + return 0; +} + +/* + * journal_dirty_metadata: mark a buffer as containing dirty metadata + * which needs to be journaled as part of the current transaction. + * + * The buffer is placed on the transaction's metadata list and is marked + * as belonging to the transaction. + * + * Special care needs to be taken if the buffer already belongs to the + * current committing transaction (in which case we should have frozen + * data present for that commit). In that case, we don't relink the + * buffer: that only gets done when the old transaction finally + * completes its commit. + * + * Returns error number or 0 on success. + */ + +int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + struct journal_head *jh = bh2jh(bh); + + jbd_debug(5, "journal_head %p\n", jh); + JBUFFER_TRACE(jh, "entry"); + lock_journal(journal); + if (is_handle_aborted(handle)) + goto out_unlock; + + spin_lock(&journal_datalist_lock); + set_bit(BH_JBDDirty, &bh->b_state); + set_buffer_flushtime(bh); + + J_ASSERT_JH(jh, jh->b_transaction != NULL); + + /* + * Metadata already on the current transaction list doesn't + * need to be filed. Metadata on another transaction's list must + * be committing, and will be refiled once the commit completes: + * leave it alone for now. + */ + + if (jh->b_transaction != transaction) { + JBUFFER_TRACE(jh, "already on other transaction"); + J_ASSERT_JH(jh, jh->b_transaction == + journal->j_committing_transaction); + J_ASSERT_JH(jh, jh->b_next_transaction == transaction); + /* And this case is illegal: we can't reuse another + * transaction's data buffer, ever. */ + /* FIXME: writepage() should be journalled */ + J_ASSERT_JH(jh, jh->b_jlist != BJ_SyncData); + goto done_locked; + } + + /* That test should have eliminated the following case: */ + J_ASSERT_JH(jh, jh->b_frozen_data == 0); + + JBUFFER_TRACE(jh, "file as BJ_Metadata"); + __journal_file_buffer(jh, handle->h_transaction, BJ_Metadata); + +done_locked: + spin_unlock(&journal_datalist_lock); + JBUFFER_TRACE(jh, "exit"); +out_unlock: + unlock_journal(journal); + return 0; +} + +#if 0 +/* + * journal_release_buffer: undo a get_write_access without any buffer + * updates, if the update decided in the end that it didn't need access. + * + * journal_get_write_access() can block, so it is quite possible for a + * journaling component to decide after the write access is returned + * that global state has changed and the update is no longer required. */ + +void journal_release_buffer (handle_t *handle, struct buffer_head *bh) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + struct journal_head *jh = bh2jh(bh); + + lock_journal(journal); + JBUFFER_TRACE(jh, "entry"); + + /* If the buffer is reserved but not modified by this + * transaction, then it is safe to release it. In all other + * cases, just leave the buffer as it is. */ + + spin_lock(&journal_datalist_lock); + if (jh->b_jlist == BJ_Reserved && jh->b_transaction == transaction && + !buffer_jdirty(jh2bh(jh))) { + JBUFFER_TRACE(jh, "unused: refiling it"); + handle->h_buffer_credits++; + __journal_refile_buffer(jh); + } + spin_unlock(&journal_datalist_lock); + + JBUFFER_TRACE(jh, "exit"); + unlock_journal(journal); +} +#endif + +/* + * journal_forget: bforget() for potentially-journaled buffers. We can + * only do the bforget if there are no commits pending against the + * buffer. If the buffer is dirty in the current running transaction we + * can safely unlink it. + * + * bh may not be a journalled buffer at all - it may be a non-JBD + * buffer which came off the hashtable. Check for this. + * + * Decrements bh->b_count by one. + * + * Allow this call even if the handle has aborted --- it may be part of + * the caller's cleanup after an abort. + */ + +void journal_forget (handle_t *handle, struct buffer_head *bh) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + struct journal_head *jh; + + BUFFER_TRACE(bh, "entry"); + + lock_journal(journal); + spin_lock(&journal_datalist_lock); + + if (!buffer_jbd(bh)) + goto not_jbd; + jh = bh2jh(bh); + + if (jh->b_transaction == handle->h_transaction) { + J_ASSERT_JH(jh, !jh->b_frozen_data); + + /* If we are forgetting a buffer which is already part + * of this transaction, then we can just drop it from + * the transaction immediately. */ + clear_bit(BH_Dirty, &bh->b_state); + clear_bit(BH_JBDDirty, &bh->b_state); + + JBUFFER_TRACE(jh, "belongs to current transaction: unfile"); + J_ASSERT_JH(jh, !jh->b_committed_data); + + __journal_unfile_buffer(jh); + jh->b_transaction = 0; + + /* + * We are no longer going to journal this buffer. + * However, the commit of this transaction is still + * important to the buffer: the delete that we are now + * processing might obsolete an old log entry, so by + * committing, we can satisfy the buffer's checkpoint. + * + * So, if we have a checkpoint on the buffer, we should + * now refile the buffer on our BJ_Forget list so that + * we know to remove the checkpoint after we commit. + */ + + if (jh->b_cp_transaction) { + __journal_file_buffer(jh, transaction, BJ_Forget); + } else { + __journal_remove_journal_head(bh); + __brelse(bh); + if (!buffer_jbd(bh)) { + spin_unlock(&journal_datalist_lock); + unlock_journal(journal); + __bforget(bh); + return; + } + } + + } else if (jh->b_transaction) { + J_ASSERT_JH(jh, (jh->b_transaction == + journal->j_committing_transaction)); + /* However, if the buffer is still owned by a prior + * (committing) transaction, we can't drop it yet... */ + JBUFFER_TRACE(jh, "belongs to older transaction"); + /* ... but we CAN drop it from the new transaction if we + * have also modified it since the original commit. */ + + if (jh->b_next_transaction) { + J_ASSERT(jh->b_next_transaction == transaction); + jh->b_next_transaction = NULL; + } + } + +not_jbd: + spin_unlock(&journal_datalist_lock); + unlock_journal(journal); + __brelse(bh); + return; +} + +#if 0 /* Unused */ +/* + * journal_sync_buffer: flush a potentially-journaled buffer to disk. + * + * Used for O_SYNC filesystem operations. If the buffer is journaled, + * we need to complete the O_SYNC by waiting for the transaction to + * complete. It is an error to call journal_sync_buffer before + * journal_stop! + */ + +void journal_sync_buffer(struct buffer_head *bh) +{ + transaction_t *transaction; + journal_t *journal; + long sequence; + struct journal_head *jh; + + /* If the buffer isn't journaled, this is easy: just sync it to + * disk. */ + BUFFER_TRACE(bh, "entry"); + + spin_lock(&journal_datalist_lock); + if (!buffer_jbd(bh)) { + spin_unlock(&journal_datalist_lock); + return; + } + jh = bh2jh(bh); + if (jh->b_transaction == NULL) { + /* If the buffer has already been journaled, then this + * is a noop. */ + if (jh->b_cp_transaction == NULL) { + spin_unlock(&journal_datalist_lock); + return; + } + atomic_inc(&bh->b_count); + spin_unlock(&journal_datalist_lock); + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer(bh); + __brelse(bh); + goto out; + } + + /* Otherwise, just wait until the transaction is synced to disk. */ + transaction = jh->b_transaction; + journal = transaction->t_journal; + sequence = transaction->t_tid; + spin_unlock(&journal_datalist_lock); + + jbd_debug(2, "requesting commit for jh %p\n", jh); + log_start_commit (journal, transaction); + + while (tid_gt(sequence, journal->j_commit_sequence)) { + wake_up(&journal->j_wait_done_commit); + sleep_on(&journal->j_wait_done_commit); + } + JBUFFER_TRACE(jh, "exit"); +out: + return; +} +#endif + +/* + * All done for a particular handle. + * + * There is not much action needed here. We just return any remaining + * buffer credits to the transaction and remove the handle. The only + * complication is that we need to start a commit operation if the + * filesystem is marked for synchronous update. + * + * journal_stop itself will not usually return an error, but it may + * do so in unusual circumstances. In particular, expect it to + * return -EIO if a journal_abort has been executed since the + * transaction began. + */ + +int journal_stop(handle_t *handle) +{ + transaction_t *transaction = handle->h_transaction; + journal_t *journal = transaction->t_journal; + int old_handle_count, err; + + if (!handle) + return 0; + + J_ASSERT (transaction->t_updates > 0); + J_ASSERT (journal_current_handle() == handle); + + if (is_handle_aborted(handle)) + err = -EIO; + else + err = 0; + + if (--handle->h_ref > 0) { + jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, + handle->h_ref); + return err; + } + + jbd_debug(4, "Handle %p going down\n", handle); + + /* + * Implement synchronous transaction batching. If the handle + * was synchronous, don't force a commit immediately. Let's + * yield and let another thread piggyback onto this transaction. + * Keep doing that while new threads continue to arrive. + * It doesn't cost much - we're about to run a commit and sleep + * on IO anyway. Speeds up many-threaded, many-dir operations + * by 30x or more... + */ + if (handle->h_sync) { + do { + old_handle_count = transaction->t_handle_count; + set_current_state(TASK_RUNNING); + current->policy |= SCHED_YIELD; + schedule(); + } while (old_handle_count != transaction->t_handle_count); + } + + current->journal_info = NULL; + transaction->t_outstanding_credits -= handle->h_buffer_credits; + transaction->t_updates--; + if (!transaction->t_updates) { + wake_up(&journal->j_wait_updates); + if (journal->j_barrier_count) + wake_up(&journal->j_wait_transaction_locked); + } + + /* + * If the handle is marked SYNC, we need to set another commit + * going! We also want to force a commit if the current + * transaction is occupying too much of the log, or if the + * transaction is too old now. + */ + if (handle->h_sync || + transaction->t_outstanding_credits > + journal->j_max_transaction_buffers || + time_after_eq(jiffies, transaction->t_expires)) { + /* Do this even for aborted journals: an abort still + * completes the commit thread, it just doesn't write + * anything to disk. */ + tid_t tid = transaction->t_tid; + + jbd_debug(2, "transaction too old, requesting commit for " + "handle %p\n", handle); + /* This is non-blocking */ + log_start_commit(journal, transaction); + + /* + * Special case: JFS_SYNC synchronous updates require us + * to wait for the commit to complete. + */ + if (handle->h_sync && !(current->flags & PF_MEMALLOC)) + log_wait_commit(journal, tid); + } + kfree(handle); + return err; +} + +/* + * For synchronous operations: force any uncommitted trasnactions + * to disk. May seem kludgy, but it reuses all the handle batching + * code in a very simple manner. + */ +int journal_force_commit(journal_t *journal) +{ + handle_t *handle; + int ret = 0; + + lock_kernel(); + handle = journal_start(journal, 1); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } + handle->h_sync = 1; + journal_stop(handle); +out: + unlock_kernel(); + return ret; +} + +/* + * + * List management code snippets: various functions for manipulating the + * transaction buffer lists. + * + */ + +/* + * Append a buffer to a transaction list, given the transaction's list head + * pointer. + * journal_datalist_lock is held. + */ + +static inline void +__blist_add_buffer(struct journal_head **list, struct journal_head *jh) +{ + if (!*list) { + jh->b_tnext = jh->b_tprev = jh; + *list = jh; + } else { + /* Insert at the tail of the list to preserve order */ + struct journal_head *first = *list, *last = first->b_tprev; + jh->b_tprev = last; + jh->b_tnext = first; + last->b_tnext = first->b_tprev = jh; + } +} + +/* + * Remove a buffer from a transaction list, given the transaction's list + * head pointer. + * + * Called with journal_datalist_lock held, and the journal may not + * be locked. + */ + +static inline void +__blist_del_buffer(struct journal_head **list, struct journal_head *jh) +{ + if (*list == jh) { + *list = jh->b_tnext; + if (*list == jh) + *list = 0; + } + jh->b_tprev->b_tnext = jh->b_tnext; + jh->b_tnext->b_tprev = jh->b_tprev; +} + +/* + * Remove a buffer from the appropriate transaction list. + * + * Note that this function can *change* the value of + * bh->b_transaction->t_sync_datalist, t_async_datalist, t_buffers, t_forget, + * t_iobuf_list, t_shadow_list, t_log_list or t_reserved_list. If the caller + * is holding onto a copy of one of thee pointers, it could go bad. + * Generally the caller needs to re-read the pointer from the transaction_t. + * + * If bh->b_jlist is BJ_SyncData or BJ_AsyncData then we may have been called + * via journal_try_to_free_buffer() or journal_clean_data_list(). In that + * case, journal_datalist_lock will be held, and the journal may not be locked. + */ +void __journal_unfile_buffer(struct journal_head *jh) +{ + struct journal_head **list = 0; + transaction_t * transaction; + + assert_spin_locked(&journal_datalist_lock); + transaction = jh->b_transaction; + +#ifdef __SMP__ + J_ASSERT (current->lock_depth >= 0); +#endif + J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); + + if (jh->b_jlist != BJ_None) + J_ASSERT_JH(jh, transaction != 0); + + switch (jh->b_jlist) { + case BJ_None: + return; + case BJ_SyncData: + list = &transaction->t_sync_datalist; + break; + case BJ_AsyncData: + list = &transaction->t_async_datalist; + break; + case BJ_Metadata: + transaction->t_nr_buffers--; + J_ASSERT_JH(jh, transaction->t_nr_buffers >= 0); + list = &transaction->t_buffers; + break; + case BJ_Forget: + list = &transaction->t_forget; + break; + case BJ_IO: + list = &transaction->t_iobuf_list; + break; + case BJ_Shadow: + list = &transaction->t_shadow_list; + break; + case BJ_LogCtl: + list = &transaction->t_log_list; + break; + case BJ_Reserved: + list = &transaction->t_reserved_list; + break; + } + + __blist_del_buffer(list, jh); + jh->b_jlist = BJ_None; + if (test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state)) { + set_bit(BH_Dirty, &jh2bh(jh)->b_state); + } +} + +void journal_unfile_buffer(struct journal_head *jh) +{ + spin_lock(&journal_datalist_lock); + __journal_unfile_buffer(jh); + spin_unlock(&journal_datalist_lock); +} + +/* + * Called from journal_try_to_free_buffers(). The journal is not + * locked. lru_list_lock is not held. + * + * Here we see why journal_datalist_lock is global and not per-journal. + * We cannot get back to this buffer's journal pointer without locking + * out journal_clean_data_list() in some manner. + * + * One could use journal_datalist_lock to get unracy access to a + * per-journal lock. + * + * Called with journal_datalist_lock held. + * + * Returns non-zero iff we were able to free the journal_head. + */ +static int __journal_try_to_free_buffer(struct buffer_head *bh, + int *locked_or_dirty) +{ + struct journal_head *jh; + + assert_spin_locked(&journal_datalist_lock); + + if (!buffer_jbd(bh)) + return 1; + jh = bh2jh(bh); + + if (buffer_locked(bh) || buffer_dirty(bh)) { + *locked_or_dirty = 1; + goto out; + } + + if (!buffer_uptodate(bh)) + goto out; + + if (jh->b_next_transaction != 0) + goto out; + + if (jh->b_transaction != 0 && jh->b_cp_transaction == 0) { + if (jh->b_jlist == BJ_SyncData || jh->b_jlist==BJ_AsyncData) { + /* A written-back ordered data buffer */ + JBUFFER_TRACE(jh, "release data"); + __journal_unfile_buffer(jh); + jh->b_transaction = 0; + __journal_remove_journal_head(bh); + __brelse(bh); + } + } + else if (jh->b_cp_transaction != 0 && jh->b_transaction == 0) { + /* written-back checkpointed metadata buffer */ + if (jh->b_jlist == BJ_None) { + JBUFFER_TRACE(jh, "remove from checkpoint list"); + __journal_remove_checkpoint(jh); + __journal_remove_journal_head(bh); + __brelse(bh); + } + } + return !buffer_jbd(bh); + +out: + return 0; +} + +/* + * journal_try_to_free_buffers(). For all the buffers on this page, + * if they are fully written out ordered data, move them onto BUF_CLEAN + * so try_to_free_buffers() can reap them. Called with lru_list_lock + * not held. Does its own locking. + * + * This complicates JBD locking somewhat. We aren't protected by the + * BKL here. We wish to remove the buffer from its committing or + * running transaction's ->t_datalist via __journal_unfile_buffer. + * + * This may *change* the value of transaction_t->t_datalist, so anyone + * who looks at t_datalist needs to lock against this function. + * + * Even worse, someone may be doing a journal_dirty_data on this + * buffer. So we need to lock against that. journal_dirty_data() + * will come out of the lock with the buffer dirty, which makes it + * ineligible for release here. + * + * Who else is affected by this? hmm... Really the only contender + * is do_get_write_access() - it could be looking at the buffer while + * journal_try_to_free_buffer() is changing its state. But that + * cannot happen because we never reallocate freed data as metadata + * while the data is part of a transaction. Yes? + * + * This function returns non-zero if we wish try_to_free_buffers() + * to be called. We do this is the page is releasable by try_to_free_buffers(). + * We also do it if the page has locked or dirty buffers and the caller wants + * us to perform sync or async writeout. + */ +int journal_try_to_free_buffers(journal_t *journal, + struct page *page, int gfp_mask) +{ + struct buffer_head *bh; + struct buffer_head *tmp; + int locked_or_dirty = 0; + int call_ttfb = 1; + + J_ASSERT(PageLocked(page)); + + bh = page->buffers; + tmp = bh; + spin_lock(&journal_datalist_lock); + do { + struct buffer_head *p = tmp; + + tmp = tmp->b_this_page; + if (buffer_jbd(p)) + if (!__journal_try_to_free_buffer(p, &locked_or_dirty)) + call_ttfb = 0; + } while (tmp != bh); + spin_unlock(&journal_datalist_lock); + + if (!(gfp_mask & (__GFP_IO|__GFP_WAIT))) + goto out; + if (!locked_or_dirty) + goto out; + /* + * The VM wants us to do writeout, or to block on IO, or both. + * So we allow try_to_free_buffers to be called even if the page + * still has journalled buffers. + */ + call_ttfb = 1; +out: + return call_ttfb; +} + +/* + * This buffer is no longer needed. If it is on an older transaction's + * checkpoint list we need to record it on this transaction's forget list + * to pin this buffer (and hence its checkpointing transaction) down until + * this transaction commits. If the buffer isn't on a checkpoint list, we + * release it. + * Returns non-zero if JBD no longer has an interest in the buffer. + */ +static int dispose_buffer(struct journal_head *jh, + transaction_t *transaction) +{ + int may_free = 1; + struct buffer_head *bh = jh2bh(jh); + + spin_lock(&journal_datalist_lock); + __journal_unfile_buffer(jh); + jh->b_transaction = 0; + + if (jh->b_cp_transaction) { + JBUFFER_TRACE(jh, "on running+cp transaction"); + __journal_file_buffer(jh, transaction, BJ_Forget); + clear_bit(BH_JBDDirty, &bh->b_state); + may_free = 0; + } else { + JBUFFER_TRACE(jh, "on running transaction"); + __journal_remove_journal_head(bh); + __brelse(bh); + } + spin_unlock(&journal_datalist_lock); + return may_free; +} + +/* + * journal_flushpage + * + * This code is tricky. It has a number of cases to deal with. + * + * There are two invariants which this code relies on: + * + * i_size must be updated on disk before we start calling flushpage on the + * data. + * + * This is done in ext3 by defining an ext3_setattr method which + * updates i_size before truncate gets going. By maintaining this + * invariant, we can be sure that it is safe to throw away any buffers + * attached to the current transaction: once the transaction commits, + * we know that the data will not be needed. + * + * Note however that we can *not* throw away data belonging to the + * previous, committing transaction! + * + * Any disk blocks which *are* part of the previous, committing + * transaction (and which therefore cannot be discarded immediately) are + * not going to be reused in the new running transaction + * + * The bitmap committed_data images guarantee this: any block which is + * allocated in one transaction and removed in the next will be marked + * as in-use in the committed_data bitmap, so cannot be reused until + * the next transaction to delete the block commits. This means that + * leaving committing buffers dirty is quite safe: the disk blocks + * cannot be reallocated to a different file and so buffer aliasing is + * not possible. + * + * + * The above applies mainly to ordered data mode. In writeback mode we + * don't make guarantees about the order in which data hits disk --- in + * particular we don't guarantee that new dirty data is flushed before + * transaction commit --- so it is always safe just to discard data + * immediately in that mode. --sct + */ + +/* + * The journal_unmap_buffer helper function returns zero if the buffer + * concerned remains pinned as an anonymous buffer belonging to an older + * transaction. + * + * We're outside-transaction here. Either or both of j_running_transaction + * and j_committing_transaction may be NULL. + */ +static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) +{ + transaction_t *transaction; + struct journal_head *jh; + int may_free = 1; + + BUFFER_TRACE(bh, "entry"); + + if (!buffer_mapped(bh)) + return 1; + + /* It is safe to proceed here without the + * journal_datalist_spinlock because the buffers cannot be + * stolen by try_to_free_buffers as long as we are holding the + * page lock. --sct */ + + if (!buffer_jbd(bh)) + goto zap_buffer; + + jh = bh2jh(bh); + transaction = jh->b_transaction; + if (transaction == NULL) { + /* First case: not on any transaction. If it + * has no checkpoint link, then we can zap it: + * it's a writeback-mode buffer so we don't care + * if it hits disk safely. */ + if (!jh->b_cp_transaction) { + JBUFFER_TRACE(jh, "not on any transaction: zap"); + goto zap_buffer; + } + + if (!buffer_dirty(bh)) { + /* bdflush has written it. We can drop it now */ + goto zap_buffer; + } + + /* OK, it must be in the journal but still not + * written fully to disk: it's metadata or + * journaled data... */ + + if (journal->j_running_transaction) { + /* ... and once the current transaction has + * committed, the buffer won't be needed any + * longer. */ + JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); + return dispose_buffer(jh, + journal->j_running_transaction); + } else { + /* There is no currently-running transaction. So the + * orphan record which we wrote for this file must have + * passed into commit. We must attach this buffer to + * the committing transaction, if it exists. */ + if (journal->j_committing_transaction) { + JBUFFER_TRACE(jh, "give to committing trans"); + return dispose_buffer(jh, + journal->j_committing_transaction); + } else { + /* The orphan record's transaction has + * committed. We can cleanse this buffer */ + clear_bit(BH_JBDDirty, &bh->b_state); + goto zap_buffer; + } + } + } else if (transaction == journal->j_committing_transaction) { + /* If it is committing, we simply cannot touch it. We + * can remove it's next_transaction pointer from the + * running transaction if that is set, but nothing + * else. */ + JBUFFER_TRACE(jh, "on committing transaction"); + if (jh->b_next_transaction) { + J_ASSERT(jh->b_next_transaction == + journal->j_running_transaction); + jh->b_next_transaction = NULL; + } + return 0; + } else { + /* Good, the buffer belongs to the running transaction. + * We are writing our own transaction's data, not any + * previous one's, so it is safe to throw it away + * (remember that we expect the filesystem to have set + * i_size already for this truncate so recovery will not + * expose the disk blocks we are discarding here.) */ + J_ASSERT_JH(jh, transaction == journal->j_running_transaction); + may_free = dispose_buffer(jh, transaction); + } + +zap_buffer: + if (buffer_dirty(bh)) + mark_buffer_clean(bh); + J_ASSERT_BH(bh, !buffer_jdirty(bh)); + clear_bit(BH_Uptodate, &bh->b_state); + clear_bit(BH_Mapped, &bh->b_state); + clear_bit(BH_Req, &bh->b_state); + clear_bit(BH_New, &bh->b_state); + return may_free; +} + +/* + * Return non-zero if the page's buffers were successfully reaped + */ +int journal_flushpage(journal_t *journal, + struct page *page, + unsigned long offset) +{ + struct buffer_head *head, *bh, *next; + unsigned int curr_off = 0; + int may_free = 1; + + if (!PageLocked(page)) + BUG(); + if (!page->buffers) + return 1; + + /* We will potentially be playing with lists other than just the + * data lists (especially for journaled data mode), so be + * cautious in our locking. */ + lock_journal(journal); + + head = bh = page->buffers; + do { + unsigned int next_off = curr_off + bh->b_size; + next = bh->b_this_page; + + /* AKPM: doing lock_buffer here may be overly paranoid */ + if (offset <= curr_off) { + /* This block is wholly outside the truncation point */ + lock_buffer(bh); + may_free &= journal_unmap_buffer(journal, bh); + unlock_buffer(bh); + } + curr_off = next_off; + bh = next; + + } while (bh != head); + + unlock_journal(journal); + + if (!offset) { + if (!may_free || !try_to_free_buffers(page, 0)) + return 0; + J_ASSERT(page->buffers == NULL); + } + return 1; +} + +/* + * File a buffer on the given transaction list. + */ +void __journal_file_buffer(struct journal_head *jh, + transaction_t *transaction, int jlist) +{ + struct journal_head **list = 0; + + assert_spin_locked(&journal_datalist_lock); + +#ifdef __SMP__ + J_ASSERT (current->lock_depth >= 0); +#endif + J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); + J_ASSERT_JH(jh, jh->b_transaction == transaction || + jh->b_transaction == 0); + + if (jh->b_transaction) { + if (jh->b_jlist == jlist) + return; + __journal_unfile_buffer(jh); + } else { + jh->b_transaction = transaction; + } + + switch (jlist) { + case BJ_None: + J_ASSERT_JH(jh, !jh->b_committed_data); + J_ASSERT_JH(jh, !jh->b_frozen_data); + return; + case BJ_SyncData: + list = &transaction->t_sync_datalist; + break; + case BJ_AsyncData: + list = &transaction->t_async_datalist; + break; + case BJ_Metadata: + transaction->t_nr_buffers++; + list = &transaction->t_buffers; + break; + case BJ_Forget: + list = &transaction->t_forget; + break; + case BJ_IO: + list = &transaction->t_iobuf_list; + break; + case BJ_Shadow: + list = &transaction->t_shadow_list; + break; + case BJ_LogCtl: + list = &transaction->t_log_list; + break; + case BJ_Reserved: + list = &transaction->t_reserved_list; + break; + } + + __blist_add_buffer(list, jh); + jh->b_jlist = jlist; + + if (jlist == BJ_Metadata || jlist == BJ_Reserved || + jlist == BJ_Shadow || jlist == BJ_Forget) { + if (atomic_set_buffer_clean(jh2bh(jh))) { + set_bit(BH_JBDDirty, &jh2bh(jh)->b_state); + } + } +} + +void journal_file_buffer(struct journal_head *jh, + transaction_t *transaction, int jlist) +{ + spin_lock(&journal_datalist_lock); + __journal_file_buffer(jh, transaction, jlist); + spin_unlock(&journal_datalist_lock); +} + +/* + * Remove a buffer from its current buffer list in preparation for + * dropping it from its current transaction entirely. If the buffer has + * already started to be used by a subsequent transaction, refile the + * buffer on that transaction's metadata list. + */ + +void __journal_refile_buffer(struct journal_head *jh) +{ + assert_spin_locked(&journal_datalist_lock); +#ifdef __SMP__ + J_ASSERT_JH(jh, current->lock_depth >= 0); +#endif + __journal_unfile_buffer(jh); + + /* If the buffer is now unused, just drop it. If it has been + modified by a later transaction, add it to the new + transaction's metadata list. */ + + jh->b_transaction = jh->b_next_transaction; + jh->b_next_transaction = NULL; + + if (jh->b_transaction != NULL) { + __journal_file_buffer(jh, jh->b_transaction, BJ_Metadata); + J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); + } else { + /* Onto BUF_DIRTY for writeback */ + refile_buffer(jh2bh(jh)); + } +} + +/* + * For the unlocked version of this call, also make sure that any + * hanging journal_head is cleaned up if necessary. + * + * __journal_refile_buffer is usually called as part of a single locked + * operation on a buffer_head, in which the caller is probably going to + * be hooking the journal_head onto other lists. In that case it is up + * to the caller to remove the journal_head if necessary. For the + * unlocked journal_refile_buffer call, the caller isn't going to be + * doing anything else to the buffer so we need to do the cleanup + * ourselves to avoid a jh leak. + * + * *** The journal_head may be freed by this call! *** + */ +void journal_refile_buffer(struct journal_head *jh) +{ + struct buffer_head *bh; + + spin_lock(&journal_datalist_lock); + bh = jh2bh(jh); + + __journal_refile_buffer(jh); + __journal_remove_journal_head(bh); + + spin_unlock(&journal_datalist_lock); + __brelse(bh); +} diff -u --recursive --new-file v2.4.14/linux/fs/nfs/Makefile linux/fs/nfs/Makefile --- v2.4.14/linux/fs/nfs/Makefile Fri Dec 29 14:07:23 2000 +++ linux/fs/nfs/Makefile Fri Nov 9 14:28:15 2001 @@ -9,8 +9,8 @@ O_TARGET := nfs.o -obj-y := inode.o file.o read.o write.o dir.o symlink.o proc.o \ - nfs2xdr.o flushd.o unlink.o +obj-y := dir.o file.o flushd.o inode.o nfs2xdr.o pagelist.o proc.o \ + read.o symlink.o unlink.o write.o obj-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o obj-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o diff -u --recursive --new-file v2.4.14/linux/fs/nfs/flushd.c linux/fs/nfs/flushd.c --- v2.4.14/linux/fs/nfs/flushd.c Sat May 19 17:47:55 2001 +++ linux/fs/nfs/flushd.c Fri Nov 9 14:28:15 2001 @@ -38,9 +38,9 @@ #include <linux/nfs.h> #include <linux/nfs_fs.h> +#include <linux/nfs_page.h> #include <linux/nfs_fs_sb.h> #include <linux/nfs_flushd.h> -#include <linux/nfs_mount.h> /* * Various constants @@ -111,13 +111,10 @@ dprintk("NFS: reqlist_exit (ptr %p rpc %p)\n", cache, cache->task); - while (cache->task || cache->inodes) { - if (!cache->task) { - nfs_reqlist_init(server); - } else { - cache->task->tk_status = -ENOMEM; - rpc_wake_up_task(cache->task); - } + while (cache->task) { + rpc_exit(cache->task, 0); + rpc_wake_up_task(cache->task); + interruptible_sleep_on_timeout(&cache->request_wait, 1 * HZ); } out: @@ -150,133 +147,47 @@ } } -void nfs_wake_flushd() -{ - rpc_wake_up_status(&flushd_queue, -ENOMEM); -} - -static void inode_append_flushd(struct inode *inode) -{ - struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); - struct inode **q; - - if (NFS_FLAGS(inode) & NFS_INO_FLUSH) - goto out; - inode->u.nfs_i.hash_next = NULL; - - q = &cache->inodes; - while (*q) - q = &(*q)->u.nfs_i.hash_next; - *q = inode; - - /* Note: we increase the inode i_count in order to prevent - * it from disappearing when on the flush list - */ - NFS_FLAGS(inode) |= NFS_INO_FLUSH; - atomic_inc(&inode->i_count); -out:; -} - -/* Protect me using the BKL */ -void inode_remove_flushd(struct inode *inode) -{ - struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); - struct inode **q; - - if (!(NFS_FLAGS(inode) & NFS_INO_FLUSH)) - return; - - q = &cache->inodes; - while (*q && *q != inode) - q = &(*q)->u.nfs_i.hash_next; - if (*q) { - *q = inode->u.nfs_i.hash_next; - NFS_FLAGS(inode) &= ~NFS_INO_FLUSH; - iput(inode); - } -} - -void inode_schedule_scan(struct inode *inode, unsigned long time) -{ - struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); - struct rpc_task *task; - unsigned long mintimeout; - - lock_kernel(); - if (time_after(NFS_NEXTSCAN(inode), time)) - NFS_NEXTSCAN(inode) = time; - mintimeout = jiffies + 1 * HZ; - if (time_before(mintimeout, NFS_NEXTSCAN(inode))) - mintimeout = NFS_NEXTSCAN(inode); - inode_append_flushd(inode); - - task = cache->task; - if (!task) { - nfs_reqlist_init(NFS_SERVER(inode)); - } else { - if (time_after(cache->runat, mintimeout)) - rpc_wake_up_task(task); - } - unlock_kernel(); -} - - +#define NFS_FLUSHD_TIMEOUT (30*HZ) static void nfs_flushd(struct rpc_task *task) { struct nfs_server *server; struct nfs_reqlist *cache; - struct inode *inode, *next; - unsigned long delay = jiffies + NFS_WRITEBACK_LOCKDELAY; - int flush = (task->tk_status == -ENOMEM); + LIST_HEAD(head); dprintk("NFS: %4d flushd starting\n", task->tk_pid); server = (struct nfs_server *) task->tk_calldata; cache = server->rw_requests; - next = cache->inodes; - cache->inodes = NULL; - - while ((inode = next) != NULL) { - next = next->u.nfs_i.hash_next; - inode->u.nfs_i.hash_next = NULL; - NFS_FLAGS(inode) &= ~NFS_INO_FLUSH; - - if (flush) { - nfs_pagein_inode(inode, 0, 0); - nfs_sync_file(inode, NULL, 0, 0, FLUSH_AGING); - } else if (time_after(jiffies, NFS_NEXTSCAN(inode))) { - NFS_NEXTSCAN(inode) = jiffies + NFS_WRITEBACK_LOCKDELAY; - nfs_pagein_timeout(inode); - nfs_flush_timeout(inode, FLUSH_AGING); -#ifdef CONFIG_NFS_V3 - nfs_commit_timeout(inode, FLUSH_AGING); -#endif + for(;;) { + spin_lock(&nfs_wreq_lock); + if (nfs_scan_lru_dirty_timeout(server, &head)) { + spin_unlock(&nfs_wreq_lock); + nfs_flush_list(&head, server->wpages, FLUSH_AGING); + continue; } - - if (nfs_have_writebacks(inode) || nfs_have_read(inode)) { - inode_append_flushd(inode); - if (time_after(delay, NFS_NEXTSCAN(inode))) - delay = NFS_NEXTSCAN(inode); + if (nfs_scan_lru_read_timeout(server, &head)) { + spin_unlock(&nfs_wreq_lock); + nfs_pagein_list(&head, server->rpages); + continue; } - iput(inode); +#ifdef CONFIG_NFS_V3 + if (nfs_scan_lru_commit_timeout(server, &head)) { + spin_unlock(&nfs_wreq_lock); + nfs_commit_list(&head, FLUSH_AGING); + continue; + } +#endif + spin_unlock(&nfs_wreq_lock); + break; } dprintk("NFS: %4d flushd back to sleep\n", task->tk_pid); - if (time_after(jiffies + 1 * HZ, delay)) - delay = 1 * HZ; - else - delay = delay - jiffies; - task->tk_status = 0; - task->tk_action = nfs_flushd; - task->tk_timeout = delay; - cache->runat = jiffies + task->tk_timeout; - - if (!atomic_read(&cache->nr_requests) && !cache->inodes) { - cache->task = NULL; - task->tk_action = NULL; - } else + if (task->tk_action) { + task->tk_timeout = NFS_FLUSHD_TIMEOUT; + cache->runat = jiffies + task->tk_timeout; rpc_sleep_on(&flushd_queue, task, NULL, NULL); + } } static void diff -u --recursive --new-file v2.4.14/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.4.14/linux/fs/nfs/inode.c Tue Oct 9 17:06:53 2001 +++ linux/fs/nfs/inode.c Fri Nov 9 14:28:15 2001 @@ -324,6 +324,10 @@ if (!server->hostname) goto out_unlock; strcpy(server->hostname, data->hostname); + INIT_LIST_HEAD(&server->lru_read); + INIT_LIST_HEAD(&server->lru_dirty); + INIT_LIST_HEAD(&server->lru_commit); + INIT_LIST_HEAD(&server->lru_busy); nfsv3_try_again: /* Check NFS protocol revision and initialize RPC op vector @@ -1072,6 +1076,8 @@ extern void nfs_destroy_nfspagecache(void); extern int nfs_init_readpagecache(void); extern int nfs_destroy_readpagecache(void); +extern int nfs_init_writepagecache(void); +extern int nfs_destroy_writepagecache(void); /* * Initialize NFS @@ -1088,6 +1094,10 @@ if (err) return err; + err = nfs_init_writepagecache(); + if (err) + return err; + #ifdef CONFIG_PROC_FS rpc_proc_register(&nfs_rpcstat); #endif @@ -1096,6 +1106,7 @@ static void __exit exit_nfs_fs(void) { + nfs_destroy_writepagecache(); nfs_destroy_readpagecache(); nfs_destroy_nfspagecache(); #ifdef CONFIG_PROC_FS @@ -1107,6 +1118,7 @@ EXPORT_NO_SYMBOLS; /* Not quite true; I just maintain it */ MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); +MODULE_LICENSE("GPL"); module_init(init_nfs_fs) module_exit(exit_nfs_fs) diff -u --recursive --new-file v2.4.14/linux/fs/nfs/pagelist.c linux/fs/nfs/pagelist.c --- v2.4.14/linux/fs/nfs/pagelist.c Wed Dec 31 16:00:00 1969 +++ linux/fs/nfs/pagelist.c Fri Nov 9 14:28:15 2001 @@ -0,0 +1,498 @@ +/* + * linux/fs/nfs/pagelist.c + * + * A set of helper functions for managing NFS read and write requests. + * The main purpose of these routines is to provide support for the + * coalescing of several requests into a single RPC call. + * + * Copyright 2000, 2001 (c) Trond Myklebust <trond.myklebust@fys.uio.no> + * + */ + +#include <linux/config.h> +#include <linux/slab.h> +#include <linux/file.h> +#include <linux/sunrpc/clnt.h> +#include <linux/nfs3.h> +#include <linux/nfs_page.h> +#include <linux/nfs_fs.h> +#include <linux/nfs_flushd.h> +#include <linux/nfs_mount.h> + +#define NFS_PARANOIA 1 + +/* + * Spinlock + */ +spinlock_t nfs_wreq_lock = SPIN_LOCK_UNLOCKED; + +static kmem_cache_t *nfs_page_cachep; + +static inline struct nfs_page * +nfs_page_alloc(void) +{ + struct nfs_page *p; + p = kmem_cache_alloc(nfs_page_cachep, SLAB_NOFS); + if (p) { + memset(p, 0, sizeof(*p)); + INIT_LIST_HEAD(&p->wb_hash); + INIT_LIST_HEAD(&p->wb_list); + INIT_LIST_HEAD(&p->wb_lru); + init_waitqueue_head(&p->wb_wait); + } + return p; +} + +static inline void +nfs_page_free(struct nfs_page *p) +{ + kmem_cache_free(nfs_page_cachep, p); +} + +static int nfs_try_to_free_pages(struct nfs_server *); + +/** + * nfs_create_request - Create an NFS read/write request. + * @file: file that owns this request + * @inode: inode to which the request is attached + * @page: page to write + * @offset: starting offset within the page for the write + * @count: number of bytes to read/write + * + * The page must be locked by the caller. This makes sure we never + * create two different requests for the same page, and avoids + * a possible deadlock when we reach the hard limit on the number + * of dirty pages. + * User should ensure it is safe to sleep in this function. + */ +struct nfs_page * +nfs_create_request(struct file *file, struct inode *inode, + struct page *page, + unsigned int offset, unsigned int count) +{ + struct nfs_server *server = NFS_SERVER(inode); + struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); + struct nfs_page *req; + + /* Deal with hard limits. */ + for (;;) { + /* Prevent races by incrementing *before* we test */ + atomic_inc(&cache->nr_requests); + + /* If we haven't reached the local hard limit yet, + * try to allocate the request struct */ + if (atomic_read(&cache->nr_requests) <= MAX_REQUEST_HARD) { + req = nfs_page_alloc(); + if (req != NULL) + break; + } + + atomic_dec(&cache->nr_requests); + + /* Try to free up at least one request in order to stay + * below the hard limit + */ + if (nfs_try_to_free_pages(server)) + continue; + if (signalled() && (server->flags & NFS_MOUNT_INTR)) + return ERR_PTR(-ERESTARTSYS); + current->policy = SCHED_YIELD; + schedule(); + } + + /* Initialize the request struct. Initially, we assume a + * long write-back delay. This will be adjusted in + * update_nfs_request below if the region is not locked. */ + req->wb_page = page; + page_cache_get(page); + req->wb_offset = offset; + req->wb_bytes = count; + + /* If we have a struct file, use its cached credentials */ + if (file) { + req->wb_file = file; + get_file(file); + req->wb_cred = nfs_file_cred(file); + } + req->wb_inode = inode; + req->wb_count = 1; + + return req; +} + + +/** + * nfs_release_request - Release the count on an NFS read/write request + * @req: request to release + * + * Release all resources associated with a write request after it + * has been committed to stable storage + * + * Note: Should never be called with the spinlock held! + */ +void +nfs_release_request(struct nfs_page *req) +{ + struct inode *inode = req->wb_inode; + struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); + + spin_lock(&nfs_wreq_lock); + if (--req->wb_count) { + spin_unlock(&nfs_wreq_lock); + return; + } + __nfs_del_lru(req); + spin_unlock(&nfs_wreq_lock); + atomic_dec(&cache->nr_requests); + +#ifdef NFS_PARANOIA + if (!list_empty(&req->wb_list)) + BUG(); + if (!list_empty(&req->wb_hash)) + BUG(); + if (NFS_WBACK_BUSY(req)) + BUG(); + if (atomic_read(&cache->nr_requests) < 0) + BUG(); +#endif + + /* Release struct file or cached credential */ + if (req->wb_file) + fput(req->wb_file); + else if (req->wb_cred) + put_rpccred(req->wb_cred); + page_cache_release(req->wb_page); + nfs_page_free(req); +} + +/** + * nfs_list_add_request - Insert a request into a sorted list + * @req: request + * @head: head of list into which to insert the request. + * + * Note that the wb_list is sorted by page index in order to facilitate + * coalescing of requests. + * We use an insertion sort that is optimized for the case of appended + * writes. + */ +void +nfs_list_add_request(struct nfs_page *req, struct list_head *head) +{ + struct list_head *pos; + unsigned long pg_idx = page_index(req->wb_page); + +#ifdef NFS_PARANOIA + if (!list_empty(&req->wb_list)) { + printk(KERN_ERR "NFS: Add to list failed!\n"); + BUG(); + } +#endif + for (pos = head->prev; pos != head; pos = pos->prev) { + struct nfs_page *p = nfs_list_entry(pos); + if (page_index(p->wb_page) < pg_idx) + break; + } + list_add(&req->wb_list, pos); + req->wb_list_head = head; +} + +/** + * nfs_wait_on_request - Wait for a request to complete. + * @req: request to wait upon. + * + * Interruptible by signals only if mounted with intr flag. + * The user is responsible for holding a count on the request. + */ +int +nfs_wait_on_request(struct nfs_page *req) +{ + struct inode *inode = req->wb_inode; + struct rpc_clnt *clnt = NFS_CLIENT(inode); + + if (!NFS_WBACK_BUSY(req)) + return 0; + return nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req)); +} + +/** + * nfs_coalesce_requests - Split coalesced requests out from a list. + * @head: source list + * @dst: destination list + * @nmax: maximum number of requests to coalesce + * + * Moves a maximum of 'nmax' elements from one list to another. + * The elements are checked to ensure that they form a contiguous set + * of pages, and that they originated from the same file. + */ +int +nfs_coalesce_requests(struct list_head *head, struct list_head *dst, + unsigned int nmax) +{ + struct nfs_page *req = NULL; + unsigned int npages = 0; + + while (!list_empty(head)) { + struct nfs_page *prev = req; + + req = nfs_list_entry(head->next); + if (prev) { + if (req->wb_file != prev->wb_file) + break; + if (page_index(req->wb_page) != page_index(prev->wb_page)+1) + break; + + if (req->wb_offset != 0) + break; + } + nfs_list_remove_request(req); + nfs_list_add_request(req, dst); + npages++; + if (req->wb_offset + req->wb_bytes != PAGE_CACHE_SIZE) + break; + if (npages >= nmax) + break; + } + return npages; +} + +/* + * nfs_scan_forward - Coalesce more requests + * @req: First request to add + * @dst: destination list + * @nmax: maximum number of requests to coalesce + * + * Tries to coalesce more requests by traversing the request's wb_list. + * Moves the resulting list into dst. Requests are guaranteed to be + * contiguous, and to originate from the same file. + */ +static int +nfs_scan_forward(struct nfs_page *req, struct list_head *dst, int nmax) +{ + struct nfs_server *server = NFS_SERVER(req->wb_inode); + struct list_head *pos, *head = req->wb_list_head; + struct file *file = req->wb_file; + unsigned long idx = page_index(req->wb_page) + 1; + int npages = 0; + + for (pos = req->wb_list.next; nfs_lock_request(req); pos = pos->next) { + nfs_list_remove_request(req); + nfs_list_add_request(req, dst); + __nfs_del_lru(req); + __nfs_add_lru(&server->lru_busy, req); + npages++; + if (npages == nmax) + break; + if (pos == head) + break; + if (req->wb_offset + req->wb_bytes != PAGE_CACHE_SIZE) + break; + req = nfs_list_entry(pos); + if (page_index(req->wb_page) != idx++) + break; + if (req->wb_offset != 0) + break; + if (req->wb_file != file) + break; + } + return npages; +} + +/** + * nfs_scan_lru - Scan one of the least recently used list + * @head: One of the NFS superblock lru lists + * @dst: Destination list + * @nmax: maximum number of requests to coalesce + * + * Scans one of the NFS superblock lru lists for upto nmax requests + * and returns them on a list. The requests are all guaranteed to be + * contiguous, originating from the same inode and the same file. + */ +int +nfs_scan_lru(struct list_head *head, struct list_head *dst, int nmax) +{ + struct list_head *pos; + struct nfs_page *req; + int npages = 0; + + list_for_each(pos, head) { + req = nfs_lru_entry(pos); + npages = nfs_scan_forward(req, dst, nmax); + if (npages) + break; + } + return npages; +} + +/** + * nfs_scan_lru_timeout - Scan one of the superblock lru lists for timed out requests + * @head: One of the NFS superblock lru lists + * @dst: Destination list + * @nmax: maximum number of requests to coalesce + * + * Scans one of the NFS superblock lru lists for upto nmax requests + * and returns them on a list. The requests are all guaranteed to be + * contiguous, originating from the same inode and the same file. + * The first request on the destination list will be timed out, the + * others are not guaranteed to be so. + */ +int +nfs_scan_lru_timeout(struct list_head *head, struct list_head *dst, int nmax) +{ + struct list_head *pos; + struct nfs_page *req; + int npages = 0; + + list_for_each(pos, head) { + req = nfs_lru_entry(pos); + if (time_after(req->wb_timeout, jiffies)) + break; + npages = nfs_scan_forward(req, dst, nmax); + if (npages) + break; + } + return npages; +} + +/** + * nfs_scan_list - Scan a list for matching requests + * @head: One of the NFS inode request lists + * @dst: Destination list + * @file: if set, ensure we match requests from this file + * @idx_start: lower bound of page->index to scan + * @npages: idx_start + npages sets the upper bound to scan. + * + * Moves elements from one of the inode request lists. + * If the number of requests is set to 0, the entire address_space + * starting at index idx_start, is scanned. + * The requests are *not* checked to ensure that they form a contiguous set. + * You must be holding the nfs_wreq_lock when calling this function + */ +int +nfs_scan_list(struct list_head *head, struct list_head *dst, + struct file *file, + unsigned long idx_start, unsigned int npages) +{ + struct list_head *pos, *tmp; + struct nfs_page *req; + unsigned long idx_end; + int res; + + res = 0; + if (npages == 0) + idx_end = ~0; + else + idx_end = idx_start + npages - 1; + + list_for_each_safe(pos, tmp, head) { + unsigned long pg_idx; + + req = nfs_list_entry(pos); + + if (file && req->wb_file != file) + continue; + + pg_idx = page_index(req->wb_page); + if (pg_idx < idx_start) + continue; + if (pg_idx > idx_end) + break; + + if (!nfs_lock_request(req)) + continue; + nfs_list_remove_request(req); + nfs_list_add_request(req, dst); + __nfs_del_lru(req); + __nfs_add_lru(&NFS_SERVER(req->wb_inode)->lru_busy, req); + res++; + } + return res; +} + +/* + * nfs_try_to_free_pages - Free up NFS read/write requests + * @server: The NFS superblock + * + * This function attempts to flush out NFS reads and writes in order + * to keep the hard limit on the total number of pending requests + * on a given NFS partition. + * Note: we first try to commit unstable writes, then flush out pending + * reads, then finally the dirty pages. + * The assumption is that this reflects the ordering from the fastest + * to the slowest method for reclaiming requests. + */ +static int +nfs_try_to_free_pages(struct nfs_server *server) +{ + LIST_HEAD(head); + struct nfs_page *req = NULL; + int nreq; + + for (;;) { + if (req) { + int status = nfs_wait_on_request(req); + nfs_release_request(req); + if (status) + break; + req = NULL; + } + nreq = atomic_read(&server->rw_requests->nr_requests); + if (nreq < MAX_REQUEST_HARD) + return 1; + spin_lock(&nfs_wreq_lock); + /* Are there any busy RPC calls that might free up requests? */ + if (!list_empty(&server->lru_busy)) { + req = nfs_lru_entry(server->lru_busy.next); + req->wb_count++; + __nfs_del_lru(req); + spin_unlock(&nfs_wreq_lock); + continue; + } + +#ifdef CONFIG_NFS_V3 + /* Let's try to free up some completed NFSv3 unstable writes */ + nfs_scan_lru_commit(server, &head); + if (!list_empty(&head)) { + spin_unlock(&nfs_wreq_lock); + nfs_commit_list(&head, 0); + continue; + } +#endif + /* OK, so we try to free up some pending readaheads */ + nfs_scan_lru_read(server, &head); + if (!list_empty(&head)) { + spin_unlock(&nfs_wreq_lock); + nfs_pagein_list(&head, server->rpages); + continue; + } + /* Last resort: we try to flush out single requests */ + nfs_scan_lru_dirty(server, &head); + if (!list_empty(&head)) { + spin_unlock(&nfs_wreq_lock); + nfs_flush_list(&head, server->wpages, FLUSH_STABLE); + continue; + } + spin_unlock(&nfs_wreq_lock); + break; + } + /* We failed to free up requests */ + return 0; +} + +int nfs_init_nfspagecache(void) +{ + nfs_page_cachep = kmem_cache_create("nfs_page", + sizeof(struct nfs_page), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (nfs_page_cachep == NULL) + return -ENOMEM; + + return 0; +} + +void nfs_destroy_nfspagecache(void) +{ + if (kmem_cache_destroy(nfs_page_cachep)) + printk(KERN_INFO "nfs_page: not all structures were freed\n"); +} + diff -u --recursive --new-file v2.4.14/linux/fs/nfs/read.c linux/fs/nfs/read.c --- v2.4.14/linux/fs/nfs/read.c Tue Oct 23 22:48:53 2001 +++ linux/fs/nfs/read.c Fri Nov 9 14:28:15 2001 @@ -148,34 +148,6 @@ return result; } -static inline struct nfs_page * -_nfs_find_read(struct inode *inode, struct page *page) -{ - struct list_head *head, *next; - - head = &inode->u.nfs_i.read; - next = head->next; - while (next != head) { - struct nfs_page *req = nfs_list_entry(next); - next = next->next; - if (page_index(req->wb_page) != page_index(page)) - continue; - req->wb_count++; - return req; - } - return NULL; -} - -static struct nfs_page * -nfs_find_read(struct inode *inode, struct page *page) -{ - struct nfs_page *req; - spin_lock(&nfs_wreq_lock); - req = _nfs_find_read(inode, page); - spin_unlock(&nfs_wreq_lock); - return req; -} - /* * Add a request to the inode's asynchronous read list. */ @@ -185,61 +157,26 @@ struct inode *inode = req->wb_inode; spin_lock(&nfs_wreq_lock); - if (list_empty(&req->wb_list)) { - nfs_list_add_request(req, &inode->u.nfs_i.read); - inode->u.nfs_i.nread++; - } + nfs_list_add_request(req, &inode->u.nfs_i.read); + inode->u.nfs_i.nread++; + __nfs_add_lru(&NFS_SERVER(inode)->lru_read, req); spin_unlock(&nfs_wreq_lock); - /* - * NB: the call to inode_schedule_scan() must lie outside the - * spinlock since it can run flushd(). - */ - inode_schedule_scan(inode, req->wb_timeout); } static int nfs_readpage_async(struct file *file, struct inode *inode, struct page *page) { - struct nfs_page *req, *new = NULL; - int result; - - for (;;) { - result = 0; - if (Page_Uptodate(page)) - break; + struct nfs_page *new; - req = nfs_find_read(inode, page); - if (req) { - if (page != req->wb_page) { - nfs_release_request(req); - nfs_pagein_inode(inode, page_index(page), 0); - continue; - } - nfs_release_request(req); - break; - } - - if (new) { - nfs_lock_request(new); - new->wb_timeout = jiffies + NFS_READ_DELAY; - nfs_mark_request_read(new); - nfs_unlock_request(new); - new = NULL; - break; - } - - result = -ENOMEM; - new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE); - if (!new) - break; - } + new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE); + if (IS_ERR(new)) + return PTR_ERR(new); + nfs_mark_request_read(new); if (inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages || page_index(page) == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) nfs_pagein_inode(inode, 0, 0); - if (new) - nfs_release_request(new); - return result; + return 0; } /* @@ -345,14 +282,13 @@ return -ENOMEM; } -static int -nfs_pagein_list(struct inode *inode, struct list_head *head) +int +nfs_pagein_list(struct list_head *head, int rpages) { LIST_HEAD(one_request); struct nfs_page *req; int error = 0; - unsigned int pages = 0, - rpages = NFS_SERVER(inode)->rpages; + unsigned int pages = 0; while (!list_empty(head)) { pages += nfs_coalesce_requests(head, &one_request, rpages); @@ -368,29 +304,70 @@ return error; } -static int -nfs_scan_read_timeout(struct inode *inode, struct list_head *dst) +/** + * nfs_scan_lru_read_timeout - Scan LRU list for timed out read requests + * @server: NFS superblock data + * @dst: destination list + * + * Moves a maximum of 'rpages' timed out requests from the NFS read LRU list. + * The elements are checked to ensure that they form a contiguous set + * of pages, and that they originated from the same file. + */ +int +nfs_scan_lru_read_timeout(struct nfs_server *server, struct list_head *dst) { - int pages; - spin_lock(&nfs_wreq_lock); - pages = nfs_scan_list_timeout(&inode->u.nfs_i.read, dst, inode); - inode->u.nfs_i.nread -= pages; - if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read)) - printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n"); - spin_unlock(&nfs_wreq_lock); - return pages; + struct inode *inode; + int npages; + + npages = nfs_scan_lru_timeout(&server->lru_read, dst, server->rpages); + if (npages) { + inode = nfs_list_entry(dst->next)->wb_inode; + inode->u.nfs_i.nread -= npages; + } + return npages; } +/** + * nfs_scan_lru_read - Scan LRU list for read requests + * @server: NFS superblock data + * @dst: destination list + * + * Moves a maximum of 'rpages' requests from the NFS read LRU list. + * The elements are checked to ensure that they form a contiguous set + * of pages, and that they originated from the same file. + */ +int +nfs_scan_lru_read(struct nfs_server *server, struct list_head *dst) +{ + struct inode *inode; + int npages; + + npages = nfs_scan_lru(&server->lru_read, dst, server->rpages); + if (npages) { + inode = nfs_list_entry(dst->next)->wb_inode; + inode->u.nfs_i.nread -= npages; + } + return npages; +} + +/* + * nfs_scan_read - Scan an inode for read requests + * @inode: NFS inode to scan + * @dst: destination list + * @idx_start: lower bound of page->index to scan + * @npages: idx_start + npages sets the upper bound to scan + * + * Moves requests from the inode's read list. + * The requests are *not* checked to ensure that they form a contiguous set. + */ static int nfs_scan_read(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) { int res; - spin_lock(&nfs_wreq_lock); res = nfs_scan_list(&inode->u.nfs_i.read, dst, NULL, idx_start, npages); inode->u.nfs_i.nread -= res; if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n"); - spin_unlock(&nfs_wreq_lock); return res; } @@ -401,28 +378,16 @@ int res, error = 0; + spin_lock(&nfs_wreq_lock); res = nfs_scan_read(inode, &head, idx_start, npages); + spin_unlock(&nfs_wreq_lock); if (res) - error = nfs_pagein_list(inode, &head); + error = nfs_pagein_list(&head, NFS_SERVER(inode)->rpages); if (error < 0) return error; return res; } -int nfs_pagein_timeout(struct inode *inode) -{ - LIST_HEAD(head); - int pages, - error = 0; - - pages = nfs_scan_read_timeout(inode, &head); - if (pages) - error = nfs_pagein_list(inode, &head); - if (error < 0) - return error; - return pages; -} - /* * This is the callback from RPC telling us whether a reply was * received or some error occurred (timeout or socket shutdown). @@ -457,8 +422,8 @@ (long long)NFS_FILEID(req->wb_inode), req->wb_bytes, (long long)(page_offset(page) + req->wb_offset)); - nfs_unlock_request(req); nfs_release_request(req); + nfs_unlock_request(req); } } @@ -500,11 +465,10 @@ if (error) goto out_error; - error = -1; - if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) + if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE) { error = nfs_readpage_async(file, inode, page); - if (error >= 0) goto out; + } error = nfs_readpage_sync(file, inode, page); if (error < 0 && IS_SWAPFILE(inode)) diff -u --recursive --new-file v2.4.14/linux/fs/nfs/write.c linux/fs/nfs/write.c --- v2.4.14/linux/fs/nfs/write.c Tue Oct 23 22:48:53 2001 +++ linux/fs/nfs/write.c Fri Nov 9 14:28:15 2001 @@ -61,16 +61,9 @@ #include <asm/uaccess.h> #include <linux/smp_lock.h> -#define NFS_PARANOIA 1 #define NFSDBG_FACILITY NFSDBG_PAGECACHE /* - * Spinlock - */ -spinlock_t nfs_wreq_lock = SPIN_LOCK_UNLOCKED; -static atomic_t nfs_nr_requests = ATOMIC_INIT(0); - -/* * Local structures * * This is the struct where the WRITE/COMMIT arguments go. @@ -103,27 +96,8 @@ # define IS_SWAPFILE(inode) (0) #endif -static kmem_cache_t *nfs_page_cachep; static kmem_cache_t *nfs_wdata_cachep; -static __inline__ struct nfs_page *nfs_page_alloc(void) -{ - struct nfs_page *p; - p = kmem_cache_alloc(nfs_page_cachep, SLAB_NOFS); - if (p) { - memset(p, 0, sizeof(*p)); - INIT_LIST_HEAD(&p->wb_hash); - INIT_LIST_HEAD(&p->wb_list); - init_waitqueue_head(&p->wb_wait); - } - return p; -} - -static __inline__ void nfs_page_free(struct nfs_page *p) -{ - kmem_cache_free(nfs_page_cachep, p); -} - static __inline__ struct nfs_write_data *nfs_writedata_alloc(void) { struct nfs_write_data *p; @@ -248,7 +222,6 @@ if (!req->wb_cred) req->wb_cred = get_rpccred(NFS_I(inode)->mm_cred); nfs_unlock_request(req); - nfs_release_request(req); nfs_strategy(inode); out: return status; @@ -367,11 +340,11 @@ inode->u.nfs_i.npages--; if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n"); - if (list_empty(&inode->u.nfs_i.writeback)) + if (list_empty(&inode->u.nfs_i.writeback)) { + spin_unlock(&nfs_wreq_lock); iput(inode); - if (!nfs_have_writebacks(inode) && !nfs_have_read(inode)) - inode_remove_flushd(inode); - spin_unlock(&nfs_wreq_lock); + } else + spin_unlock(&nfs_wreq_lock); nfs_release_request(req); } @@ -408,44 +381,6 @@ } /* - * Insert a write request into a sorted list - */ -void nfs_list_add_request(struct nfs_page *req, struct list_head *head) -{ - struct list_head *prev; - - if (!list_empty(&req->wb_list)) { - printk(KERN_ERR "NFS: Add to list failed!\n"); - return; - } - if (!NFS_WBACK_BUSY(req)) - printk(KERN_ERR "NFS: unlocked request attempted added to list!\n"); - prev = head->prev; - while (prev != head) { - struct nfs_page *p = nfs_list_entry(prev); - if (page_index(p->wb_page) < page_index(req->wb_page)) - break; - prev = prev->prev; - } - list_add(&req->wb_list, prev); - req->wb_list_head = head; -} - -/* - * Insert a write request into an inode - */ -void nfs_list_remove_request(struct nfs_page *req) -{ - if (list_empty(&req->wb_list)) - return; - if (!NFS_WBACK_BUSY(req)) - printk(KERN_ERR "NFS: unlocked request attempted removed from list!\n"); - list_del(&req->wb_list); - INIT_LIST_HEAD(&req->wb_list); - req->wb_list_head = NULL; -} - -/* * Add a request to the inode's dirty list. */ static inline void @@ -454,16 +389,11 @@ struct inode *inode = req->wb_inode; spin_lock(&nfs_wreq_lock); - if (list_empty(&req->wb_list)) { - nfs_list_add_request(req, &inode->u.nfs_i.dirty); - inode->u.nfs_i.ndirty++; - } + nfs_list_add_request(req, &inode->u.nfs_i.dirty); + inode->u.nfs_i.ndirty++; + __nfs_del_lru(req); + __nfs_add_lru(&NFS_SERVER(inode)->lru_dirty, req); spin_unlock(&nfs_wreq_lock); - /* - * NB: the call to inode_schedule_scan() must lie outside the - * spinlock since it can run flushd(). - */ - inode_schedule_scan(inode, req->wb_timeout); mark_inode_dirty(inode); } @@ -487,165 +417,16 @@ struct inode *inode = req->wb_inode; spin_lock(&nfs_wreq_lock); - if (list_empty(&req->wb_list)) { - nfs_list_add_request(req, &inode->u.nfs_i.commit); - inode->u.nfs_i.ncommit++; - } + nfs_list_add_request(req, &inode->u.nfs_i.commit); + inode->u.nfs_i.ncommit++; + __nfs_del_lru(req); + __nfs_add_lru(&NFS_SERVER(inode)->lru_commit, req); spin_unlock(&nfs_wreq_lock); - /* - * NB: the call to inode_schedule_scan() must lie outside the - * spinlock since it can run flushd(). - */ - inode_schedule_scan(inode, req->wb_timeout); mark_inode_dirty(inode); } #endif /* - * Create a write request. - * Page must be locked by the caller. This makes sure we never create - * two different requests for the same page, and avoids possible deadlock - * when we reach the hard limit on the number of dirty pages. - * It should be safe to sleep here. - */ -struct nfs_page *nfs_create_request(struct file *file, struct inode *inode, - struct page *page, - unsigned int offset, unsigned int count) -{ - struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); - struct nfs_page *req = NULL; - long timeout; - - /* Deal with hard/soft limits. - */ - do { - /* If we're over the global soft limit, wake up all requests */ - if (atomic_read(&nfs_nr_requests) >= MAX_REQUEST_SOFT) { - dprintk("NFS: hit soft limit (%d requests)\n", - atomic_read(&nfs_nr_requests)); - if (!cache->task) - nfs_reqlist_init(NFS_SERVER(inode)); - nfs_wake_flushd(); - } - - /* If we haven't reached the local hard limit yet, - * try to allocate the request struct */ - if (atomic_read(&cache->nr_requests) < MAX_REQUEST_HARD) { - req = nfs_page_alloc(); - if (req != NULL) - break; - } - - /* We're over the hard limit. Wait for better times */ - dprintk("NFS: create_request sleeping (total %d pid %d)\n", - atomic_read(&cache->nr_requests), current->pid); - - timeout = 1 * HZ; - if (NFS_SERVER(inode)->flags & NFS_MOUNT_INTR) { - interruptible_sleep_on_timeout(&cache->request_wait, - timeout); - if (signalled()) - break; - } else - sleep_on_timeout(&cache->request_wait, timeout); - - dprintk("NFS: create_request waking up (tot %d pid %d)\n", - atomic_read(&cache->nr_requests), current->pid); - } while (!req); - if (!req) - return NULL; - - /* Initialize the request struct. Initially, we assume a - * long write-back delay. This will be adjusted in - * update_nfs_request below if the region is not locked. */ - req->wb_page = page; - page_cache_get(page); - req->wb_offset = offset; - req->wb_bytes = count; - req->wb_file = file; - - /* If we have a struct file, use its cached credentials */ - if (file) { - get_file(file); - req->wb_cred = nfs_file_cred(file); - } - req->wb_inode = inode; - req->wb_count = 1; - - /* register request's existence */ - atomic_inc(&cache->nr_requests); - atomic_inc(&nfs_nr_requests); - return req; -} - - -/* - * Release all resources associated with a write request after it - * has been committed to stable storage - * - * Note: Should always be called with the spinlock held! - */ -void -nfs_release_request(struct nfs_page *req) -{ - struct inode *inode = req->wb_inode; - struct nfs_reqlist *cache = NFS_REQUESTLIST(inode); - struct page *page = req->wb_page; - - spin_lock(&nfs_wreq_lock); - if (--req->wb_count) { - spin_unlock(&nfs_wreq_lock); - return; - } - spin_unlock(&nfs_wreq_lock); - - if (!list_empty(&req->wb_list)) { - printk(KERN_ERR "NFS: Request released while still on a list!\n"); - nfs_list_remove_request(req); - } - if (!list_empty(&req->wb_hash)) { - printk(KERN_ERR "NFS: Request released while still hashed!\n"); - nfs_inode_remove_request(req); - } - if (NFS_WBACK_BUSY(req)) - printk(KERN_ERR "NFS: Request released while still locked!\n"); - - /* Release struct file or cached credential */ - if (req->wb_file) - fput(req->wb_file); - else if (req->wb_cred) - put_rpccred(req->wb_cred); - page_cache_release(page); - nfs_page_free(req); - /* wake up anyone waiting to allocate a request */ - atomic_dec(&cache->nr_requests); - atomic_dec(&nfs_nr_requests); - wake_up(&cache->request_wait); -#ifdef NFS_PARANOIA - if (atomic_read(&cache->nr_requests) < 0) - BUG(); - if (atomic_read(&nfs_nr_requests) < 0) - BUG(); -#endif -} - -/* - * Wait for a request to complete. - * - * Interruptible by signals only if mounted with intr flag. - */ -static int -nfs_wait_on_request(struct nfs_page *req) -{ - struct inode *inode = req->wb_inode; - struct rpc_clnt *clnt = NFS_CLIENT(inode); - - if (!NFS_WBACK_BUSY(req)) - return 0; - return nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req)); -} - -/* * Wait for a request to complete. * * Interruptible by signals only if mounted with intr flag. @@ -695,155 +476,152 @@ return res; } -/* - * Scan cluster for dirty pages and send as many of them to the - * server as possible. +/** + * nfs_scan_lru_dirty_timeout - Scan LRU list for timed out dirty requests + * @server: NFS superblock data + * @dst: destination list + * + * Moves a maximum of 'wpages' requests from the NFS dirty page LRU list. + * The elements are checked to ensure that they form a contiguous set + * of pages, and that they originated from the same file. */ -int nfs_scan_list_timeout(struct list_head *head, struct list_head *dst, struct inode *inode) +int +nfs_scan_lru_dirty_timeout(struct nfs_server *server, struct list_head *dst) { - struct list_head *p; - struct nfs_page *req; - int pages = 0; + struct inode *inode; + int npages; - p = head->next; - while (p != head) { - req = nfs_list_entry(p); - p = p->next; - if (time_after(req->wb_timeout, jiffies)) { - if (time_after(NFS_NEXTSCAN(inode), req->wb_timeout)) - NFS_NEXTSCAN(inode) = req->wb_timeout; - continue; - } - if (!nfs_lock_request(req)) - continue; - nfs_list_remove_request(req); - nfs_list_add_request(req, dst); - pages++; + npages = nfs_scan_lru_timeout(&server->lru_dirty, dst, server->wpages); + if (npages) { + inode = nfs_list_entry(dst->next)->wb_inode; + inode->u.nfs_i.ndirty -= npages; } - return pages; -} - -static int -nfs_scan_dirty_timeout(struct inode *inode, struct list_head *dst) -{ - int pages; - spin_lock(&nfs_wreq_lock); - pages = nfs_scan_list_timeout(&inode->u.nfs_i.dirty, dst, inode); - inode->u.nfs_i.ndirty -= pages; - if ((inode->u.nfs_i.ndirty == 0) != list_empty(&inode->u.nfs_i.dirty)) - printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); - spin_unlock(&nfs_wreq_lock); - return pages; + return npages; } -#ifdef CONFIG_NFS_V3 -static int -nfs_scan_commit_timeout(struct inode *inode, struct list_head *dst) -{ - int pages; - spin_lock(&nfs_wreq_lock); - pages = nfs_scan_list_timeout(&inode->u.nfs_i.commit, dst, inode); - inode->u.nfs_i.ncommit -= pages; - if ((inode->u.nfs_i.ncommit == 0) != list_empty(&inode->u.nfs_i.commit)) - printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); - spin_unlock(&nfs_wreq_lock); - return pages; -} -#endif - -int nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages) +/** + * nfs_scan_lru_dirty - Scan LRU list for dirty requests + * @server: NFS superblock data + * @dst: destination list + * + * Moves a maximum of 'wpages' requests from the NFS dirty page LRU list. + * The elements are checked to ensure that they form a contiguous set + * of pages, and that they originated from the same file. + */ +int +nfs_scan_lru_dirty(struct nfs_server *server, struct list_head *dst) { - struct list_head *p; - struct nfs_page *req; - unsigned long idx_end; - int res; - - res = 0; - if (npages == 0) - idx_end = ~0; - else - idx_end = idx_start + npages - 1; - p = src->next; - while (p != src) { - unsigned long pg_idx; - - req = nfs_list_entry(p); - p = p->next; - - if (file && req->wb_file != file) - continue; - - pg_idx = page_index(req->wb_page); - if (pg_idx < idx_start || pg_idx > idx_end) - continue; + struct inode *inode; + int npages; - if (!nfs_lock_request(req)) - continue; - nfs_list_remove_request(req); - nfs_list_add_request(req, dst); - res++; + npages = nfs_scan_lru(&server->lru_dirty, dst, server->wpages); + if (npages) { + inode = nfs_list_entry(dst->next)->wb_inode; + inode->u.nfs_i.ndirty -= npages; } - return res; + return npages; } +/* + * nfs_scan_dirty - Scan an inode for dirty requests + * @inode: NFS inode to scan + * @dst: destination list + * @file: if set, ensure we match requests from this file + * @idx_start: lower bound of page->index to scan. + * @npages: idx_start + npages sets the upper bound to scan. + * + * Moves requests from the inode's dirty page list. + * The requests are *not* checked to ensure that they form a contiguous set. + */ static int nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages) { int res; - spin_lock(&nfs_wreq_lock); res = nfs_scan_list(&inode->u.nfs_i.dirty, dst, file, idx_start, npages); inode->u.nfs_i.ndirty -= res; if ((inode->u.nfs_i.ndirty == 0) != list_empty(&inode->u.nfs_i.dirty)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); - spin_unlock(&nfs_wreq_lock); return res; } #ifdef CONFIG_NFS_V3 +/** + * nfs_scan_lru_commit_timeout - Scan LRU list for timed out commit requests + * @server: NFS superblock data + * @dst: destination list + * + * Finds the first a timed out request in the NFS commit LRU list and moves it + * to the list dst. If such an element is found, we move all other commit + * requests that apply to the same inode. + * The assumption is that doing everything in a single commit-to-disk is + * the cheaper alternative. + */ +int +nfs_scan_lru_commit_timeout(struct nfs_server *server, struct list_head *dst) +{ + struct inode *inode; + int npages; + + npages = nfs_scan_lru_timeout(&server->lru_commit, dst, 1); + if (npages) { + inode = nfs_list_entry(dst->next)->wb_inode; + npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, NULL, 0, 0); + inode->u.nfs_i.ncommit -= npages; + } + return npages; +} + + +/** + * nfs_scan_lru_commit_timeout - Scan LRU list for timed out commit requests + * @server: NFS superblock data + * @dst: destination list + * + * Finds the first request in the NFS commit LRU list and moves it + * to the list dst. If such an element is found, we move all other commit + * requests that apply to the same inode. + * The assumption is that doing everything in a single commit-to-disk is + * the cheaper alternative. + */ +int +nfs_scan_lru_commit(struct nfs_server *server, struct list_head *dst) +{ + struct inode *inode; + int npages; + + npages = nfs_scan_lru(&server->lru_commit, dst, 1); + if (npages) { + inode = nfs_list_entry(dst->next)->wb_inode; + npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, NULL, 0, 0); + inode->u.nfs_i.ncommit -= npages; + } + return npages; +} + +/* + * nfs_scan_commit - Scan an inode for commit requests + * @inode: NFS inode to scan + * @dst: destination list + * @file: if set, ensure we collect requests from this file only. + * @idx_start: lower bound of page->index to scan. + * @npages: idx_start + npages sets the upper bound to scan. + * + * Moves requests from the inode's 'commit' request list. + * The requests are *not* checked to ensure that they form a contiguous set. + */ static int nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages) { int res; - spin_lock(&nfs_wreq_lock); res = nfs_scan_list(&inode->u.nfs_i.commit, dst, file, idx_start, npages); inode->u.nfs_i.ncommit -= res; if ((inode->u.nfs_i.ncommit == 0) != list_empty(&inode->u.nfs_i.commit)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); - spin_unlock(&nfs_wreq_lock); return res; } #endif -int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int maxpages) -{ - struct nfs_page *req = NULL; - unsigned int pages = 0; - - while (!list_empty(src)) { - struct nfs_page *prev = req; - - req = nfs_list_entry(src->next); - if (prev) { - if (req->wb_file != prev->wb_file) - break; - if (page_index(req->wb_page) != page_index(prev->wb_page)+1) - break; - - if (req->wb_offset != 0) - break; - } - nfs_list_remove_request(req); - nfs_list_add_request(req, dst); - pages++; - if (req->wb_offset + req->wb_bytes != PAGE_CACHE_SIZE) - break; - if (pages >= maxpages) - break; - } - return pages; -} - /* * Try to update any existing write request, or create one if there is none. * In order to match, the request's credentials must match those of @@ -867,7 +645,7 @@ spin_lock(&nfs_wreq_lock); req = _nfs_find_request(inode, page); if (req) { - if (!nfs_lock_request(req)) { + if (!nfs_lock_request_dontget(req)) { int error; spin_unlock(&nfs_wreq_lock); error = nfs_wait_on_request(req); @@ -882,24 +660,18 @@ break; } - req = new; - if (req) { - nfs_lock_request(req); - nfs_inode_add_request(inode, req); + if (new) { + nfs_lock_request_dontget(new); + nfs_inode_add_request(inode, new); spin_unlock(&nfs_wreq_lock); - nfs_mark_request_dirty(req); - break; + nfs_mark_request_dirty(new); + return new; } spin_unlock(&nfs_wreq_lock); - /* - * If we're over the soft limit, flush out old requests - */ - if (inode->u.nfs_i.npages >= MAX_REQUEST_SOFT) - nfs_wb_file(inode, file); new = nfs_create_request(file, inode, page, offset, bytes); - if (!new) - return ERR_PTR(-ENOMEM); + if (IS_ERR(new)) + return new; /* If the region is locked, adjust the timeout */ if (region_locked(inode, new)) new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY; @@ -919,7 +691,6 @@ || !nfs_dirty_request(req) || offset > rqend || end < req->wb_offset) { nfs_unlock_request(req); - nfs_release_request(req); return ERR_PTR(-EBUSY); } @@ -967,23 +738,12 @@ if (NFS_PROTO(inode)->version == 2) { if (dirty >= NFS_STRATEGY_PAGES * wpages) nfs_flush_file(inode, NULL, 0, 0, 0); - } else { - if (dirty >= wpages) - nfs_flush_file(inode, NULL, 0, 0, 0); - if (inode->u.nfs_i.ncommit > NFS_STRATEGY_PAGES * wpages && - atomic_read(&nfs_nr_requests) > MAX_REQUEST_SOFT) - nfs_commit_file(inode, NULL, 0, 0, 0); - } + } else if (dirty >= wpages) + nfs_flush_file(inode, NULL, 0, 0, 0); #else if (dirty >= NFS_STRATEGY_PAGES * wpages) nfs_flush_file(inode, NULL, 0, 0, 0); #endif - /* - * If we're running out of free requests, flush out everything - * in order to reduce memory useage... - */ - if (inode->u.nfs_i.npages > MAX_REQUEST_SOFT) - nfs_wb_all(inode); } int @@ -1052,16 +812,16 @@ goto done; status = 0; - nfs_unlock_request(req); /* If we wrote past the end of the page. * Call the strategy routine so it can send out a bunch * of requests. */ if (req->wb_offset == 0 && req->wb_bytes == PAGE_CACHE_SIZE) { SetPageUptodate(page); + nfs_unlock_request(req); nfs_strategy(inode); - } - nfs_release_request(req); + } else + nfs_unlock_request(req); done: dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", status, (long long)inode->i_size); @@ -1123,6 +883,7 @@ struct rpc_task *task; struct rpc_message msg; int flags, + nfsvers = NFS_PROTO(inode)->version, async = !(how & FLUSH_SYNC), stable = (how & FLUSH_STABLE); sigset_t oldset; @@ -1138,7 +899,9 @@ /* Set up the argument struct */ nfs_write_rpcsetup(head, data); - if (stable) { + if (nfsvers < 3) + data->args.stable = NFS_FILE_SYNC; + else if (stable) { if (!inode->u.nfs_i.ncommit) data->args.stable = NFS_FILE_SYNC; else @@ -1153,7 +916,7 @@ task->tk_release = nfs_writedata_release; #ifdef CONFIG_NFS_V3 - msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_WRITE : NFSPROC_WRITE; + msg.rpc_proc = (nfsvers == 3) ? NFS3PROC_WRITE : NFSPROC_WRITE; #else msg.rpc_proc = NFSPROC_WRITE; #endif @@ -1184,14 +947,13 @@ return -ENOMEM; } -static int -nfs_flush_list(struct inode *inode, struct list_head *head, int how) +int +nfs_flush_list(struct list_head *head, int wpages, int how) { LIST_HEAD(one_request); struct nfs_page *req; int error = 0; - unsigned int pages = 0, - wpages = NFS_SERVER(inode)->wpages; + unsigned int pages = 0; while (!list_empty(head)) { pages += nfs_coalesce_requests(head, &one_request, wpages); @@ -1294,7 +1056,7 @@ } #ifdef CONFIG_NFS_V3 - if (resp->verf->committed != NFS_UNSTABLE) { + if (argp->stable != NFS_UNSTABLE || resp->verf->committed == NFS_FILE_SYNC) { nfs_inode_remove_request(req); dprintk(" OK\n"); goto next; @@ -1355,7 +1117,7 @@ /* * Commit dirty pages */ -static int +int nfs_commit_list(struct list_head *head, int how) { struct rpc_message msg; @@ -1464,28 +1226,16 @@ int res, error = 0; + spin_lock(&nfs_wreq_lock); res = nfs_scan_dirty(inode, &head, file, idx_start, npages); + spin_unlock(&nfs_wreq_lock); if (res) - error = nfs_flush_list(inode, &head, how); + error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how); if (error < 0) return error; return res; } -int nfs_flush_timeout(struct inode *inode, int how) -{ - LIST_HEAD(head); - int pages, - error = 0; - - pages = nfs_scan_dirty_timeout(inode, &head); - if (pages) - error = nfs_flush_list(inode, &head, how); - if (error < 0) - return error; - return pages; -} - #ifdef CONFIG_NFS_V3 int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages, int how) @@ -1494,29 +1244,15 @@ int res, error = 0; + spin_lock(&nfs_wreq_lock); res = nfs_scan_commit(inode, &head, file, idx_start, npages); + spin_unlock(&nfs_wreq_lock); if (res) error = nfs_commit_list(&head, how); if (error < 0) return error; return res; } - -int nfs_commit_timeout(struct inode *inode, int how) -{ - LIST_HEAD(head); - int pages, - error = 0; - - pages = nfs_scan_commit_timeout(inode, &head); - if (pages) { - pages += nfs_scan_commit(inode, &head, NULL, 0, 0); - error = nfs_commit_list(&head, how); - } - if (error < 0) - return error; - return pages; -} #endif int nfs_sync_file(struct inode *inode, struct file *file, unsigned long idx_start, @@ -1545,15 +1281,8 @@ return error; } -int nfs_init_nfspagecache(void) +int nfs_init_writepagecache(void) { - nfs_page_cachep = kmem_cache_create("nfs_page", - sizeof(struct nfs_page), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (nfs_page_cachep == NULL) - return -ENOMEM; - nfs_wdata_cachep = kmem_cache_create("nfs_write_data", sizeof(struct nfs_write_data), 0, SLAB_HWCACHE_ALIGN, @@ -1564,10 +1293,8 @@ return 0; } -void nfs_destroy_nfspagecache(void) +void nfs_destroy_writepagecache(void) { - if (kmem_cache_destroy(nfs_page_cachep)) - printk(KERN_INFO "nfs_page: not all structures were freed\n"); if (kmem_cache_destroy(nfs_wdata_cachep)) printk(KERN_INFO "nfs_write_data: not all structures were freed\n"); } diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/Makefile linux/fs/reiserfs/Makefile --- v2.4.14/linux/fs/reiserfs/Makefile Tue Oct 23 22:48:53 2001 +++ linux/fs/reiserfs/Makefile Fri Nov 9 14:18:25 2001 @@ -9,7 +9,7 @@ O_TARGET := reiserfs.o obj-y := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o super.o prints.o objectid.o \ -lbalance.o ibalance.o stree.o hashes.o buffer2.o tail_conversion.o journal.o resize.o tail_conversion.o version.o item_ops.o ioctl.o +lbalance.o ibalance.o stree.o hashes.o buffer2.o tail_conversion.o journal.o resize.o tail_conversion.o version.o item_ops.o ioctl.o procfs.o obj-m := $(O_TARGET) diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/bitmap.c linux/fs/reiserfs/bitmap.c --- v2.4.14/linux/fs/reiserfs/bitmap.c Tue Oct 23 22:48:53 2001 +++ linux/fs/reiserfs/bitmap.c Fri Nov 9 14:18:25 2001 @@ -95,6 +95,8 @@ RFALSE(!s, "vs-4060: trying to free block on nonexistent device"); RFALSE(is_reusable (s, block, 1) == 0, "vs-4070: can not free such block"); + PROC_INFO_INC( s, free_block ); + rs = SB_DISK_SUPER_BLOCK (s); sbh = SB_BUFFER_WITH_SB (s); apbh = SB_AP_BITMAP (s); @@ -136,10 +138,14 @@ unsigned long block_to_try = 0; unsigned long next_block_to_try = 0 ; - for (i = *bmap_nr; i < SB_BMAP_NR (s); i ++, *offset = 0) { + PROC_INFO_INC( s, find_forward.call ); + + for (i = *bmap_nr; i < SB_BMAP_NR (s); i ++, *offset = 0, + PROC_INFO_INC( s, find_forward.bmap )) { /* get corresponding bitmap block */ bh = SB_AP_BITMAP (s)[i]; if (buffer_locked (bh)) { + PROC_INFO_INC( s, find_forward.wait ); __wait_on_buffer (bh); } retry: @@ -174,17 +180,21 @@ int new_i ; get_bit_address (s, next_block_to_try, &new_i, offset); + PROC_INFO_INC( s, find_forward.in_journal_hint ); + /* block is not in this bitmap. reset i and continue ** we only reset i if new_i is in a later bitmap. */ if (new_i > i) { i = (new_i - 1 ); /* i gets incremented by the for loop */ + PROC_INFO_INC( s, find_forward.in_journal_out ); continue ; } } else { /* no suggestion was made, just try the next block */ *offset = j+1 ; } + PROC_INFO_INC( s, find_forward.retry ); goto retry ; } } diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/buffer2.c linux/fs/reiserfs/buffer2.c --- v2.4.14/linux/fs/reiserfs/buffer2.c Mon Nov 5 15:55:34 2001 +++ linux/fs/reiserfs/buffer2.c Fri Nov 9 14:18:25 2001 @@ -16,6 +16,7 @@ #include <linux/locks.h> #include <linux/reiserfs_fs.h> #include <linux/smp_lock.h> +#include <linux/kernel_stat.h> /* * wait_buffer_until_released @@ -63,9 +64,16 @@ block. */ /* The function is NOT SCHEDULE-SAFE! */ -struct buffer_head * reiserfs_bread (kdev_t n_dev, int n_block, int n_size) +struct buffer_head * reiserfs_bread (struct super_block *super, int n_block, int n_size) { - return bread (n_dev, n_block, n_size); + struct buffer_head *result; + PROC_EXP( unsigned int ctx_switches = kstat.context_swtch ); + + result = bread (super -> s_dev, n_block, n_size); + PROC_INFO_INC( super, breads ); + PROC_EXP( if( kstat.context_swtch != ctx_switches ) + PROC_INFO_INC( super, bread_miss ) ); + return result; } /* This function looks for a buffer which contains a given block. If diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/do_balan.c linux/fs/reiserfs/do_balan.c --- v2.4.14/linux/fs/reiserfs/do_balan.c Mon Nov 5 15:55:34 2001 +++ linux/fs/reiserfs/do_balan.c Fri Nov 9 14:18:25 2001 @@ -280,6 +280,9 @@ tb->insert_size [0]); } #endif + + PROC_INFO_INC( tb -> tb_sb, balance_at[ 0 ] ); + /* Make balance in case insert_size[0] < 0 */ if ( tb->insert_size[0] < 0 ) return balance_leaf_when_delete (tb, flag); diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c --- v2.4.14/linux/fs/reiserfs/fix_node.c Tue Oct 23 22:48:53 2001 +++ linux/fs/reiserfs/fix_node.c Fri Nov 9 14:18:25 2001 @@ -575,6 +575,11 @@ tb->lbytes = lb; tb->rbytes = rb; } + PROC_INFO_ADD( tb -> tb_sb, lnum[ h ], lnum ); + PROC_INFO_ADD( tb -> tb_sb, rnum[ h ], rnum ); + + PROC_INFO_ADD( tb -> tb_sb, lbytes[ h ], lb ); + PROC_INFO_ADD( tb -> tb_sb, rbytes[ h ], rb ); } @@ -666,6 +671,7 @@ if (MAX_CHILD_SIZE (S0) + vn->vn_size <= rfree + lfree + ih_size) { set_parameters (tb, 0, -1, -1, -1, NULL, -1, -1); + PROC_INFO_INC( tb -> tb_sb, leaves_removable ); return 1; } return 0; @@ -1169,6 +1175,7 @@ return NO_BALANCING_NEEDED; } } + PROC_INFO_INC( tb -> tb_sb, can_node_be_removed[ h ] ); return !NO_BALANCING_NEEDED; } @@ -1906,8 +1913,11 @@ struct buffer_head * p_s_bh; + PROC_INFO_INC( p_s_sb, get_neighbors[ n_h ] ); + if ( p_s_tb->lnum[n_h] ) { /* We need left neighbor to balance S[n_h]. */ + PROC_INFO_INC( p_s_sb, need_l_neighbor[ n_h ] ); p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset); RFALSE( p_s_bh == p_s_tb->FL[n_h] && @@ -1916,11 +1926,12 @@ n_child_position = ( p_s_bh == p_s_tb->FL[n_h] ) ? p_s_tb->lkey[n_h] : B_NR_ITEMS (p_s_tb->FL[n_h]); n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position); - p_s_bh = reiserfs_bread(p_s_sb->s_dev, n_son_number, p_s_sb->s_blocksize); + p_s_bh = reiserfs_bread(p_s_sb, n_son_number, p_s_sb->s_blocksize); if (!p_s_bh) return IO_ERROR; if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) { decrement_bcount(p_s_bh); + PROC_INFO_INC( p_s_sb, get_neighbors_restart[ n_h ] ); return REPEAT_SEARCH; } @@ -1939,6 +1950,7 @@ if ( p_s_tb->rnum[n_h] ) { /* We need right neighbor to balance S[n_path_offset]. */ + PROC_INFO_INC( p_s_sb, need_r_neighbor[ n_h ] ); p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset); RFALSE( p_s_bh == p_s_tb->FR[n_h] && @@ -1947,11 +1959,12 @@ n_child_position = ( p_s_bh == p_s_tb->FR[n_h] ) ? p_s_tb->rkey[n_h] + 1 : 0; n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position); - p_s_bh = reiserfs_bread(p_s_sb->s_dev, n_son_number, p_s_sb->s_blocksize); + p_s_bh = reiserfs_bread(p_s_sb, n_son_number, p_s_sb->s_blocksize); if (!p_s_bh) return IO_ERROR; if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) { decrement_bcount(p_s_bh); + PROC_INFO_INC( p_s_sb, get_neighbors_restart[ n_h ] ); return REPEAT_SEARCH; } decrement_bcount(p_s_tb->R[n_h]); @@ -2292,6 +2305,8 @@ int wait_tb_buffers_run = 0 ; int windex ; struct buffer_head * p_s_tbS0 = PATH_PLAST_BUFFER(p_s_tb->tb_path); + + ++ p_s_tb -> tb_sb -> u.reiserfs_sb.s_fix_nodes; n_pos_in_item = p_s_tb->tb_path->pos_in_item; diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/ibalance.c linux/fs/reiserfs/ibalance.c --- v2.4.14/linux/fs/reiserfs/ibalance.c Mon Nov 5 15:55:34 2001 +++ linux/fs/reiserfs/ibalance.c Fri Nov 9 14:18:25 2001 @@ -769,6 +769,8 @@ RFALSE( h < 1, "h (%d) can not be < 1 on internal level", h); + PROC_INFO_INC( tb -> tb_sb, balance_at[ h ] ); + order = ( tbSh ) ? PATH_H_POSITION (tb->tb_path, h + 1)/*tb->S[h]->b_item_order*/ : 0; /* Using insert_size[h] calculate the number insert_num of items diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c --- v2.4.14/linux/fs/reiserfs/journal.c Mon Nov 5 15:55:34 2001 +++ linux/fs/reiserfs/journal.c Fri Nov 9 14:18:25 2001 @@ -520,12 +520,14 @@ return 0 ; } + PROC_INFO_INC( p_s_sb, journal.in_journal ); /* If we aren't doing a search_all, this is a metablock, and it will be logged before use. ** if we crash before the transaction that freed it commits, this transaction won't ** have committed either, and the block will never be written */ if (search_all) { for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) { + PROC_INFO_INC( p_s_sb, journal.in_journal_bitmap ); jb = SB_JOURNAL(p_s_sb)->j_list_bitmap + i ; if (jb->journal_list && jb->bitmaps[bmap_nr] && test_bit(bit_nr, jb->bitmaps[bmap_nr]->data)) { @@ -548,6 +550,7 @@ return 1; } + PROC_INFO_INC( p_s_sb, journal.in_journal_reusable ); /* safe for reuse */ return 0 ; } @@ -568,7 +571,9 @@ /* lock the current transaction */ inline static void lock_journal(struct super_block *p_s_sb) { + PROC_INFO_INC( p_s_sb, journal.lock_journal ); while(atomic_read(&(SB_JOURNAL(p_s_sb)->j_wlock)) > 0) { + PROC_INFO_INC( p_s_sb, journal.lock_journal_wait ); sleep_on(&(SB_JOURNAL(p_s_sb)->j_wait)) ; } atomic_set(&(SB_JOURNAL(p_s_sb)->j_wlock), 1) ; @@ -2011,6 +2016,7 @@ th->t_super = p_s_sb ; /* others will check this for the don't log flag */ return 0 ; } + PROC_INFO_INC( p_s_sb, journal.journal_being ); relock: lock_journal(p_s_sb) ; @@ -2018,6 +2024,7 @@ if (test_bit(WRITERS_BLOCKED, &SB_JOURNAL(p_s_sb)->j_state)) { unlock_journal(p_s_sb) ; reiserfs_wait_on_write_block(p_s_sb) ; + PROC_INFO_INC( p_s_sb, journal.journal_relock_writers ); goto relock ; } @@ -2056,6 +2063,7 @@ sleep_on(&(SB_JOURNAL(p_s_sb)->j_join_wait)) ; } } + PROC_INFO_INC( p_s_sb, journal.journal_relock_wcount ); goto relock ; } @@ -2102,6 +2110,7 @@ int count_already_incd = 0 ; int prepared = 0 ; + PROC_INFO_INC( p_s_sb, journal.mark_dirty ); if (reiserfs_dont_log(th->t_super)) { mark_buffer_dirty(bh) ; return 0 ; @@ -2116,6 +2125,7 @@ prepared = test_and_clear_bit(BH_JPrepared, &bh->b_state) ; /* already in this transaction, we are done */ if (buffer_journaled(bh)) { + PROC_INFO_INC( p_s_sb, journal.mark_dirty_already ); return 0 ; } @@ -2145,6 +2155,7 @@ if (buffer_journal_dirty(bh)) { count_already_incd = 1 ; + PROC_INFO_INC( p_s_sb, journal.mark_dirty_notjournal ); mark_buffer_notjournal_dirty(bh) ; } @@ -2645,6 +2656,7 @@ void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb, struct buffer_head *bh) { + PROC_INFO_INC( p_s_sb, journal.restore_prepared ); if (reiserfs_dont_log (p_s_sb)) return; @@ -2666,6 +2678,7 @@ struct buffer_head *bh, int wait) { int retry_count = 0 ; + PROC_INFO_INC( p_s_sb, journal.prepare ); if (reiserfs_dont_log (p_s_sb)) return; @@ -2681,6 +2694,7 @@ "waiting while do_balance was running\n") ; wait_on_buffer(bh) ; } + PROC_INFO_INC( p_s_sb, journal.prepare_retry ); retry_count++ ; } } diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/namei.c linux/fs/reiserfs/namei.c --- v2.4.14/linux/fs/reiserfs/namei.c Mon Nov 5 15:55:34 2001 +++ linux/fs/reiserfs/namei.c Fri Nov 9 14:18:25 2001 @@ -475,6 +475,9 @@ put_deh_offset(deh, SET_GENERATION_NUMBER(deh_offset(deh), gen_number)); set_cpu_key_k_offset (&entry_key, deh_offset(deh)); + /* update max-hash-collisions counter in reiserfs_sb_info */ + PROC_INFO_MAX( th -> t_super, max_hash_collisions, gen_number ); + if (gen_number != 0) { /* we need to re-search for the insertion point */ if (search_by_entry_key (dir->i_sb, &entry_key, &path, &de) != NAME_NOT_FOUND) { reiserfs_warning ("vs-7032: reiserfs_add_entry: " diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/objectid.c linux/fs/reiserfs/objectid.c --- v2.4.14/linux/fs/reiserfs/objectid.c Mon Nov 5 15:55:34 2001 +++ linux/fs/reiserfs/objectid.c Fri Nov 9 14:18:25 2001 @@ -145,9 +145,11 @@ } /* JDM comparing two little-endian values for equality -- safe */ - if (rs->s_oid_cursize == rs->s_oid_maxsize) + if (rs->s_oid_cursize == rs->s_oid_maxsize) { /* objectid map must be expanded, but there is no space */ + PROC_INFO_INC( s, leaked_oid ); return; + } /* expand the objectid map*/ memmove (map + i + 3, map + i + 1, diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/prints.c linux/fs/reiserfs/prints.c --- v2.4.14/linux/fs/reiserfs/prints.c Mon Nov 5 15:55:34 2001 +++ linux/fs/reiserfs/prints.c Fri Nov 9 14:18:25 2001 @@ -520,15 +520,8 @@ (sb_state(rs) == REISERFS_VALID_FS) ? "VALID" : "ERROR"); printk ("Hash function \"%s\"\n", sb_hash_function_code(rs) == TEA_HASH ? "tea" : - ((sb_hash_function_code(rs) == YURA_HASH) ? "rupasov" : "unknown")); + ( sb_hash_function_code(rs) == YURA_HASH ? "rupasov" : (sb_hash_function_code(rs) == R5_HASH ? "r5" : "unknown"))); -#if 0 - __u32 s_journal_trans_max ; /* max number of blocks in a transaction. */ - __u32 s_journal_block_count ; /* total size of the journal. can change over time */ - __u32 s_journal_max_batch ; /* max number of blocks to batch into a trans */ - __u32 s_journal_max_commit_age ; /* in seconds, how old can an async commit be */ - __u32 s_journal_max_trans_age ; /* in seconds, how old can a transaction be */ -#endif printk ("Tree height %d\n", sb_tree_height(rs)); return 0; } diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/procfs.c linux/fs/reiserfs/procfs.c --- v2.4.14/linux/fs/reiserfs/procfs.c Wed Dec 31 16:00:00 1969 +++ linux/fs/reiserfs/procfs.c Fri Nov 9 14:18:25 2001 @@ -0,0 +1,711 @@ +/* -*- linux-c -*- */ + +/* fs/reiserfs/procfs.c */ + +/* + * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README + */ + +/* proc info support a la one created by Sizif@Botik.RU for PGC */ + +/* $Id: procfs.c,v 1.1.8.2 2001/07/15 17:08:42 god Exp $ */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <asm/uaccess.h> +#include <linux/reiserfs_fs.h> +#include <linux/smp_lock.h> +#include <linux/locks.h> +#include <linux/init.h> +#include <linux/proc_fs.h> + +#if defined( REISERFS_PROC_INFO ) + +/* + * LOCKING: + * + * We rely on new Alexander Viro's super-block locking. + * + */ + +static struct super_block *procinfo_prologue( kdev_t dev ) +{ + struct super_block *result; + + /* get super-block by device */ + result = get_super( dev ); + if( result != NULL ) { + if( !reiserfs_is_super( result ) ) { + printk( KERN_DEBUG "reiserfs: procfs-52: " + "non-reiserfs super found\n" ); + drop_super( result ); + result = NULL; + } + } else + printk( KERN_DEBUG "reiserfs: procfs-74: " + "race between procinfo and umount\n" ); + return result; +} + +int procinfo_epilogue( struct super_block *super ) +{ + drop_super( super ); + return 0; +} + +int reiserfs_proc_tail( int len, char *buffer, char **start, + off_t offset, int count, int *eof ) +{ + /* this is black procfs magic */ + if( offset >= len ) { + *start = buffer; + *eof = 1; + return 0; + } + *start = buffer + offset; + if( ( len -= offset ) > count ) { + return count; + } + *eof = 1; + return len; +} + +int reiserfs_version_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ + int len = 0; + struct super_block *sb; + + sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + if( sb == NULL ) + return -ENOENT; + len += sprintf( &buffer[ len ], "%s format\twith checks %s\n", + old_format_only( sb ) ? "old" : "new", +#if defined( CONFIG_REISERFS_CHECK ) + "on" +#else + "off" +#endif + ); + procinfo_epilogue( sb ); + return reiserfs_proc_tail( len, buffer, start, offset, count, eof ); +} + +int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ + int len = 0; + + len += sprintf( &buffer[ len ], "%s [%s]\n", + reiserfs_get_version_string(), +#if defined( CONFIG_REISERFS_FS_MODULE ) + "as module" +#else + "built into kernel" +#endif + ); + return reiserfs_proc_tail( len, buffer, start, offset, count, eof ); +} + +#define SF( x ) ( r -> x ) +#define SFP( x ) SF( s_proc_info_data.x ) +#define SFPL( x ) SFP( x[ level ] ) +#define SFPF( x ) SFP( find_forward.x ) +#define SFPJ( x ) SFP( journal.x ) + +#define D2C( x ) le16_to_cpu( x ) +#define D4C( x ) le32_to_cpu( x ) +#define DF( x ) D2C( rs -> x ) +#define DFL( x ) D4C( rs -> x ) + +#define objectid_map( s, rs ) (old_format_only (s) ? \ + (__u32 *)((struct reiserfs_super_block_v1 *)rs + 1) : \ + (__u32 *)(rs + 1)) +#define MAP( i ) D4C( objectid_map( sb, rs )[ i ] ) + +#define DJF( x ) le32_to_cpu( rs -> x ) +#define JF( x ) ( r -> s_journal -> x ) + +int reiserfs_super_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ + struct super_block *sb; + struct reiserfs_sb_info *r; + int len = 0; + + sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + if( sb == NULL ) + return -ENOENT; + r = &sb->u.reiserfs_sb; + len += sprintf( &buffer[ len ], + "state: \t%s\n" + "mount options: \t%s%s%s%s%s%s%s%s%s%s%s%s\n" + "gen. counter: \t%i\n" + "s_kmallocs: \t%i\n" + "s_disk_reads: \t%i\n" + "s_disk_writes: \t%i\n" + "s_fix_nodes: \t%i\n" + "s_do_balance: \t%i\n" + "s_unneeded_left_neighbor: \t%i\n" + "s_good_search_by_key_reada: \t%i\n" + "s_bmaps: \t%i\n" + "s_bmaps_without_search: \t%i\n" + "s_direct2indirect: \t%i\n" + "s_indirect2direct: \t%i\n" + "\n" + "max_hash_collisions: \t%i\n" + + "breads: \t%lu\n" + "bread_misses: \t%lu\n" + + "search_by_key: \t%lu\n" + "search_by_key_fs_changed: \t%lu\n" + "search_by_key_restarted: \t%lu\n" + + "leaked_oid: \t%lu\n" + "leaves_removable: \t%lu\n", + + SF( s_mount_state ) == REISERFS_VALID_FS ? + "REISERFS_VALID_FS" : "REISERFS_ERROR_FS", + reiserfs_r5_hash( sb ) ? "FORCE_R5 " : "", + reiserfs_rupasov_hash( sb ) ? "FORCE_RUPASOV " : "", + reiserfs_tea_hash( sb ) ? "FORCE_TEA " : "", + reiserfs_hash_detect( sb ) ? "DETECT_HASH " : "", + reiserfs_no_border( sb ) ? "NO_BORDER " : "BORDER ", + reiserfs_no_unhashed_relocation( sb ) ? "NO_UNHASHED_RELOCATION " : "", + reiserfs_hashed_relocation( sb ) ? "UNHASHED_RELOCATION " : "", + reiserfs_test4( sb ) ? "TEST4 " : "", + dont_have_tails( sb ) ? "NO_TAILS " : "TAILS ", + replay_only( sb ) ? "REPLAY_ONLY " : "", + reiserfs_dont_log( sb ) ? "DONT_LOG " : "LOG ", + old_format_only( sb ) ? "CONV " : "", + + atomic_read( &r -> s_generation_counter ), + SF( s_kmallocs ), + SF( s_disk_reads ), + SF( s_disk_writes ), + SF( s_fix_nodes ), + SF( s_do_balance ), + SF( s_unneeded_left_neighbor ), + SF( s_good_search_by_key_reada ), + SF( s_bmaps ), + SF( s_bmaps_without_search ), + SF( s_direct2indirect ), + SF( s_indirect2direct ), + SFP( max_hash_collisions ), + SFP( breads ), + SFP( bread_miss ), + SFP( search_by_key ), + SFP( search_by_key_fs_changed ), + SFP( search_by_key_restarted ), + SFP( leaked_oid ), + SFP( leaves_removable ) ); + + procinfo_epilogue( sb ); + return reiserfs_proc_tail( len, buffer, start, offset, count, eof ); +} + +int reiserfs_per_level_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ + struct super_block *sb; + struct reiserfs_sb_info *r; + int len = 0; + int level; + + sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + if( sb == NULL ) + return -ENOENT; + r = &sb->u.reiserfs_sb; + + len += sprintf( &buffer[ len ], + "level\t" + " balances" + " [sbk: reads" + " fs_changed" + " restarted]" + " free space" + " items" + " can_remove" + " lnum" + " rnum" + " lbytes" + " rbytes" + " get_neig" + " get_neig_res" + " need_l_neig" + " need_r_neig" + "\n" + + ); + + for( level = 0 ; level < MAX_HEIGHT ; ++ level ) { + if( len > PAGE_SIZE - 240 ) { + len += sprintf( &buffer[ len ], "... and more\n" ); + break; + } + len += sprintf( &buffer[ len ], + "%i\t" + " %12lu" + " %12lu" + " %12lu" + " %12lu" + " %12lu" + " %12lu" + " %12lu" + " %12li" + " %12li" + " %12li" + " %12li" + " %12lu" + " %12lu" + " %12lu" + " %12lu" + "\n", + level, + SFPL( balance_at ), + SFPL( sbk_read_at ), + SFPL( sbk_fs_changed ), + SFPL( sbk_restarted ), + SFPL( free_at ), + SFPL( items_at ), + SFPL( can_node_be_removed ), + SFPL( lnum ), + SFPL( rnum ), + SFPL( lbytes ), + SFPL( rbytes ), + SFPL( get_neighbors ), + SFPL( get_neighbors_restart ), + SFPL( need_l_neighbor ), + SFPL( need_r_neighbor ) + ); + } + + procinfo_epilogue( sb ); + return reiserfs_proc_tail( len, buffer, start, offset, count, eof ); +} + +int reiserfs_bitmap_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ + struct super_block *sb; + struct reiserfs_sb_info *r = &sb->u.reiserfs_sb; + int len = 0; + + sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + if( sb == NULL ) + return -ENOENT; + r = &sb->u.reiserfs_sb; + + len += sprintf( &buffer[ len ], "free_block: %lu\n" + "find_forward:" + " wait" + " bmap" + " retry" + " journal_hint" + " journal_out" + "\n" + " %12lu" + " %12lu" + " %12lu" + " %12lu" + " %12lu" + " %12lu" + "\n", + SFP( free_block ), + SFPF( call ), + SFPF( wait ), + SFPF( bmap ), + SFPF( retry ), + SFPF( in_journal_hint ), + SFPF( in_journal_out ) ); + + procinfo_epilogue( sb ); + return reiserfs_proc_tail( len, buffer, start, offset, count, eof ); +} + +int reiserfs_on_disk_super_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ + struct super_block *sb; + struct reiserfs_sb_info *sb_info; + struct reiserfs_super_block *rs; + int hash_code; + int len = 0; + + sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + if( sb == NULL ) + return -ENOENT; + sb_info = &sb->u.reiserfs_sb; + rs = sb_info -> s_rs; + hash_code = DFL( s_hash_function_code ); + + len += sprintf( &buffer[ len ], + "block_count: \t%i\n" + "free_blocks: \t%i\n" + "root_block: \t%i\n" + "blocksize: \t%i\n" + "oid_maxsize: \t%i\n" + "oid_cursize: \t%i\n" + "state: \t%i\n" + "magic: \t%12.12s\n" + "hash: \t%s\n" + "tree_height: \t%i\n" + "bmap_nr: \t%i\n" + "version: \t%i\n", + + DFL( s_block_count ), + DFL( s_free_blocks ), + DFL( s_root_block ), + DF( s_blocksize ), + DF( s_oid_maxsize ), + DF( s_oid_cursize ), + DF( s_state ), + rs -> s_magic, + hash_code == TEA_HASH ? "tea" : + ( hash_code == YURA_HASH ) ? "rupasov" : + ( hash_code == R5_HASH ) ? "r5" : + ( hash_code == UNSET_HASH ) ? "unset" : "unknown", + DF( s_tree_height ), + DF( s_bmap_nr ), + DF( s_version ) ); + + procinfo_epilogue( sb ); + return reiserfs_proc_tail( len, buffer, start, offset, count, eof ); +} + +int reiserfs_oidmap_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ + struct super_block *sb; + struct reiserfs_sb_info *sb_info; + struct reiserfs_super_block *rs; + int i; + unsigned int mapsize; + unsigned long total_used; + int len = 0; + int exact; + + sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + if( sb == NULL ) + return -ENOENT; + sb_info = &sb->u.reiserfs_sb; + rs = sb_info -> s_rs; + mapsize = le16_to_cpu( rs -> s_oid_cursize ); + total_used = 0; + + for( i = 0 ; i < mapsize ; ++i ) { + __u32 right; + + right = ( i == mapsize - 1 ) ? MAX_KEY_OBJECTID : MAP( i + 1 ); + len += sprintf( &buffer[ len ], "%s: [ %x .. %x )\n", + ( i & 1 ) ? "free" : "used", MAP( i ), right ); + if( ! ( i & 1 ) ) { + total_used += right - MAP( i ); + } + if( len > PAGE_SIZE - 100 ) { + len += sprintf( &buffer[ len ], "... and more\n" ); + break; + } + } +#if defined( REISERFS_USE_OIDMAPF ) + if( sb_info -> oidmap.use_file && ( sb_info -> oidmap.mapf != NULL ) ) { + loff_t size; + + size = sb_info -> oidmap.mapf -> f_dentry -> d_inode -> i_size; + total_used += size / sizeof( reiserfs_oidinterval_d_t ); + exact = 1; + } else +#endif + { + exact = ( i == mapsize ); + } + len += sprintf( &buffer[ len ], "total: \t%i [%i/%i] used: %lu [%s]\n", + i, + mapsize, le16_to_cpu( rs -> s_oid_maxsize ), + total_used, exact ? "exact" : "estimation" ); + + procinfo_epilogue( sb ); + return reiserfs_proc_tail( len, buffer, start, offset, count, eof ); +} + +int reiserfs_journal_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ + struct super_block *sb; + struct reiserfs_sb_info *r; + struct reiserfs_super_block *rs; + int len = 0; + + sb = procinfo_prologue( ( kdev_t ) ( int ) data ); + if( sb == NULL ) + return -ENOENT; + r = &sb->u.reiserfs_sb; + rs = r -> s_rs; + + len += sprintf( &buffer[ len ], + /* on-disk fields */ + "s_journal_block: \t%i\n" + "s_journal_dev: \t%s[%x]\n" + "s_orig_journal_size: \t%i\n" + "s_journal_trans_max: \t%i\n" + "s_journal_block_count: \t%i\n" + "s_journal_max_batch: \t%i\n" + "s_journal_max_commit_age: \t%i\n" + "s_journal_max_trans_age: \t%i\n" + /* incore fields */ + "j_state: \t%i\n" + "j_trans_id: \t%lu\n" + "j_mount_id: \t%lu\n" + "j_start: \t%lu\n" + "j_len: \t%lu\n" + "j_len_alloc: \t%lu\n" + "j_wcount: \t%i\n" + "j_bcount: \t%lu\n" + "j_first_unflushed_offset: \t%lu\n" + "j_last_flush_trans_id: \t%lu\n" + "j_trans_start_time: \t%li\n" + "j_journal_list_index: \t%i\n" + "j_list_bitmap_index: \t%i\n" + "j_must_wait: \t%i\n" + "j_next_full_flush: \t%i\n" + "j_next_async_flush: \t%i\n" + "j_cnode_used: \t%i\n" + "j_cnode_free: \t%i\n" + "\n" + /* reiserfs_proc_info_data_t.journal fields */ + "in_journal: \t%12lu\n" + "in_journal_bitmap: \t%12lu\n" + "in_journal_reusable: \t%12lu\n" + "lock_journal: \t%12lu\n" + "lock_journal_wait: \t%12lu\n" + "journal_begin: \t%12lu\n" + "journal_relock_writers: \t%12lu\n" + "journal_relock_wcount: \t%12lu\n" + "mark_dirty: \t%12lu\n" + "mark_dirty_already: \t%12lu\n" + "mark_dirty_notjournal: \t%12lu\n" + "restore_prepared: \t%12lu\n" + "prepare: \t%12lu\n" + "prepare_retry: \t%12lu\n", + + DJF( s_journal_block ), + DJF( s_journal_dev ) == 0 ? "none" : bdevname( DJF( s_journal_dev ) ), + DJF( s_journal_dev ), + DJF( s_orig_journal_size ), + DJF( s_journal_trans_max ), + DJF( s_journal_block_count ), + DJF( s_journal_max_batch ), + DJF( s_journal_max_commit_age ), + DJF( s_journal_max_trans_age ), + + JF( j_state ), + JF( j_trans_id ), + JF( j_mount_id ), + JF( j_start ), + JF( j_len ), + JF( j_len_alloc ), + atomic_read( & r -> s_journal -> j_wcount ), + JF( j_bcount ), + JF( j_first_unflushed_offset ), + JF( j_last_flush_trans_id ), + JF( j_trans_start_time ), + JF( j_journal_list_index ), + JF( j_list_bitmap_index ), + JF( j_must_wait ), + JF( j_next_full_flush ), + JF( j_next_async_flush ), + JF( j_cnode_used ), + JF( j_cnode_free ), + + SFPJ( in_journal ), + SFPJ( in_journal_bitmap ), + SFPJ( in_journal_reusable ), + SFPJ( lock_journal ), + SFPJ( lock_journal_wait ), + SFPJ( journal_being ), + SFPJ( journal_relock_writers ), + SFPJ( journal_relock_wcount ), + SFPJ( mark_dirty ), + SFPJ( mark_dirty_already ), + SFPJ( mark_dirty_notjournal ), + SFPJ( restore_prepared ), + SFPJ( prepare ), + SFPJ( prepare_retry ) + ); + + procinfo_epilogue( sb ); + return reiserfs_proc_tail( len, buffer, start, offset, count, eof ); +} + + +static struct proc_dir_entry *proc_info_root = NULL; +static const char *proc_info_root_name = "fs/reiserfs"; + +int reiserfs_proc_info_init( struct super_block *sb ) +{ + spin_lock_init( & __PINFO( sb ).lock ); + sb->u.reiserfs_sb.procdir = proc_mkdir( bdevname( sb -> s_dev ), + proc_info_root ); + if( sb->u.reiserfs_sb.procdir ) { + sb->u.reiserfs_sb.procdir -> owner = THIS_MODULE; + return 0; + } + reiserfs_warning( "reiserfs: cannot create /proc/%s/%s\n", + proc_info_root_name, bdevname( sb -> s_dev ) ); + return 1; +} + + +int reiserfs_proc_info_done( struct super_block *sb ) +{ + spin_lock( & __PINFO( sb ).lock ); + __PINFO( sb ).exiting = 1; + spin_unlock( & __PINFO( sb ).lock ); + if ( proc_info_root ) { + remove_proc_entry( bdevname( sb -> s_dev ), proc_info_root ); + sb->u.reiserfs_sb.procdir = NULL; + } + return 0; +} + +/* Create /proc/fs/reiserfs/DEV/name and attach read procedure @func + to it. Other parts of reiserfs use this function to make their + per-device statistics available via /proc */ + +struct proc_dir_entry *reiserfs_proc_register( struct super_block *sb, + char *name, read_proc_t *func ) +{ + return ( sb->u.reiserfs_sb.procdir ) ? create_proc_read_entry + ( name, 0, sb->u.reiserfs_sb.procdir, func, + ( void * ) ( int ) sb -> s_dev ) : NULL; +} + +void reiserfs_proc_unregister( struct super_block *sb, const char *name ) +{ + remove_proc_entry( name, sb->u.reiserfs_sb.procdir ); +} + +struct proc_dir_entry *reiserfs_proc_register_global( char *name, + read_proc_t *func ) +{ + return ( proc_info_root ) ? create_proc_read_entry( name, 0, + proc_info_root, + func, NULL ) : NULL; +} + +void reiserfs_proc_unregister_global( const char *name ) +{ + remove_proc_entry( name, proc_info_root ); +} + +int reiserfs_proc_info_global_init( void ) +{ + if( proc_info_root == NULL ) { + proc_info_root = proc_mkdir( proc_info_root_name, 0 ); + if( proc_info_root ) { + proc_info_root -> owner = THIS_MODULE; + } else { + reiserfs_warning( "reiserfs: cannot create /proc/%s\n", + proc_info_root_name ); + return 1; + } + } + return 0; +} + +int reiserfs_proc_info_global_done( void ) +{ + if ( proc_info_root != NULL ) { + proc_info_root = NULL; + remove_proc_entry( proc_info_root_name, 0 ); + } + return 0; +} + +/* REISERFS_PROC_INFO */ +#else + +int reiserfs_proc_info_init( struct super_block *sb ) { return 0; } +int reiserfs_proc_info_done( struct super_block *sb ) { return 0; } + +struct proc_dir_entry *reiserfs_proc_register( struct super_block *sb, + char *name, + read_proc_t *func ) +{ return NULL; } + +void reiserfs_proc_unregister( struct super_block *sb, const char *name ) +{;} + +struct proc_dir_entry *reiserfs_proc_register_global( char *name, + read_proc_t *func ) +{ return NULL; } + +void reiserfs_proc_unregister_global( const char *name ) {;} + +int reiserfs_proc_info_global_init( void ) { return 0; } +int reiserfs_proc_info_global_done( void ) { return 0; } + +int reiserfs_global_version_in_proc( char *buffer, char **start, + off_t offset, + int count, int *eof, void *data ) +{ return 0; } + +int reiserfs_version_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ return 0; } + +int reiserfs_super_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ return 0; } + +int reiserfs_per_level_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ return 0; } + +int reiserfs_bitmap_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ return 0; } + +int reiserfs_on_disk_super_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ return 0; } + +int reiserfs_oidmap_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ return 0; } + +int reiserfs_journal_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ) +{ return 0; } + +/* REISERFS_PROC_INFO */ +#endif + +/* + * $Log: procfs.c,v $ + * Revision 1.1.8.2 2001/07/15 17:08:42 god + * . use get_super() in procfs.c + * . remove remove_save_link() from reiserfs_do_truncate() + * + * I accept terms and conditions stated in the Legal Agreement + * (available at http://www.namesys.com/legalese.html) + * + * Revision 1.1.8.1 2001/07/11 16:48:50 god + * proc info support + * + * I accept terms and conditions stated in the Legal Agreement + * (available at http://www.namesys.com/legalese.html) + * + */ + +/* + * Make Linus happy. + * Local variables: + * c-indentation-style: "K&R" + * mode-name: "LC" + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c --- v2.4.14/linux/fs/reiserfs/stree.c Mon Nov 5 15:55:34 2001 +++ linux/fs/reiserfs/stree.c Fri Nov 9 14:18:25 2001 @@ -648,7 +648,6 @@ stop at leaf level - set to DISK_LEAF_NODE_LEVEL */ ) { - kdev_t n_dev = p_s_sb->s_dev; int n_block_number = SB_ROOT_BLOCK (p_s_sb), expected_level = SB_TREE_HEIGHT (p_s_sb), n_block_size = p_s_sb->s_blocksize; @@ -661,7 +660,9 @@ #ifdef CONFIG_REISERFS_CHECK int n_repeat_counter = 0; #endif - + + PROC_INFO_INC( p_s_sb, search_by_key ); + /* As we add each node to a path we increase its count. This means that we must be careful to release all nodes in a path before we either discard the path struct or re-use the path struct, as we do here. */ @@ -696,17 +697,24 @@ /* Read the next tree node, and set the last element in the path to have a pointer to it. */ if ( ! (p_s_bh = p_s_last_element->pe_buffer = - reiserfs_bread(n_dev, n_block_number, n_block_size)) ) { + reiserfs_bread(p_s_sb, n_block_number, n_block_size)) ) { p_s_search_path->path_length --; pathrelse(p_s_search_path); return IO_ERROR; } + if( fs_changed (fs_gen, p_s_sb) ) { + PROC_INFO_INC( p_s_sb, search_by_key_fs_changed ); + PROC_INFO_INC( p_s_sb, sbk_fs_changed[ expected_level - 1 ] ); + } + /* It is possible that schedule occurred. We must check whether the key to search is still in the tree rooted from the current buffer. If not then repeat search from the root. */ if ( fs_changed (fs_gen, p_s_sb) && (!B_IS_IN_TREE (p_s_bh) || !key_in_buffer(p_s_search_path, p_s_key, p_s_sb)) ) { + PROC_INFO_INC( p_s_sb, search_by_key_restarted ); + PROC_INFO_INC( p_s_sb, sbk_restarted[ expected_level - 1 ] ); decrement_counters_in_path(p_s_search_path); /* Get the root block number so that we can repeat the search @@ -740,6 +748,8 @@ /* ok, we have acquired next formatted node in the tree */ n_node_level = B_LEVEL (p_s_bh); + + PROC_INFO_BH_STAT( p_s_sb, p_s_bh, n_node_level - 1 ); RFALSE( n_node_level < n_stop_level, "vs-5152: tree level (%d) is less than stop level (%d)", diff -u --recursive --new-file v2.4.14/linux/fs/reiserfs/super.c linux/fs/reiserfs/super.c --- v2.4.14/linux/fs/reiserfs/super.c Mon Nov 5 15:55:34 2001 +++ linux/fs/reiserfs/super.c Fri Nov 9 14:18:25 2001 @@ -108,10 +108,18 @@ print_statistics (s); if (s->u.reiserfs_sb.s_kmallocs != 0) { - reiserfs_warning ("vs-2004: reiserfs_put_super: aloocated memory left %d\n", + reiserfs_warning ("vs-2004: reiserfs_put_super: allocated memory left %d\n", s->u.reiserfs_sb.s_kmallocs); } + reiserfs_proc_unregister( s, "journal" ); + reiserfs_proc_unregister( s, "oidmap" ); + reiserfs_proc_unregister( s, "on-disk-super" ); + reiserfs_proc_unregister( s, "bitmap" ); + reiserfs_proc_unregister( s, "per-level" ); + reiserfs_proc_unregister( s, "super" ); + reiserfs_proc_unregister( s, "version" ); + reiserfs_proc_info_done( s ); return; } @@ -294,11 +302,11 @@ labeling scheme currently used will have enough space. Then we need one block for the super. -Hans */ bmp = (REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1; /* first of bitmap blocks */ - SB_AP_BITMAP (s)[0] = reiserfs_bread (s->s_dev, bmp, s->s_blocksize); + SB_AP_BITMAP (s)[0] = reiserfs_bread (s, bmp, s->s_blocksize); if(!SB_AP_BITMAP(s)[0]) return 1; for (i = 1, bmp = dl = s->s_blocksize * 8; i < sb_bmap_nr(rs); i ++) { - SB_AP_BITMAP (s)[i] = reiserfs_bread (s->s_dev, bmp, s->s_blocksize); + SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp, s->s_blocksize); if (!SB_AP_BITMAP (s)[i]) return 1; bmp += dl; @@ -321,7 +329,7 @@ memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * sb_bmap_nr(rs)); for (i = 0; i < sb_bmap_nr(rs); i ++) { - SB_AP_BITMAP (s)[i] = reiserfs_bread (s->s_dev, bmp1 + i, s->s_blocksize); + SB_AP_BITMAP (s)[i] = reiserfs_bread (s, bmp1 + i, s->s_blocksize); if (!SB_AP_BITMAP (s)[i]) return 1; } @@ -383,7 +391,7 @@ if (s->s_blocksize != size) set_blocksize (s->s_dev, s->s_blocksize); - bh = reiserfs_bread (s->s_dev, offset / s->s_blocksize, s->s_blocksize); + bh = reiserfs_bread (s, offset / s->s_blocksize, s->s_blocksize); if (!bh) { printk("read_super_block: " "bread failed (dev %s, block %d, size %d)\n", @@ -593,7 +601,6 @@ return 0; } - // // a portion of this function, particularly the VFS interface portion, // was derived from minix or ext2's analog and evolved as the @@ -746,6 +753,14 @@ } } + reiserfs_proc_info_init( s ); + reiserfs_proc_register( s, "version", reiserfs_version_in_proc ); + reiserfs_proc_register( s, "super", reiserfs_super_in_proc ); + reiserfs_proc_register( s, "per-level", reiserfs_per_level_in_proc ); + reiserfs_proc_register( s, "bitmap", reiserfs_bitmap_in_proc ); + reiserfs_proc_register( s, "on-disk-super", reiserfs_on_disk_super_in_proc ); + reiserfs_proc_register( s, "oidmap", reiserfs_oidmap_in_proc ); + reiserfs_proc_register( s, "journal", reiserfs_journal_in_proc ); init_waitqueue_head (&(s->u.reiserfs_sb.s_wait)); printk("%s\n", reiserfs_get_version_string()) ; @@ -800,6 +815,9 @@ // static int __init init_reiserfs_fs (void) { + reiserfs_proc_info_global_init(); + reiserfs_proc_register_global( "version", + reiserfs_global_version_in_proc ); return register_filesystem(&reiserfs_fs_type); } @@ -813,6 +831,8 @@ // static void __exit exit_reiserfs_fs(void) { + reiserfs_proc_unregister_global( "version" ); + reiserfs_proc_info_global_done(); unregister_filesystem(&reiserfs_fs_type); } diff -u --recursive --new-file v2.4.14/linux/fs/sysv/ChangeLog linux/fs/sysv/ChangeLog --- v2.4.14/linux/fs/sysv/ChangeLog Wed Dec 31 16:00:00 1969 +++ linux/fs/sysv/ChangeLog Fri Nov 9 13:45:35 2001 @@ -0,0 +1,13 @@ +Fri Oct 26 2001 Christoph Hellwig <hch@caldera.de> + + * dir.c, ialloc.c, namei.c, include/linux/sysv_fs_i.h: + Implement per-Inode lookup offset cache. + Modelled after Ted's ext2 patch. + +Fri Oct 26 2001 Christoph Hellwig <hch@caldera.de> + + * inode.c, super.c, include/linux/sysv_fs.h, + include/linux/sysv_fs_sb.h: + Remove symlink faking. Noone really wants to use these as + linux filesystems and native OSes don't support it anyway. + diff -u --recursive --new-file v2.4.14/linux/fs/sysv/dir.c linux/fs/sysv/dir.c --- v2.4.14/linux/fs/sysv/dir.c Wed Jul 25 17:10:25 2001 +++ linux/fs/sysv/dir.c Fri Nov 9 13:45:35 2001 @@ -140,33 +140,43 @@ const char * name = dentry->d_name.name; int namelen = dentry->d_name.len; struct inode * dir = dentry->d_parent->d_inode; - unsigned long n; + unsigned long start, n; unsigned long npages = dir_pages(dir); struct page *page = NULL; struct sysv_dir_entry *de; *res_page = NULL; - for (n = 0; n < npages; n++) { + start = dir->u.sysv_i.i_dir_start_lookup; + if (start >= npages) + start = 0; + n = start; + + do { char *kaddr; page = dir_get_page(dir, n); - if (IS_ERR(page)) - continue; - - kaddr = (char*)page_address(page); - de = (struct sysv_dir_entry *) kaddr; - kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE; - for ( ; (char *) de <= kaddr ; de++) { - if (!de->inode) - continue; - if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) - goto found; + if (!IS_ERR(page)) { + kaddr = (char*)page_address(page); + de = (struct sysv_dir_entry *) kaddr; + kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE; + for ( ; (char *) de <= kaddr ; de++) { + if (!de->inode) + continue; + if (namecompare(namelen, SYSV_NAMELEN, + name, de->name)) + goto found; + } } dir_put_page(page); - } + + if (++n >= npages) + n = 0; + } while (n != start); + return NULL; found: + dir->u.sysv_i.i_dir_start_lookup = n; *res_page = page; return de; } diff -u --recursive --new-file v2.4.14/linux/fs/sysv/file.c linux/fs/sysv/file.c --- v2.4.14/linux/fs/sysv/file.c Mon Aug 27 12:41:47 2001 +++ linux/fs/sysv/file.c Fri Nov 9 13:45:35 2001 @@ -30,7 +30,6 @@ struct inode_operations sysv_file_inode_operations = { truncate: sysv_truncate, - setattr: sysv_notify_change, }; int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync) diff -u --recursive --new-file v2.4.14/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c --- v2.4.14/linux/fs/sysv/ialloc.c Wed Jul 25 17:10:25 2001 +++ linux/fs/sysv/ialloc.c Fri Nov 9 13:45:35 2001 @@ -165,6 +165,7 @@ inode->i_ino = fs16_to_cpu(sb, ino); inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_blocks = inode->i_blksize = 0; + inode->u.sysv_i.i_dir_start_lookup = 0; insert_inode_hash(inode); mark_inode_dirty(inode); diff -u --recursive --new-file v2.4.14/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v2.4.14/linux/fs/sysv/inode.c Sun Sep 23 11:41:00 2001 +++ linux/fs/sysv/inode.c Fri Nov 9 13:45:35 2001 @@ -117,7 +117,6 @@ static struct inode_operations sysv_symlink_inode_operations = { readlink: page_readlink, follow_link: page_follow_link, - setattr: sysv_notify_change, }; void sysv_set_inode(struct inode *inode, dev_t rdev) @@ -146,7 +145,6 @@ struct buffer_head * bh; struct sysv_inode * raw_inode; unsigned int block, ino; - umode_t mode; dev_t rdev = 0; ino = inode->i_ino; @@ -162,11 +160,8 @@ bdevname(inode->i_dev)); return; } - mode = fs16_to_cpu(sb, raw_inode->i_mode); - if (sb->sv_kludge_symlinks) - mode = from_coh_imode(mode); /* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */ - inode->i_mode = mode; + inode->i_mode = fs16_to_cpu(sb, raw_inode->i_mode); inode->i_uid = (uid_t)fs16_to_cpu(sb, raw_inode->i_uid); inode->i_gid = (gid_t)fs16_to_cpu(sb, raw_inode->i_gid); inode->i_nlink = fs16_to_cpu(sb, raw_inode->i_nlink); @@ -181,33 +176,16 @@ brelse(bh); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) rdev = (u16)fs32_to_cpu(sb, inode->u.sysv_i.i_data[0]); + inode->u.sysv_i.i_dir_start_lookup = 0; sysv_set_inode(inode, rdev); } -/* To avoid inconsistencies between inodes in memory and inodes on disk. */ -int sysv_notify_change(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = dentry->d_inode; - int error; - - if ((error = inode_change_ok(inode, attr)) != 0) - return error; - - if (attr->ia_valid & ATTR_MODE) - if (inode->i_sb->sv_kludge_symlinks) - if (attr->ia_mode == COH_KLUDGE_SYMLINK_MODE) - attr->ia_mode = COH_KLUDGE_NOT_SYMLINK; - - return inode_setattr(inode, attr); -} - static struct buffer_head * sysv_update_inode(struct inode * inode) { struct super_block * sb = inode->i_sb; struct buffer_head * bh; struct sysv_inode * raw_inode; unsigned int ino, block; - umode_t mode; ino = inode->i_ino; if (!ino || ino > sb->sv_ninodes) { @@ -220,10 +198,8 @@ printk("unable to read i-node block\n"); return 0; } - mode = inode->i_mode; - if (sb->sv_kludge_symlinks) - mode = to_coh_imode(mode); - raw_inode->i_mode = cpu_to_fs16(sb, mode); + + raw_inode->i_mode = cpu_to_fs16(sb, inode->i_mode); raw_inode->i_uid = cpu_to_fs16(sb, fs_high2lowuid(inode->i_uid)); raw_inode->i_gid = cpu_to_fs16(sb, fs_high2lowgid(inode->i_gid)); raw_inode->i_nlink = cpu_to_fs16(sb, inode->i_nlink); diff -u --recursive --new-file v2.4.14/linux/fs/sysv/namei.c linux/fs/sysv/namei.c --- v2.4.14/linux/fs/sysv/namei.c Wed Jul 25 17:10:25 2001 +++ linux/fs/sysv/namei.c Fri Nov 9 13:45:35 2001 @@ -320,5 +320,4 @@ rmdir: sysv_rmdir, mknod: sysv_mknod, rename: sysv_rename, - setattr: sysv_notify_change, }; diff -u --recursive --new-file v2.4.14/linux/fs/sysv/super.c linux/fs/sysv/super.c --- v2.4.14/linux/fs/sysv/super.c Tue Oct 9 17:06:53 2001 +++ linux/fs/sysv/super.c Fri Nov 9 13:45:35 2001 @@ -298,7 +298,6 @@ int bsize = 1 << n_bits; int bsize_4 = bsize >> 2; - sb->sv_kludge_symlinks = 1; sb->sv_firstinodezone = 2; flavour_setup[sb->sv_type](sb); diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/core_apecs.h linux/include/asm-alpha/core_apecs.h --- v2.4.14/linux/include/asm-alpha/core_apecs.h Tue Oct 9 17:06:53 2001 +++ linux/include/asm-alpha/core_apecs.h Fri Nov 9 13:45:35 2001 @@ -374,13 +374,13 @@ #define vuip volatile unsigned int * #define vulp volatile unsigned long * -__EXTERN_INLINE unsigned int apecs_inb(unsigned long addr) +__EXTERN_INLINE u8 apecs_inb(unsigned long addr) { long result = *(vip) ((addr << 5) + APECS_IO + 0x00); return __kernel_extbl(result, addr & 3); } -__EXTERN_INLINE void apecs_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void apecs_outb(u8 b, unsigned long addr) { unsigned long w; @@ -389,13 +389,13 @@ mb(); } -__EXTERN_INLINE unsigned int apecs_inw(unsigned long addr) +__EXTERN_INLINE u16 apecs_inw(unsigned long addr) { long result = *(vip) ((addr << 5) + APECS_IO + 0x08); return __kernel_extwl(result, addr & 3); } -__EXTERN_INLINE void apecs_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void apecs_outw(u16 b, unsigned long addr) { unsigned long w; @@ -404,12 +404,12 @@ mb(); } -__EXTERN_INLINE unsigned int apecs_inl(unsigned long addr) +__EXTERN_INLINE u32 apecs_inl(unsigned long addr) { return *(vuip) ((addr << 5) + APECS_IO + 0x18); } -__EXTERN_INLINE void apecs_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void apecs_outl(u32 b, unsigned long addr) { *(vuip) ((addr << 5) + APECS_IO + 0x18) = b; mb(); @@ -421,7 +421,7 @@ * dense memory space, everything else through sparse space. */ -__EXTERN_INLINE unsigned long apecs_readb(unsigned long addr) +__EXTERN_INLINE u8 apecs_readb(unsigned long addr) { unsigned long result, msb; @@ -435,7 +435,7 @@ return __kernel_extbl(result, addr & 3); } -__EXTERN_INLINE unsigned long apecs_readw(unsigned long addr) +__EXTERN_INLINE u16 apecs_readw(unsigned long addr) { unsigned long result, msb; @@ -449,17 +449,17 @@ return __kernel_extwl(result, addr & 3); } -__EXTERN_INLINE unsigned long apecs_readl(unsigned long addr) +__EXTERN_INLINE u32 apecs_readl(unsigned long addr) { - return *(vuip)addr; + return (*(vuip)addr) & 0xffffffff; } -__EXTERN_INLINE unsigned long apecs_readq(unsigned long addr) +__EXTERN_INLINE u64 apecs_readq(unsigned long addr) { return *(vulp)addr; } -__EXTERN_INLINE void apecs_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void apecs_writeb(u8 b, unsigned long addr) { unsigned long msb; @@ -472,7 +472,7 @@ *(vuip) ((addr << 5) + APECS_SPARSE_MEM + 0x00) = b * 0x01010101; } -__EXTERN_INLINE void apecs_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void apecs_writew(u16 b, unsigned long addr) { unsigned long msb; @@ -485,12 +485,12 @@ *(vuip) ((addr << 5) + APECS_SPARSE_MEM + 0x08) = b * 0x00010001; } -__EXTERN_INLINE void apecs_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void apecs_writel(u32 b, unsigned long addr) { *(vuip)addr = b; } -__EXTERN_INLINE void apecs_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void apecs_writeq(u64 b, unsigned long addr) { *(vulp)addr = b; } diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/core_cia.h linux/include/asm-alpha/core_cia.h --- v2.4.14/linux/include/asm-alpha/core_cia.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-alpha/core_cia.h Fri Nov 9 13:45:35 2001 @@ -307,46 +307,46 @@ #define vuip volatile unsigned int * #define vulp volatile unsigned long * -__EXTERN_INLINE unsigned int cia_inb(unsigned long addr) +__EXTERN_INLINE u8 cia_inb(unsigned long addr) { long result; result = *(vip) ((addr << 5) + CIA_IO + 0x00); return __kernel_extbl(result, addr & 3); } -__EXTERN_INLINE void cia_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void cia_outb(u8 b, unsigned long addr) { unsigned long w = __kernel_insbl(b, addr & 3); *(vuip) ((addr << 5) + CIA_IO + 0x00) = w; mb(); } -__EXTERN_INLINE unsigned int cia_inw(unsigned long addr) +__EXTERN_INLINE u16 cia_inw(unsigned long addr) { long result; result = *(vip) ((addr << 5) + CIA_IO + 0x08); return __kernel_extwl(result, addr & 3); } -__EXTERN_INLINE void cia_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void cia_outw(u16 b, unsigned long addr) { unsigned long w = __kernel_inswl(b, addr & 3); *(vuip) ((addr << 5) + CIA_IO + 0x08) = w; mb(); } -__EXTERN_INLINE unsigned int cia_inl(unsigned long addr) +__EXTERN_INLINE u32 cia_inl(unsigned long addr) { return *(vuip) ((addr << 5) + CIA_IO + 0x18); } -__EXTERN_INLINE void cia_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void cia_outl(u32 b, unsigned long addr) { *(vuip) ((addr << 5) + CIA_IO + 0x18) = b; mb(); } -__EXTERN_INLINE unsigned int cia_bwx_inb(unsigned long addr) +__EXTERN_INLINE u8 cia_bwx_inb(unsigned long addr) { /* ??? I wish I could get rid of this. But there's no ioremap equivalent for I/O space. PCI I/O can be forced into the @@ -356,29 +356,29 @@ return __kernel_ldbu(*(vucp)(addr+CIA_BW_IO)); } -__EXTERN_INLINE void cia_bwx_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void cia_bwx_outb(u8 b, unsigned long addr) { __kernel_stb(b, *(vucp)(addr+CIA_BW_IO)); mb(); } -__EXTERN_INLINE unsigned int cia_bwx_inw(unsigned long addr) +__EXTERN_INLINE u16 cia_bwx_inw(unsigned long addr) { return __kernel_ldwu(*(vusp)(addr+CIA_BW_IO)); } -__EXTERN_INLINE void cia_bwx_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void cia_bwx_outw(u16 b, unsigned long addr) { __kernel_stw(b, *(vusp)(addr+CIA_BW_IO)); mb(); } -__EXTERN_INLINE unsigned int cia_bwx_inl(unsigned long addr) +__EXTERN_INLINE u32 cia_bwx_inl(unsigned long addr) { return *(vuip)(addr+CIA_BW_IO); } -__EXTERN_INLINE void cia_bwx_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void cia_bwx_outl(u32 b, unsigned long addr) { *(vuip)(addr+CIA_BW_IO) = b; mb(); @@ -417,7 +417,7 @@ * */ -__EXTERN_INLINE unsigned long cia_readb(unsigned long addr) +__EXTERN_INLINE u8 cia_readb(unsigned long addr) { unsigned long result; @@ -426,7 +426,7 @@ return __kernel_extbl(result, addr & 3); } -__EXTERN_INLINE unsigned long cia_readw(unsigned long addr) +__EXTERN_INLINE u16 cia_readw(unsigned long addr) { unsigned long result; @@ -435,7 +435,7 @@ return __kernel_extwl(result, addr & 3); } -__EXTERN_INLINE void cia_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void cia_writeb(u8 b, unsigned long addr) { unsigned long w; @@ -444,7 +444,7 @@ *(vuip) ((addr << 5) + CIA_SPARSE_MEM + 0x00) = w; } -__EXTERN_INLINE void cia_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void cia_writew(u16 b, unsigned long addr) { unsigned long w; @@ -453,22 +453,22 @@ *(vuip) ((addr << 5) + CIA_SPARSE_MEM + 0x08) = w; } -__EXTERN_INLINE unsigned long cia_readl(unsigned long addr) +__EXTERN_INLINE u32 cia_readl(unsigned long addr) { return *(vuip)addr; } -__EXTERN_INLINE unsigned long cia_readq(unsigned long addr) +__EXTERN_INLINE u64 cia_readq(unsigned long addr) { return *(vulp)addr; } -__EXTERN_INLINE void cia_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void cia_writel(u32 b, unsigned long addr) { *(vuip)addr = b; } -__EXTERN_INLINE void cia_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void cia_writeq(u64 b, unsigned long addr) { *(vulp)addr = b; } @@ -485,42 +485,42 @@ return; } -__EXTERN_INLINE unsigned long cia_bwx_readb(unsigned long addr) +__EXTERN_INLINE u8 cia_bwx_readb(unsigned long addr) { return __kernel_ldbu(*(vucp)addr); } -__EXTERN_INLINE unsigned long cia_bwx_readw(unsigned long addr) +__EXTERN_INLINE u16 cia_bwx_readw(unsigned long addr) { return __kernel_ldwu(*(vusp)addr); } -__EXTERN_INLINE unsigned long cia_bwx_readl(unsigned long addr) +__EXTERN_INLINE u32 cia_bwx_readl(unsigned long addr) { return *(vuip)addr; } -__EXTERN_INLINE unsigned long cia_bwx_readq(unsigned long addr) +__EXTERN_INLINE u64 cia_bwx_readq(unsigned long addr) { return *(vulp)addr; } -__EXTERN_INLINE void cia_bwx_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void cia_bwx_writeb(u8 b, unsigned long addr) { __kernel_stb(b, *(vucp)addr); } -__EXTERN_INLINE void cia_bwx_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void cia_bwx_writew(u16 b, unsigned long addr) { __kernel_stw(b, *(vusp)addr); } -__EXTERN_INLINE void cia_bwx_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void cia_bwx_writel(u32 b, unsigned long addr) { *(vuip)addr = b; } -__EXTERN_INLINE void cia_bwx_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void cia_bwx_writeq(u64 b, unsigned long addr) { *(vulp)addr = b; } diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/core_irongate.h linux/include/asm-alpha/core_irongate.h --- v2.4.14/linux/include/asm-alpha/core_irongate.h Sun Sep 23 11:41:01 2001 +++ linux/include/asm-alpha/core_irongate.h Fri Nov 9 13:45:35 2001 @@ -190,34 +190,34 @@ #define vuip volatile unsigned int * #define vulp volatile unsigned long * -__EXTERN_INLINE unsigned int irongate_inb(unsigned long addr) +__EXTERN_INLINE u8 irongate_inb(unsigned long addr) { return __kernel_ldbu(*(vucp)(addr + IRONGATE_IO)); } -__EXTERN_INLINE void irongate_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void irongate_outb(u8 b, unsigned long addr) { __kernel_stb(b, *(vucp)(addr + IRONGATE_IO)); mb(); } -__EXTERN_INLINE unsigned int irongate_inw(unsigned long addr) +__EXTERN_INLINE u16 irongate_inw(unsigned long addr) { return __kernel_ldwu(*(vusp)(addr + IRONGATE_IO)); } -__EXTERN_INLINE void irongate_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void irongate_outw(u16 b, unsigned long addr) { __kernel_stw(b, *(vusp)(addr + IRONGATE_IO)); mb(); } -__EXTERN_INLINE unsigned int irongate_inl(unsigned long addr) +__EXTERN_INLINE u32 irongate_inl(unsigned long addr) { return *(vuip)(addr + IRONGATE_IO); } -__EXTERN_INLINE void irongate_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void irongate_outl(u32 b, unsigned long addr) { *(vuip)(addr + IRONGATE_IO) = b; mb(); @@ -227,42 +227,42 @@ * Memory functions. All accesses are done through linear space. */ -__EXTERN_INLINE unsigned long irongate_readb(unsigned long addr) +__EXTERN_INLINE u8 irongate_readb(unsigned long addr) { return __kernel_ldbu(*(vucp)addr); } -__EXTERN_INLINE unsigned long irongate_readw(unsigned long addr) +__EXTERN_INLINE u16 irongate_readw(unsigned long addr) { return __kernel_ldwu(*(vusp)addr); } -__EXTERN_INLINE unsigned long irongate_readl(unsigned long addr) +__EXTERN_INLINE u32 irongate_readl(unsigned long addr) { - return *(vuip)addr; + return (*(vuip)addr) & 0xffffffff; } -__EXTERN_INLINE unsigned long irongate_readq(unsigned long addr) +__EXTERN_INLINE u64 irongate_readq(unsigned long addr) { return *(vulp)addr; } -__EXTERN_INLINE void irongate_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void irongate_writeb(u8 b, unsigned long addr) { __kernel_stb(b, *(vucp)addr); } -__EXTERN_INLINE void irongate_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void irongate_writew(u16 b, unsigned long addr) { __kernel_stw(b, *(vusp)addr); } -__EXTERN_INLINE void irongate_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void irongate_writel(u32 b, unsigned long addr) { *(vuip)addr = b; } -__EXTERN_INLINE void irongate_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void irongate_writeq(u64 b, unsigned long addr) { *(vulp)addr = b; } diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/core_lca.h linux/include/asm-alpha/core_lca.h --- v2.4.14/linux/include/asm-alpha/core_lca.h Sun Sep 23 11:41:01 2001 +++ linux/include/asm-alpha/core_lca.h Fri Nov 9 13:45:35 2001 @@ -219,13 +219,13 @@ #define vuip volatile unsigned int * #define vulp volatile unsigned long * -__EXTERN_INLINE unsigned int lca_inb(unsigned long addr) +__EXTERN_INLINE u8 lca_inb(unsigned long addr) { long result = *(vip) ((addr << 5) + LCA_IO + 0x00); return __kernel_extbl(result, addr & 3); } -__EXTERN_INLINE void lca_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void lca_outb(u8 b, unsigned long addr) { unsigned long w; @@ -234,13 +234,13 @@ mb(); } -__EXTERN_INLINE unsigned int lca_inw(unsigned long addr) +__EXTERN_INLINE u16 lca_inw(unsigned long addr) { long result = *(vip) ((addr << 5) + LCA_IO + 0x08); return __kernel_extwl(result, addr & 3); } -__EXTERN_INLINE void lca_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void lca_outw(u16 b, unsigned long addr) { unsigned long w; @@ -249,12 +249,12 @@ mb(); } -__EXTERN_INLINE unsigned int lca_inl(unsigned long addr) +__EXTERN_INLINE u32 lca_inl(unsigned long addr) { return *(vuip) ((addr << 5) + LCA_IO + 0x18); } -__EXTERN_INLINE void lca_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void lca_outl(u32 b, unsigned long addr) { *(vuip) ((addr << 5) + LCA_IO + 0x18) = b; mb(); @@ -266,7 +266,7 @@ * dense memory space, everything else through sparse space. */ -__EXTERN_INLINE unsigned long lca_readb(unsigned long addr) +__EXTERN_INLINE u8 lca_readb(unsigned long addr) { unsigned long result, msb; @@ -280,7 +280,7 @@ return __kernel_extbl(result, addr & 3); } -__EXTERN_INLINE unsigned long lca_readw(unsigned long addr) +__EXTERN_INLINE u16 lca_readw(unsigned long addr) { unsigned long result, msb; @@ -294,17 +294,17 @@ return __kernel_extwl(result, addr & 3); } -__EXTERN_INLINE unsigned long lca_readl(unsigned long addr) +__EXTERN_INLINE u32 lca_readl(unsigned long addr) { - return *(vuip)addr; + return (*(vuip)addr) & 0xffffffff; } -__EXTERN_INLINE unsigned long lca_readq(unsigned long addr) +__EXTERN_INLINE u64 lca_readq(unsigned long addr) { return *(vulp)addr; } -__EXTERN_INLINE void lca_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void lca_writeb(u8 b, unsigned long addr) { unsigned long msb; unsigned long w; @@ -319,7 +319,7 @@ *(vuip) ((addr << 5) + LCA_SPARSE_MEM + 0x00) = w; } -__EXTERN_INLINE void lca_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void lca_writew(u16 b, unsigned long addr) { unsigned long msb; unsigned long w; @@ -334,12 +334,12 @@ *(vuip) ((addr << 5) + LCA_SPARSE_MEM + 0x08) = w; } -__EXTERN_INLINE void lca_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void lca_writel(u32 b, unsigned long addr) { *(vuip)addr = b; } -__EXTERN_INLINE void lca_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void lca_writeq(u64 b, unsigned long addr) { *(vulp)addr = b; } diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/core_mcpcia.h linux/include/asm-alpha/core_mcpcia.h --- v2.4.14/linux/include/asm-alpha/core_mcpcia.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-alpha/core_mcpcia.h Fri Nov 9 13:45:35 2001 @@ -217,7 +217,7 @@ #define vuip volatile unsigned int * #define vulp volatile unsigned long * -__EXTERN_INLINE unsigned int mcpcia_inb(unsigned long in_addr) +__EXTERN_INLINE u8 mcpcia_inb(unsigned long in_addr) { unsigned long addr, hose, result; @@ -234,7 +234,7 @@ return __kernel_extbl(result, addr & 3); } -__EXTERN_INLINE void mcpcia_outb(unsigned char b, unsigned long in_addr) +__EXTERN_INLINE void mcpcia_outb(u8 b, unsigned long in_addr) { unsigned long addr, hose, w; @@ -247,7 +247,7 @@ mb(); } -__EXTERN_INLINE unsigned int mcpcia_inw(unsigned long in_addr) +__EXTERN_INLINE u16 mcpcia_inw(unsigned long in_addr) { unsigned long addr, hose, result; @@ -259,7 +259,7 @@ return __kernel_extwl(result, addr & 3); } -__EXTERN_INLINE void mcpcia_outw(unsigned short b, unsigned long in_addr) +__EXTERN_INLINE void mcpcia_outw(u16 b, unsigned long in_addr) { unsigned long addr, hose, w; @@ -272,7 +272,7 @@ mb(); } -__EXTERN_INLINE unsigned int mcpcia_inl(unsigned long in_addr) +__EXTERN_INLINE u32 mcpcia_inl(unsigned long in_addr) { unsigned long addr, hose; @@ -283,7 +283,7 @@ return *(vuip) ((addr << 5) + hose + 0x18); } -__EXTERN_INLINE void mcpcia_outl(unsigned int b, unsigned long in_addr) +__EXTERN_INLINE void mcpcia_outl(u32 b, unsigned long in_addr) { unsigned long addr, hose; @@ -345,7 +345,7 @@ return addr >= MCPCIA_SPARSE(0); } -__EXTERN_INLINE unsigned long mcpcia_readb(unsigned long in_addr) +__EXTERN_INLINE u8 mcpcia_readb(unsigned long in_addr) { unsigned long addr = in_addr & 0xffffffffUL; unsigned long hose = in_addr & ~0xffffffffUL; @@ -364,7 +364,7 @@ return __kernel_extbl(result, addr & 3); } -__EXTERN_INLINE unsigned long mcpcia_readw(unsigned long in_addr) +__EXTERN_INLINE u16 mcpcia_readw(unsigned long in_addr) { unsigned long addr = in_addr & 0xffffffffUL; unsigned long hose = in_addr & ~0xffffffffUL; @@ -383,7 +383,7 @@ return __kernel_extwl(result, addr & 3); } -__EXTERN_INLINE void mcpcia_writeb(unsigned char b, unsigned long in_addr) +__EXTERN_INLINE void mcpcia_writeb(u8 b, unsigned long in_addr) { unsigned long addr = in_addr & 0xffffffffUL; unsigned long hose = in_addr & ~0xffffffffUL; @@ -401,7 +401,7 @@ *(vuip) ((addr << 5) + hose + 0x00) = w; } -__EXTERN_INLINE void mcpcia_writew(unsigned short b, unsigned long in_addr) +__EXTERN_INLINE void mcpcia_writew(u16 b, unsigned long in_addr) { unsigned long addr = in_addr & 0xffffffffUL; unsigned long hose = in_addr & ~0xffffffffUL; @@ -419,22 +419,22 @@ *(vuip) ((addr << 5) + hose + 0x08) = w; } -__EXTERN_INLINE unsigned long mcpcia_readl(unsigned long addr) +__EXTERN_INLINE u32 mcpcia_readl(unsigned long addr) { - return *(vuip)addr; + return (*(vuip)addr) & 0xffffffff; } -__EXTERN_INLINE unsigned long mcpcia_readq(unsigned long addr) +__EXTERN_INLINE u64 mcpcia_readq(unsigned long addr) { return *(vulp)addr; } -__EXTERN_INLINE void mcpcia_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void mcpcia_writel(u32 b, unsigned long addr) { *(vuip)addr = b; } -__EXTERN_INLINE void mcpcia_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void mcpcia_writeq(u64 b, unsigned long addr) { *(vulp)addr = b; } diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/core_polaris.h linux/include/asm-alpha/core_polaris.h --- v2.4.14/linux/include/asm-alpha/core_polaris.h Sun Sep 23 11:41:01 2001 +++ linux/include/asm-alpha/core_polaris.h Fri Nov 9 13:45:35 2001 @@ -68,7 +68,7 @@ #define vuip volatile unsigned int * #define vulp volatile unsigned long * -__EXTERN_INLINE unsigned int polaris_inb(unsigned long addr) +__EXTERN_INLINE u8 polaris_inb(unsigned long addr) { /* ??? I wish I could get rid of this. But there's no ioremap equivalent for I/O space. PCI I/O can be forced into the @@ -78,29 +78,29 @@ return __kernel_ldbu(*(vucp)(addr + POLARIS_DENSE_IO_BASE)); } -__EXTERN_INLINE void polaris_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void polaris_outb(u8 b, unsigned long addr) { __kernel_stb(b, *(vucp)(addr + POLARIS_DENSE_IO_BASE)); mb(); } -__EXTERN_INLINE unsigned int polaris_inw(unsigned long addr) +__EXTERN_INLINE u16 polaris_inw(unsigned long addr) { return __kernel_ldwu(*(vusp)(addr + POLARIS_DENSE_IO_BASE)); } -__EXTERN_INLINE void polaris_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void polaris_outw(u16 b, unsigned long addr) { __kernel_stw(b, *(vusp)(addr + POLARIS_DENSE_IO_BASE)); mb(); } -__EXTERN_INLINE unsigned int polaris_inl(unsigned long addr) +__EXTERN_INLINE u32 polaris_inl(unsigned long addr) { return *(vuip)(addr + POLARIS_DENSE_IO_BASE); } -__EXTERN_INLINE void polaris_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void polaris_outl(u32 b, unsigned long addr) { *(vuip)(addr + POLARIS_DENSE_IO_BASE) = b; mb(); @@ -113,42 +113,42 @@ * We will only support DENSE access via BWX insns. */ -__EXTERN_INLINE unsigned long polaris_readb(unsigned long addr) +__EXTERN_INLINE u8 polaris_readb(unsigned long addr) { return __kernel_ldbu(*(vucp)addr); } -__EXTERN_INLINE unsigned long polaris_readw(unsigned long addr) +__EXTERN_INLINE u16 polaris_readw(unsigned long addr) { return __kernel_ldwu(*(vusp)addr); } -__EXTERN_INLINE unsigned long polaris_readl(unsigned long addr) +__EXTERN_INLINE u32 polaris_readl(unsigned long addr) { - return *(vuip)addr; + return (*(vuip)addr) & 0xffffffff; } -__EXTERN_INLINE unsigned long polaris_readq(unsigned long addr) +__EXTERN_INLINE u64 polaris_readq(unsigned long addr) { return *(vulp)addr; } -__EXTERN_INLINE void polaris_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void polaris_writeb(u8 b, unsigned long addr) { __kernel_stb(b, *(vucp)addr); } -__EXTERN_INLINE void polaris_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void polaris_writew(u16 b, unsigned long addr) { __kernel_stw(b, *(vusp)addr); } -__EXTERN_INLINE void polaris_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void polaris_writel(u32 b, unsigned long addr) { *(vuip)addr = b; } -__EXTERN_INLINE void polaris_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void polaris_writeq(u64 b, unsigned long addr) { *(vulp)addr = b; } diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/core_t2.h linux/include/asm-alpha/core_t2.h --- v2.4.14/linux/include/asm-alpha/core_t2.h Sun Sep 23 11:41:01 2001 +++ linux/include/asm-alpha/core_t2.h Fri Nov 9 13:45:35 2001 @@ -329,13 +329,13 @@ #define vip volatile int * #define vuip volatile unsigned int * -__EXTERN_INLINE unsigned int t2_inb(unsigned long addr) +__EXTERN_INLINE u8 t2_inb(unsigned long addr) { long result = *(vip) ((addr << 5) + T2_IO + 0x00); return __kernel_extbl(result, addr & 3); } -__EXTERN_INLINE void t2_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void t2_outb(u8 b, unsigned long addr) { unsigned long w; @@ -344,13 +344,13 @@ mb(); } -__EXTERN_INLINE unsigned int t2_inw(unsigned long addr) +__EXTERN_INLINE u16 t2_inw(unsigned long addr) { long result = *(vip) ((addr << 5) + T2_IO + 0x08); return __kernel_extwl(result, addr & 3); } -__EXTERN_INLINE void t2_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void t2_outw(u16 b, unsigned long addr) { unsigned long w; @@ -359,12 +359,12 @@ mb(); } -__EXTERN_INLINE unsigned int t2_inl(unsigned long addr) +__EXTERN_INLINE u32 t2_inl(unsigned long addr) { return *(vuip) ((addr << 5) + T2_IO + 0x18); } -__EXTERN_INLINE void t2_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void t2_outl(u32 b, unsigned long addr) { *(vuip) ((addr << 5) + T2_IO + 0x18) = b; mb(); @@ -402,7 +402,7 @@ * */ -__EXTERN_INLINE unsigned long t2_readb(unsigned long addr) +__EXTERN_INLINE u8 t2_readb(unsigned long addr) { unsigned long result, msb; @@ -414,7 +414,7 @@ return __kernel_extbl(result, addr & 3); } -__EXTERN_INLINE unsigned long t2_readw(unsigned long addr) +__EXTERN_INLINE u16 t2_readw(unsigned long addr) { unsigned long result, msb; @@ -427,7 +427,7 @@ } /* On SABLE with T2, we must use SPARSE memory even for 32-bit access. */ -__EXTERN_INLINE unsigned long t2_readl(unsigned long addr) +__EXTERN_INLINE u32 t2_readl(unsigned long addr) { unsigned long msb; @@ -438,7 +438,7 @@ return *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18); } -__EXTERN_INLINE unsigned long t2_readq(unsigned long addr) +__EXTERN_INLINE u64 t2_readq(unsigned long addr) { unsigned long r0, r1, work, msb; @@ -452,7 +452,7 @@ return r1 << 32 | r0; } -__EXTERN_INLINE void t2_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void t2_writeb(u8 b, unsigned long addr) { unsigned long msb, w; @@ -464,7 +464,7 @@ *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = w; } -__EXTERN_INLINE void t2_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void t2_writew(u16 b, unsigned long addr) { unsigned long msb, w; @@ -477,7 +477,7 @@ } /* On SABLE with T2, we must use SPARSE memory even for 32-bit access. */ -__EXTERN_INLINE void t2_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void t2_writel(u32 b, unsigned long addr) { unsigned long msb; @@ -488,7 +488,7 @@ *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b; } -__EXTERN_INLINE void t2_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void t2_writeq(u64 b, unsigned long addr) { unsigned long msb, work; diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/core_titan.h linux/include/asm-alpha/core_titan.h --- v2.4.14/linux/include/asm-alpha/core_titan.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-alpha/core_titan.h Fri Nov 9 13:45:35 2001 @@ -379,7 +379,7 @@ #define vuip volatile unsigned int * #define vulp volatile unsigned long * -__EXTERN_INLINE unsigned int titan_inb(unsigned long addr) +__EXTERN_INLINE u8 titan_inb(unsigned long addr) { /* ??? I wish I could get rid of this. But there's no ioremap equivalent for I/O space. PCI I/O can be forced into the @@ -390,33 +390,33 @@ return __kernel_ldbu(*(vucp)addr); } -__EXTERN_INLINE void titan_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void titan_outb(u8 b, unsigned long addr) { addr += TITAN_IO_BIAS; __kernel_stb(b, *(vucp)addr); mb(); } -__EXTERN_INLINE unsigned int titan_inw(unsigned long addr) +__EXTERN_INLINE u16 titan_inw(unsigned long addr) { addr += TITAN_IO_BIAS; return __kernel_ldwu(*(vusp)addr); } -__EXTERN_INLINE void titan_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void titan_outw(u16 b, unsigned long addr) { addr += TITAN_IO_BIAS; __kernel_stw(b, *(vusp)addr); mb(); } -__EXTERN_INLINE unsigned int titan_inl(unsigned long addr) +__EXTERN_INLINE u32 titan_inl(unsigned long addr) { addr += TITAN_IO_BIAS; return *(vuip)addr; } -__EXTERN_INLINE void titan_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void titan_outl(u32 b, unsigned long addr) { addr += TITAN_IO_BIAS; *(vuip)addr = b; @@ -444,42 +444,42 @@ return addr >= TITAN_BASE; } -__EXTERN_INLINE unsigned long titan_readb(unsigned long addr) +__EXTERN_INLINE u8 titan_readb(unsigned long addr) { return __kernel_ldbu(*(vucp)addr); } -__EXTERN_INLINE unsigned long titan_readw(unsigned long addr) +__EXTERN_INLINE u16 titan_readw(unsigned long addr) { return __kernel_ldwu(*(vusp)addr); } -__EXTERN_INLINE unsigned long titan_readl(unsigned long addr) +__EXTERN_INLINE u32 titan_readl(unsigned long addr) { - return *(vuip)addr; + return (*(vuip)addr) & 0xffffffff; } -__EXTERN_INLINE unsigned long titan_readq(unsigned long addr) +__EXTERN_INLINE u64 titan_readq(unsigned long addr) { return *(vulp)addr; } -__EXTERN_INLINE void titan_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void titan_writeb(u8 b, unsigned long addr) { __kernel_stb(b, *(vucp)addr); } -__EXTERN_INLINE void titan_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void titan_writew(u16 b, unsigned long addr) { __kernel_stw(b, *(vusp)addr); } -__EXTERN_INLINE void titan_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void titan_writel(u32 b, unsigned long addr) { *(vuip)addr = b; } -__EXTERN_INLINE void titan_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void titan_writeq(u64 b, unsigned long addr) { *(vulp)addr = b; } diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/core_tsunami.h linux/include/asm-alpha/core_tsunami.h --- v2.4.14/linux/include/asm-alpha/core_tsunami.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-alpha/core_tsunami.h Fri Nov 9 13:45:35 2001 @@ -304,7 +304,7 @@ #define vuip volatile unsigned int * #define vulp volatile unsigned long * -__EXTERN_INLINE unsigned int tsunami_inb(unsigned long addr) +__EXTERN_INLINE u8 tsunami_inb(unsigned long addr) { /* ??? I wish I could get rid of this. But there's no ioremap equivalent for I/O space. PCI I/O can be forced into the @@ -315,33 +315,33 @@ return __kernel_ldbu(*(vucp)addr); } -__EXTERN_INLINE void tsunami_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void tsunami_outb(u8 b, unsigned long addr) { addr += TSUNAMI_IO_BIAS; __kernel_stb(b, *(vucp)addr); mb(); } -__EXTERN_INLINE unsigned int tsunami_inw(unsigned long addr) +__EXTERN_INLINE u16 tsunami_inw(unsigned long addr) { addr += TSUNAMI_IO_BIAS; return __kernel_ldwu(*(vusp)addr); } -__EXTERN_INLINE void tsunami_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void tsunami_outw(u16 b, unsigned long addr) { addr += TSUNAMI_IO_BIAS; __kernel_stw(b, *(vusp)addr); mb(); } -__EXTERN_INLINE unsigned int tsunami_inl(unsigned long addr) +__EXTERN_INLINE u32 tsunami_inl(unsigned long addr) { addr += TSUNAMI_IO_BIAS; return *(vuip)addr; } -__EXTERN_INLINE void tsunami_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void tsunami_outl(u32 b, unsigned long addr) { addr += TSUNAMI_IO_BIAS; *(vuip)addr = b; @@ -369,42 +369,42 @@ return addr >= TSUNAMI_BASE; } -__EXTERN_INLINE unsigned long tsunami_readb(unsigned long addr) +__EXTERN_INLINE u8 tsunami_readb(unsigned long addr) { return __kernel_ldbu(*(vucp)addr); } -__EXTERN_INLINE unsigned long tsunami_readw(unsigned long addr) +__EXTERN_INLINE u16 tsunami_readw(unsigned long addr) { return __kernel_ldwu(*(vusp)addr); } -__EXTERN_INLINE unsigned long tsunami_readl(unsigned long addr) +__EXTERN_INLINE u32 tsunami_readl(unsigned long addr) { return *(vuip)addr; } -__EXTERN_INLINE unsigned long tsunami_readq(unsigned long addr) +__EXTERN_INLINE u64 tsunami_readq(unsigned long addr) { return *(vulp)addr; } -__EXTERN_INLINE void tsunami_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void tsunami_writeb(u8 b, unsigned long addr) { __kernel_stb(b, *(vucp)addr); } -__EXTERN_INLINE void tsunami_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void tsunami_writew(u16 b, unsigned long addr) { __kernel_stw(b, *(vusp)addr); } -__EXTERN_INLINE void tsunami_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void tsunami_writel(u32 b, unsigned long addr) { *(vuip)addr = b; } -__EXTERN_INLINE void tsunami_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void tsunami_writeq(u64 b, unsigned long addr) { *(vulp)addr = b; } diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/core_wildfire.h linux/include/asm-alpha/core_wildfire.h --- v2.4.14/linux/include/asm-alpha/core_wildfire.h Sun Sep 23 11:41:01 2001 +++ linux/include/asm-alpha/core_wildfire.h Fri Nov 9 13:45:35 2001 @@ -278,7 +278,7 @@ #define vuip volatile unsigned int * #define vulp volatile unsigned long * -__EXTERN_INLINE unsigned int wildfire_inb(unsigned long addr) +__EXTERN_INLINE u8 wildfire_inb(unsigned long addr) { /* ??? I wish I could get rid of this. But there's no ioremap equivalent for I/O space. PCI I/O can be forced into the @@ -289,33 +289,33 @@ return __kernel_ldbu(*(vucp)addr); } -__EXTERN_INLINE void wildfire_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void wildfire_outb(u8 b, unsigned long addr) { addr += WILDFIRE_IO_BIAS; __kernel_stb(b, *(vucp)addr); mb(); } -__EXTERN_INLINE unsigned int wildfire_inw(unsigned long addr) +__EXTERN_INLINE u16 wildfire_inw(unsigned long addr) { addr += WILDFIRE_IO_BIAS; return __kernel_ldwu(*(vusp)addr); } -__EXTERN_INLINE void wildfire_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void wildfire_outw(u16 b, unsigned long addr) { addr += WILDFIRE_IO_BIAS; __kernel_stw(b, *(vusp)addr); mb(); } -__EXTERN_INLINE unsigned int wildfire_inl(unsigned long addr) +__EXTERN_INLINE u32 wildfire_inl(unsigned long addr) { addr += WILDFIRE_IO_BIAS; return *(vuip)addr; } -__EXTERN_INLINE void wildfire_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void wildfire_outl(u32 b, unsigned long addr) { addr += WILDFIRE_IO_BIAS; *(vuip)addr = b; @@ -343,42 +343,42 @@ return addr >= WILDFIRE_BASE; } -__EXTERN_INLINE unsigned long wildfire_readb(unsigned long addr) +__EXTERN_INLINE u8 wildfire_readb(unsigned long addr) { return __kernel_ldbu(*(vucp)addr); } -__EXTERN_INLINE unsigned long wildfire_readw(unsigned long addr) +__EXTERN_INLINE u16 wildfire_readw(unsigned long addr) { return __kernel_ldwu(*(vusp)addr); } -__EXTERN_INLINE unsigned long wildfire_readl(unsigned long addr) +__EXTERN_INLINE u32 wildfire_readl(unsigned long addr) { - return *(vuip)addr; + return (*(vuip)addr) & 0xffffffff; } -__EXTERN_INLINE unsigned long wildfire_readq(unsigned long addr) +__EXTERN_INLINE u64 wildfire_readq(unsigned long addr) { return *(vulp)addr; } -__EXTERN_INLINE void wildfire_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void wildfire_writeb(u8 b, unsigned long addr) { __kernel_stb(b, *(vucp)addr); } -__EXTERN_INLINE void wildfire_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void wildfire_writew(u16 b, unsigned long addr) { __kernel_stw(b, *(vusp)addr); } -__EXTERN_INLINE void wildfire_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void wildfire_writel(u32 b, unsigned long addr) { *(vuip)addr = b; } -__EXTERN_INLINE void wildfire_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void wildfire_writeq(u64 b, unsigned long addr) { *(vulp)addr = b; } diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h --- v2.4.14/linux/include/asm-alpha/io.h Sun Sep 23 11:41:01 2001 +++ linux/include/asm-alpha/io.h Fri Nov 9 13:45:35 2001 @@ -192,20 +192,20 @@ * to convince yourself that it won't break anything (in particular * module support). */ -extern unsigned int _inb (unsigned long port); -extern unsigned int _inw (unsigned long port); -extern unsigned int _inl (unsigned long port); -extern void _outb (unsigned char b,unsigned long port); -extern void _outw (unsigned short w,unsigned long port); -extern void _outl (unsigned int l,unsigned long port); -extern unsigned long _readb(unsigned long addr); -extern unsigned long _readw(unsigned long addr); -extern unsigned long _readl(unsigned long addr); -extern unsigned long _readq(unsigned long addr); -extern void _writeb(unsigned char b, unsigned long addr); -extern void _writew(unsigned short b, unsigned long addr); -extern void _writel(unsigned int b, unsigned long addr); -extern void _writeq(unsigned long b, unsigned long addr); +extern u8 _inb (unsigned long port); +extern u16 _inw (unsigned long port); +extern u32 _inl (unsigned long port); +extern void _outb (u8 b,unsigned long port); +extern void _outw (u16 w,unsigned long port); +extern void _outl (u32 l,unsigned long port); +extern u8 _readb(unsigned long addr); +extern u16 _readw(unsigned long addr); +extern u32 _readl(unsigned long addr); +extern u64 _readq(unsigned long addr); +extern void _writeb(u8 b, unsigned long addr); +extern void _writew(u16 b, unsigned long addr); +extern void _writel(u32 b, unsigned long addr); +extern void _writeq(u64 b, unsigned long addr); #ifdef __KERNEL__ /* @@ -256,7 +256,7 @@ #else -/* Userspace declarations. */ +/* Userspace declarations. Kill in 2.5. */ extern unsigned int inb(unsigned long port); extern unsigned int inw(unsigned long port); @@ -308,26 +308,26 @@ /* Indirect back to the macros provided. */ -extern unsigned long ___raw_readb(unsigned long addr); -extern unsigned long ___raw_readw(unsigned long addr); -extern unsigned long ___raw_readl(unsigned long addr); -extern unsigned long ___raw_readq(unsigned long addr); -extern void ___raw_writeb(unsigned char b, unsigned long addr); -extern void ___raw_writew(unsigned short b, unsigned long addr); -extern void ___raw_writel(unsigned int b, unsigned long addr); -extern void ___raw_writeq(unsigned long b, unsigned long addr); +extern u8 ___raw_readb(unsigned long addr); +extern u16 ___raw_readw(unsigned long addr); +extern u32 ___raw_readl(unsigned long addr); +extern u64 ___raw_readq(unsigned long addr); +extern void ___raw_writeb(u8 b, unsigned long addr); +extern void ___raw_writew(u16 b, unsigned long addr); +extern void ___raw_writel(u32 b, unsigned long addr); +extern void ___raw_writeq(u64 b, unsigned long addr); #ifdef __raw_readb -# define readb(a) ({ unsigned long r_ = __raw_readb(a); mb(); r_; }) +# define readb(a) ({ u8 r_ = __raw_readb(a); mb(); r_; }) #endif #ifdef __raw_readw -# define readw(a) ({ unsigned long r_ = __raw_readw(a); mb(); r_; }) +# define readw(a) ({ u16 r_ = __raw_readw(a); mb(); r_; }) #endif #ifdef __raw_readl -# define readl(a) ({ unsigned long r_ = __raw_readl(a); mb(); r_; }) +# define readl(a) ({ u32 r_ = __raw_readl(a); mb(); r_; }) #endif #ifdef __raw_readq -# define readq(a) ({ unsigned long r_ = __raw_readq(a); mb(); r_; }) +# define readq(a) ({ u64 r_ = __raw_readq(a); mb(); r_; }) #endif #ifdef __raw_writeb diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/jensen.h linux/include/asm-alpha/jensen.h --- v2.4.14/linux/include/asm-alpha/jensen.h Sun Sep 23 11:41:01 2001 +++ linux/include/asm-alpha/jensen.h Fri Nov 9 13:45:35 2001 @@ -118,7 +118,7 @@ return 0xff & *(vuip)((addr << 9) + EISA_VL82C106); } -static inline void jensen_local_outb(unsigned char b, unsigned long addr) +static inline void jensen_local_outb(u8 b, unsigned long addr) { *(vuip)((addr << 9) + EISA_VL82C106) = b; mb(); @@ -133,7 +133,7 @@ return __kernel_extbl(result, addr & 3); } -static inline void jensen_bus_outb(unsigned char b, unsigned long addr) +static inline void jensen_bus_outb(u8 b, unsigned long addr) { jensen_set_hae(0); *(vuip)((addr << 7) + EISA_IO + 0x00) = b * 0x01010101; @@ -153,7 +153,7 @@ /* mb LPT1 */ (addr >= 0x3bc && addr <= 0x3be) || \ /* mb COM2 */ (addr >= 0x3f8 && addr <= 0x3ff)) -__EXTERN_INLINE unsigned int jensen_inb(unsigned long addr) +__EXTERN_INLINE u8 jensen_inb(unsigned long addr) { if (jensen_is_local(addr)) return jensen_local_inb(addr); @@ -161,7 +161,7 @@ return jensen_bus_inb(addr); } -__EXTERN_INLINE void jensen_outb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void jensen_outb(u8 b, unsigned long addr) { if (jensen_is_local(addr)) jensen_local_outb(b, addr); @@ -169,7 +169,7 @@ jensen_bus_outb(b, addr); } -__EXTERN_INLINE unsigned int jensen_inw(unsigned long addr) +__EXTERN_INLINE u16 jensen_inw(unsigned long addr) { long result; @@ -179,20 +179,20 @@ return 0xffffUL & result; } -__EXTERN_INLINE unsigned int jensen_inl(unsigned long addr) +__EXTERN_INLINE u32 jensen_inl(unsigned long addr) { jensen_set_hae(0); return *(vuip) ((addr << 7) + EISA_IO + 0x60); } -__EXTERN_INLINE void jensen_outw(unsigned short b, unsigned long addr) +__EXTERN_INLINE void jensen_outw(u16 b, unsigned long addr) { jensen_set_hae(0); *(vuip) ((addr << 7) + EISA_IO + 0x20) = b * 0x00010001; mb(); } -__EXTERN_INLINE void jensen_outl(unsigned int b, unsigned long addr) +__EXTERN_INLINE void jensen_outl(u32 b, unsigned long addr) { jensen_set_hae(0); *(vuip) ((addr << 7) + EISA_IO + 0x60) = b; @@ -203,7 +203,7 @@ * Memory functions. */ -__EXTERN_INLINE unsigned long jensen_readb(unsigned long addr) +__EXTERN_INLINE u8 jensen_readb(unsigned long addr) { long result; @@ -214,7 +214,7 @@ return 0xffUL & result; } -__EXTERN_INLINE unsigned long jensen_readw(unsigned long addr) +__EXTERN_INLINE u16 jensen_readw(unsigned long addr) { long result; @@ -225,14 +225,14 @@ return 0xffffUL & result; } -__EXTERN_INLINE unsigned long jensen_readl(unsigned long addr) +__EXTERN_INLINE u32 jensen_readl(unsigned long addr) { jensen_set_hae(addr); addr &= JENSEN_HAE_MASK; return *(vuip) ((addr << 7) + EISA_MEM + 0x60); } -__EXTERN_INLINE unsigned long jensen_readq(unsigned long addr) +__EXTERN_INLINE u64 jensen_readq(unsigned long addr) { unsigned long r0, r1; @@ -244,28 +244,28 @@ return r1 << 32 | r0; } -__EXTERN_INLINE void jensen_writeb(unsigned char b, unsigned long addr) +__EXTERN_INLINE void jensen_writeb(u8 b, unsigned long addr) { jensen_set_hae(addr); addr &= JENSEN_HAE_MASK; *(vuip) ((addr << 7) + EISA_MEM + 0x00) = b * 0x01010101; } -__EXTERN_INLINE void jensen_writew(unsigned short b, unsigned long addr) +__EXTERN_INLINE void jensen_writew(u16 b, unsigned long addr) { jensen_set_hae(addr); addr &= JENSEN_HAE_MASK; *(vuip) ((addr << 7) + EISA_MEM + 0x20) = b * 0x00010001; } -__EXTERN_INLINE void jensen_writel(unsigned int b, unsigned long addr) +__EXTERN_INLINE void jensen_writel(u32 b, unsigned long addr) { jensen_set_hae(addr); addr &= JENSEN_HAE_MASK; *(vuip) ((addr << 7) + EISA_MEM + 0x60) = b; } -__EXTERN_INLINE void jensen_writeq(unsigned long b, unsigned long addr) +__EXTERN_INLINE void jensen_writeq(u64 b, unsigned long addr) { jensen_set_hae(addr); addr &= JENSEN_HAE_MASK; diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h --- v2.4.14/linux/include/asm-alpha/machvec.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-alpha/machvec.h Fri Nov 9 13:45:35 2001 @@ -44,23 +44,23 @@ void (*mv_pci_tbi)(struct pci_controller *hose, dma_addr_t start, dma_addr_t end); - unsigned int (*mv_inb)(unsigned long); - unsigned int (*mv_inw)(unsigned long); - unsigned int (*mv_inl)(unsigned long); + u8 (*mv_inb)(unsigned long); + u16 (*mv_inw)(unsigned long); + u32 (*mv_inl)(unsigned long); - void (*mv_outb)(unsigned char, unsigned long); - void (*mv_outw)(unsigned short, unsigned long); - void (*mv_outl)(unsigned int, unsigned long); + void (*mv_outb)(u8, unsigned long); + void (*mv_outw)(u16, unsigned long); + void (*mv_outl)(u32, unsigned long); - unsigned long (*mv_readb)(unsigned long); - unsigned long (*mv_readw)(unsigned long); - unsigned long (*mv_readl)(unsigned long); - unsigned long (*mv_readq)(unsigned long); + u8 (*mv_readb)(unsigned long); + u16 (*mv_readw)(unsigned long); + u32 (*mv_readl)(unsigned long); + u64 (*mv_readq)(unsigned long); - void (*mv_writeb)(unsigned char, unsigned long); - void (*mv_writew)(unsigned short, unsigned long); - void (*mv_writel)(unsigned int, unsigned long); - void (*mv_writeq)(unsigned long, unsigned long); + void (*mv_writeb)(u8, unsigned long); + void (*mv_writew)(u16, unsigned long); + void (*mv_writel)(u32, unsigned long); + void (*mv_writeq)(u64, unsigned long); unsigned long (*mv_ioremap)(unsigned long, unsigned long); void (*mv_iounmap)(unsigned long); diff -u --recursive --new-file v2.4.14/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h --- v2.4.14/linux/include/asm-alpha/unistd.h Wed Jan 24 15:16:23 2001 +++ linux/include/asm-alpha/unistd.h Fri Nov 9 13:45:35 2001 @@ -315,6 +315,9 @@ #define __NR_mincore 375 #define __NR_pciconfig_iobase 376 #define __NR_getdents64 377 +#define __NR_gettid 378 +#define __NR_readahead 379 +#define __NR_security 380 /* syscall for security modules */ #if defined(__GNUC__) diff -u --recursive --new-file v2.4.14/linux/include/asm-arm/arch-epxa10db/hardware.h linux/include/asm-arm/arch-epxa10db/hardware.h --- v2.4.14/linux/include/asm-arm/arch-epxa10db/hardware.h Mon Nov 5 15:55:34 2001 +++ linux/include/asm-arm/arch-epxa10db/hardware.h Fri Nov 9 14:11:14 2001 @@ -23,7 +23,6 @@ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H -#include <asm/arch/sizes.h> #include <asm/arch/platform.h> /* diff -u --recursive --new-file v2.4.14/linux/include/asm-arm/arch-integrator/hardware.h linux/include/asm-arm/arch-integrator/hardware.h --- v2.4.14/linux/include/asm-arm/arch-integrator/hardware.h Fri Mar 2 18:38:39 2001 +++ linux/include/asm-arm/arch-integrator/hardware.h Fri Nov 9 14:11:14 2001 @@ -22,7 +22,7 @@ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H -#include <asm/arch/sizes.h> +#include <asm/sizes.h> #include <asm/arch/platform.h> /* diff -u --recursive --new-file v2.4.14/linux/include/asm-arm/arch-integrator/sizes.h linux/include/asm-arm/arch-integrator/sizes.h --- v2.4.14/linux/include/asm-arm/arch-integrator/sizes.h Fri Mar 2 18:38:39 2001 +++ linux/include/asm-arm/arch-integrator/sizes.h Wed Dec 31 16:00:00 1969 @@ -1,52 +0,0 @@ -/* - * 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 - */ -/* DO NOT EDIT!! - this file automatically generated - * from .s file by awk -f s2h.awk - */ -/* Size defintions - * Copyright (C) ARM Limited 1998. All rights reserved. - */ - -#ifndef __sizes_h -#define __sizes_h 1 - -/* handy sizes */ -#define SZ_1K 0x00000400 -#define SZ_4K 0x00001000 -#define SZ_8K 0x00002000 -#define SZ_16K 0x00004000 -#define SZ_64K 0x00010000 -#define SZ_128K 0x00020000 -#define SZ_256K 0x00040000 -#define SZ_512K 0x00080000 - -#define SZ_1M 0x00100000 -#define SZ_2M 0x00200000 -#define SZ_4M 0x00400000 -#define SZ_8M 0x00800000 -#define SZ_16M 0x01000000 -#define SZ_32M 0x02000000 -#define SZ_64M 0x04000000 -#define SZ_128M 0x08000000 -#define SZ_256M 0x10000000 -#define SZ_512M 0x20000000 - -#define SZ_1G 0x40000000 -#define SZ_2G 0x80000000 - -#endif - -/* END */ diff -u --recursive --new-file v2.4.14/linux/include/asm-arm/arch-sa1100/hardware.h linux/include/asm-arm/arch-sa1100/hardware.h --- v2.4.14/linux/include/asm-arm/arch-sa1100/hardware.h Mon Nov 5 15:55:34 2001 +++ linux/include/asm-arm/arch-sa1100/hardware.h Fri Nov 9 14:11:15 2001 @@ -62,7 +62,7 @@ #ifndef __ASSEMBLY__ #if 0 -# define __REG(x) (*((volatile unsigned long *)io_p2v(x))) +# define __REG(x) (*((volatile u32 *)io_p2v(x))) #else /* * This __REG() version gives the same results as the one above, except @@ -70,12 +70,12 @@ * assembly code for access to contigous registers. It's a shame that gcc * doesn't guess this by itself. */ -typedef struct { volatile unsigned long offset[4096]; } __regbase; +typedef struct { volatile u32 offset[4096]; } __regbase; # define __REGP(x) ((__regbase *)((x)&~4095))->offset[((x)&4095)>>2] # define __REG(x) __REGP(io_p2v(x)) #endif -# define __PREG(x) (io_v2p((unsigned long)&(x))) +# define __PREG(x) (io_v2p((u32)&(x))) #else diff -u --recursive --new-file v2.4.14/linux/include/asm-arm/pci.h linux/include/asm-arm/pci.h --- v2.4.14/linux/include/asm-arm/pci.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-arm/pci.h Fri Nov 9 14:11:15 2001 @@ -165,6 +165,9 @@ return 1; } +/* This isn't fine. */ +#define pci_dac_dma_supported(pci_dev, mask) (0) + /* Return the index of the PCI controller for device PDEV. */ #define pci_controller_num(PDEV) (0) diff -u --recursive --new-file v2.4.14/linux/include/asm-arm/proc-fns.h linux/include/asm-arm/proc-fns.h --- v2.4.14/linux/include/asm-arm/proc-fns.h Tue Mar 6 19:44:35 2001 +++ linux/include/asm-arm/proc-fns.h Fri Nov 9 14:11:15 2001 @@ -60,6 +60,14 @@ # define CPU_NAME arm920 # endif # endif +# ifdef CONFIG_CPU_ARM926T +# ifdef CPU_NAME +# undef MULTI_CPU +# define MULTI_CPU +# else +# define CPU_NAME arm926 +# endif +# endif # ifdef CONFIG_CPU_SA110 # ifdef CPU_NAME # undef MULTI_CPU diff -u --recursive --new-file v2.4.14/linux/include/asm-arm/sizes.h linux/include/asm-arm/sizes.h --- v2.4.14/linux/include/asm-arm/sizes.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/sizes.h Fri Nov 9 14:11:15 2001 @@ -0,0 +1,52 @@ +/* + * 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 + */ +/* DO NOT EDIT!! - this file automatically generated + * from .s file by awk -f s2h.awk + */ +/* Size defintions + * Copyright (C) ARM Limited 1998. All rights reserved. + */ + +#ifndef __sizes_h +#define __sizes_h 1 + +/* handy sizes */ +#define SZ_1K 0x00000400 +#define SZ_4K 0x00001000 +#define SZ_8K 0x00002000 +#define SZ_16K 0x00004000 +#define SZ_64K 0x00010000 +#define SZ_128K 0x00020000 +#define SZ_256K 0x00040000 +#define SZ_512K 0x00080000 + +#define SZ_1M 0x00100000 +#define SZ_2M 0x00200000 +#define SZ_4M 0x00400000 +#define SZ_8M 0x00800000 +#define SZ_16M 0x01000000 +#define SZ_32M 0x02000000 +#define SZ_64M 0x04000000 +#define SZ_128M 0x08000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 + +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 + +#endif + +/* END */ diff -u --recursive --new-file v2.4.14/linux/include/asm-cris/etraxgpio.h linux/include/asm-cris/etraxgpio.h --- v2.4.14/linux/include/asm-cris/etraxgpio.h Wed Jul 25 17:10:25 2001 +++ linux/include/asm-cris/etraxgpio.h Fri Nov 9 14:11:15 2001 @@ -35,4 +35,15 @@ /* SHUTDOWN ioctl */ #define IO_SHUTDOWN 0xD #define IO_GET_PWR_BT 0xE + +/* Bit toggling in driver settings */ +/* bit set in low byte0 is CLK mask (0x00FF), + bit set in byte1 is DATA mask (0xFF00) + msb, data_mask[7:0] , clk_mask[7:0] + */ +#define IO_CFG_WRITE_MODE 0xF +#define IO_CFG_WRITE_MODE_VALUE(msb, data_mask, clk_mask) \ + ( (((msb)&1) << 16) | (((data_mask) &0xFF) << 8) | ((clk_mask) & 0xFF) ) + + #endif diff -u --recursive --new-file v2.4.14/linux/include/asm-cris/pgtable.h linux/include/asm-cris/pgtable.h --- v2.4.14/linux/include/asm-cris/pgtable.h Tue Oct 9 17:06:53 2001 +++ linux/include/asm-cris/pgtable.h Fri Nov 9 14:11:15 2001 @@ -504,4 +504,9 @@ #include <asm-generic/pgtable.h> +/* + * No page table caches to initialise + */ +#define pgtable_cache_init() do { } while (0) + #endif /* _CRIS_PGTABLE_H */ diff -u --recursive --new-file v2.4.14/linux/include/asm-cris/system.h linux/include/asm-cris/system.h --- v2.4.14/linux/include/asm-cris/system.h Tue Oct 9 17:06:53 2001 +++ linux/include/asm-cris/system.h Fri Nov 9 14:11:15 2001 @@ -17,7 +17,7 @@ /* read the CPU version register */ static inline unsigned long rdvr(void) { - unsigned long vr; + unsigned char vr; __asm__ volatile ("move $vr,%0" : "=rm" (vr)); return vr; } diff -u --recursive --new-file v2.4.14/linux/include/asm-cris/timex.h linux/include/asm-cris/timex.h --- v2.4.14/linux/include/asm-cris/timex.h Tue May 1 16:05:00 2001 +++ linux/include/asm-cris/timex.h Fri Nov 9 14:11:15 2001 @@ -8,6 +8,19 @@ #define CLOCK_TICK_RATE 19200 /* Underlying frequency of the HZ timer */ +/* The timer0 values gives ~52.1us resolution (1/19200) but interrupts at HZ*/ +#define TIMER0_FREQ (CLOCK_TICK_RATE) +#define TIMER0_CLKSEL c19k2Hz +#define TIMER0_DIV (TIMER0_FREQ/(HZ)) +/* This is the slow one: */ +/* +#define GET_JIFFIES_USEC() \ + ( (*R_TIMER0_DATA - TIMER0_DIV) * (1000000/HZ)/TIMER0_DIV ) +*/ +/* This is the fast version: */ +extern unsigned short cris_timer0_value_us[TIMER0_DIV+1]; /* in kernel/time.c */ +#define GET_JIFFIES_USEC() (cris_timer0_value_us[*R_TIMER0_DATA]) + /* * We don't have a cycle-counter.. but we do not support SMP anyway where this is * used so it does not matter. diff -u --recursive --new-file v2.4.14/linux/include/asm-cris/uaccess.h linux/include/asm-cris/uaccess.h --- v2.4.14/linux/include/asm-cris/uaccess.h Tue Oct 9 17:06:53 2001 +++ linux/include/asm-cris/uaccess.h Fri Nov 9 14:11:15 2001 @@ -3,6 +3,9 @@ * Hans-Peter Nilsson (hp@axis.com) * * $Log: uaccess.h,v $ + * Revision 1.8 2001/10/29 13:01:48 bjornw + * Removed unused variable tmp2 in strnlen_user + * * Revision 1.7 2001/10/02 12:44:52 hp * Add support for 64-bit put_user/get_user * @@ -1057,7 +1060,7 @@ static inline long strnlen_user(const char *s, long n) { - long res, tmp1, tmp2; + long res, tmp1; if (!access_ok(VERIFY_READ, s, 0)) return 0; diff -u --recursive --new-file v2.4.14/linux/include/asm-cris/unistd.h linux/include/asm-cris/unistd.h --- v2.4.14/linux/include/asm-cris/unistd.h Tue May 1 16:05:00 2001 +++ linux/include/asm-cris/unistd.h Fri Nov 9 14:11:15 2001 @@ -227,6 +227,9 @@ #define __NR_madvise 219 #define __NR_getdents64 220 #define __NR_fcntl64 221 +#define __NR_security 223 /* syscall for security modules */ +#define __NR_gettid 224 +#define __NR_readahead 225 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ #define _syscall0(type,name) \ diff -u --recursive --new-file v2.4.14/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h --- v2.4.14/linux/include/asm-i386/hardirq.h Thu Oct 18 13:47:38 2001 +++ linux/include/asm-i386/hardirq.h Fri Nov 9 14:55:32 2001 @@ -68,7 +68,7 @@ ++local_irq_count(cpu); while (test_bit(0,&global_irq_lock)) { - /* nothing */; + cpu_relax(); } } diff -u --recursive --new-file v2.4.14/linux/include/asm-i386/keyboard.h linux/include/asm-i386/keyboard.h --- v2.4.14/linux/include/asm-i386/keyboard.h Thu Oct 18 13:48:29 2001 +++ linux/include/asm-i386/keyboard.h Fri Nov 9 15:01:30 2001 @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/kd.h> +#include <linux/pm.h> #include <asm/io.h> #define KEYBOARD_IRQ 1 @@ -28,7 +29,8 @@ extern char pckbd_unexpected_up(unsigned char keycode); extern void pckbd_leds(unsigned char leds); extern void pckbd_init_hw(void); -extern void pckbd_pm_resume(void); +extern int pckbd_pm_resume(struct pm_dev *, pm_request_t, void *); +extern pm_callback pm_kbd_request_override; extern unsigned char pckbd_sysrq_xlate[128]; #define kbd_setkeycode pckbd_setkeycode diff -u --recursive --new-file v2.4.14/linux/include/asm-i386/mpspec.h linux/include/asm-i386/mpspec.h --- v2.4.14/linux/include/asm-i386/mpspec.h Tue Oct 9 17:06:53 2001 +++ linux/include/asm-i386/mpspec.h Fri Nov 9 14:47:04 2001 @@ -16,7 +16,13 @@ /* * a maximum of 16 APICs with the current APIC ID architecture. */ +#ifdef CONFIG_MULTIQUAD +#define MAX_APICS 256 +#else /* !CONFIG_MULTIQUAD */ #define MAX_APICS 16 +#endif /* CONFIG_MULTIQUAD */ + +#define MAX_MPC_ENTRY 1024 struct intel_mp_floating { @@ -55,6 +61,7 @@ #define MP_IOAPIC 2 #define MP_INTSRC 3 #define MP_LINTSRC 4 +#define MP_TRANSLATION 192 /* Used by IBM NUMA-Q to describe node locality */ struct mpc_config_processor { @@ -144,6 +151,27 @@ unsigned char mpc_destapiclint; }; +struct mp_config_oemtable +{ + char oem_signature[4]; +#define MPC_OEM_SIGNATURE "_OEM" + unsigned short oem_length; /* Size of table */ + char oem_rev; /* 0x01 */ + char oem_checksum; + char mpc_oem[8]; +}; + +struct mpc_config_translation +{ + unsigned char mpc_type; + unsigned char trans_len; + unsigned char trans_type; + unsigned char trans_quad; + unsigned char trans_global; + unsigned char trans_local; + unsigned short trans_reserved; +}; + /* * Default configurations * @@ -156,7 +184,12 @@ * 7 2 CPU MCA+PCI */ +#ifdef CONFIG_MULTIQUAD +#define MAX_IRQ_SOURCES 512 +#else /* !CONFIG_MULTIQUAD */ #define MAX_IRQ_SOURCES 256 +#endif /* CONFIG_MULTIQUAD */ + #define MAX_MP_BUSSES 32 enum mp_bustype { MP_BUS_ISA = 1, diff -u --recursive --new-file v2.4.14/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h --- v2.4.14/linux/include/asm-i386/pci.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-i386/pci.h Fri Nov 9 14:55:40 2001 @@ -21,6 +21,8 @@ void pcibios_set_master(struct pci_dev *dev); void pcibios_penalize_isa_irq(int irq); +struct irq_routing_table *pcibios_get_irq_routing_table(void); +int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq); /* Dynamic DMA mapping stuff. * i386 has everything mapped statically. @@ -72,6 +74,7 @@ { if (direction == PCI_DMA_NONE) BUG(); + flush_write_buffers(); return virt_to_bus(ptr); } @@ -133,22 +136,23 @@ if (direction == PCI_DMA_NONE) BUG(); - - /* - * temporary 2.4 hack - */ - for (i = 0; i < nents; i++ ) { - if (sg[i].address && sg[i].page) - BUG(); - else if (!sg[i].address && !sg[i].page) - BUG(); - - if (sg[i].address) - sg[i].dma_address = virt_to_bus(sg[i].address); - else - sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset; - } - + + /* + * temporary 2.4 hack + */ + for (i = 0; i < nents; i++ ) { + if (sg[i].address && sg[i].page) + BUG(); + else if (!sg[i].address && !sg[i].page) + BUG(); + + if (sg[i].address) + sg[i].dma_address = virt_to_bus(sg[i].address); + else + sg[i].dma_address = page_to_bus(sg[i].page) + sg[i].offset; + } + + flush_write_buffers(); return nents; } @@ -179,7 +183,7 @@ { if (direction == PCI_DMA_NONE) BUG(); - /* Nothing to do */ + flush_write_buffers(); } /* Make physical memory consistent for a set of streaming @@ -194,7 +198,7 @@ { if (direction == PCI_DMA_NONE) BUG(); - /* Nothing to do */ + flush_write_buffers(); } /* Return whether the given PCI device DMA address mask can @@ -242,7 +246,7 @@ static __inline__ void pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) { - /* Nothing to do. */ + flush_write_buffers(); } /* These macros should be used after a pci_map_sg call has been done diff -u --recursive --new-file v2.4.14/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v2.4.14/linux/include/asm-i386/system.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-i386/system.h Fri Nov 9 14:51:21 2001 @@ -3,6 +3,7 @@ #include <linux/config.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/segment.h> #include <linux/bitops.h> /* for LOCK_PREFIX */ @@ -349,6 +350,10 @@ void disable_hlt(void); void enable_hlt(void); +extern unsigned long dmi_broken; extern int is_sony_vaio_laptop; + +#define BROKEN_ACPI_Sx 0x0001 +#define BROKEN_INIT_AFTER_S1 0x0002 #endif diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/acpi-ext.h linux/include/asm-ia64/acpi-ext.h --- v2.4.14/linux/include/asm-ia64/acpi-ext.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/acpi-ext.h Fri Nov 9 14:26:17 2001 @@ -9,7 +9,7 @@ * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 2000 Intel Corp. - * Copyright (C) 2000 J.I. Lee <jung-ik.lee@intel.com> + * Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com> * ACPI 2.0 specification */ @@ -189,9 +189,16 @@ u32 global_vector; } acpi20_entry_platform_src_t; +/* constants for interrupt routing API for device drivers */ +#define ACPI20_ENTRY_PIS_PMI 1 +#define ACPI20_ENTRY_PIS_INIT 2 +#define ACPI20_ENTRY_PIS_CPEI 3 +#define ACPI_MAX_PLATFORM_IRQS 4 + extern int acpi20_parse(acpi20_rsdp_t *); extern int acpi_parse(acpi_rsdp_t *); extern const char *acpi_get_sysname (void); +extern int acpi_request_vector(u32 int_type); extern void (*acpi_idle) (void); /* power-management idle function, if any */ #pragma pack() diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/ia32.h linux/include/asm-ia64/ia32.h --- v2.4.14/linux/include/asm-ia64/ia32.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/ia32.h Fri Nov 9 14:26:17 2001 @@ -12,31 +12,40 @@ */ /* 32bit compatibility types */ -typedef unsigned int __kernel_size_t32; -typedef int __kernel_ssize_t32; -typedef int __kernel_ptrdiff_t32; -typedef int __kernel_time_t32; -typedef int __kernel_clock_t32; -typedef int __kernel_pid_t32; -typedef unsigned short __kernel_ipc_pid_t32; -typedef unsigned short __kernel_uid_t32; -typedef unsigned short __kernel_gid_t32; -typedef unsigned short __kernel_dev_t32; -typedef unsigned int __kernel_ino_t32; -typedef unsigned short __kernel_mode_t32; -typedef unsigned short __kernel_umode_t32; -typedef short __kernel_nlink_t32; -typedef int __kernel_daddr_t32; -typedef int __kernel_off_t32; -typedef unsigned int __kernel_caddr_t32; -typedef long __kernel_loff_t32; -typedef __kernel_fsid_t __kernel_fsid_t32; +typedef unsigned int __kernel_size_t32; +typedef int __kernel_ssize_t32; +typedef int __kernel_ptrdiff_t32; +typedef int __kernel_time_t32; +typedef int __kernel_clock_t32; +typedef int __kernel_pid_t32; +typedef unsigned short __kernel_ipc_pid_t32; +typedef unsigned short __kernel_uid_t32; +typedef unsigned int __kernel_uid32_t32; +typedef unsigned short __kernel_gid_t32; +typedef unsigned int __kernel_gid32_t32; +typedef unsigned short __kernel_dev_t32; +typedef unsigned int __kernel_ino_t32; +typedef unsigned short __kernel_mode_t32; +typedef unsigned short __kernel_umode_t32; +typedef short __kernel_nlink_t32; +typedef int __kernel_daddr_t32; +typedef int __kernel_off_t32; +typedef unsigned int __kernel_caddr_t32; +typedef long __kernel_loff_t32; +typedef __kernel_fsid_t __kernel_fsid_t32; #define IA32_PAGE_SHIFT 12 /* 4KB pages */ -#define IA32_PAGE_SIZE (1ULL << IA32_PAGE_SHIFT) +#define IA32_PAGE_SIZE (1UL << IA32_PAGE_SHIFT) +#define IA32_PAGE_MASK (~(IA32_PAGE_SIZE - 1)) +#define IA32_PAGE_ALIGN(addr) (((addr) + IA32_PAGE_SIZE - 1) & IA32_PAGE_MASK) #define IA32_CLOCKS_PER_SEC 100 /* Cast in stone for IA32 Linux */ #define IA32_TICK(tick) ((unsigned long long)(tick) * IA32_CLOCKS_PER_SEC / CLOCKS_PER_SEC) +struct timespec32 { + int tv_sec; + int tv_nsec; +}; + /* fcntl.h */ struct flock32 { short l_type; @@ -46,6 +55,9 @@ __kernel_pid_t32 l_pid; }; +#define F_GETLK64 12 +#define F_SETLK64 13 +#define F_SETLKW64 14 /* sigcontext.h */ /* @@ -103,13 +115,19 @@ #define _IA32_NSIG_BPW 32 #define _IA32_NSIG_WORDS (_IA32_NSIG / _IA32_NSIG_BPW) +#define IA32_SET_SA_HANDLER(ka,handler,restorer) \ + ((ka)->sa.sa_handler = (__sighandler_t) \ + (((unsigned long)(restorer) << 32) \ + | ((handler) & 0xffffffff))) +#define IA32_SA_HANDLER(ka) ((unsigned long) (ka)->sa.sa_handler & 0xffffffff) +#define IA32_SA_RESTORER(ka) ((unsigned long) (ka)->sa.sa_handler >> 32) + typedef struct { unsigned int sig[_IA32_NSIG_WORDS]; } sigset32_t; struct sigaction32 { - unsigned int sa_handler; /* Really a pointer, but need to deal - with 32 bits */ + unsigned int sa_handler; /* Really a pointer, but need to deal with 32 bits */ unsigned int sa_flags; unsigned int sa_restorer; /* Another 32 bit pointer */ sigset32_t sa_mask; /* A 32 bit mask */ @@ -162,6 +180,31 @@ unsigned int __unused5; }; +struct stat64 { + unsigned short st_dev; + unsigned char __pad0[10]; + unsigned int __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned short st_rdev; + unsigned char __pad3[10]; + unsigned int st_size_lo; + unsigned int st_size_hi; + unsigned int st_blksize; + unsigned int st_blocks; /* Number 512-byte blocks allocated. */ + unsigned int __pad4; /* future possible st_blocks high bits */ + unsigned int st_atime; + unsigned int __pad5; + unsigned int st_mtime; + unsigned int __pad6; + unsigned int st_ctime; + unsigned int __pad7; /* will be high 32 bits of ctime someday */ + unsigned int st_ino_lo; + unsigned int st_ino_hi; +}; + struct statfs32 { int f_type; int f_bsize; @@ -229,6 +272,19 @@ } _sifields; } siginfo_t32; +struct linux32_dirent { + u32 d_ino; + u32 d_off; + u16 d_reclen; + char d_name[256]; +}; + +struct old_linux32_dirent { + u32 d_ino; + u32 d_offset; + u16 d_namlen; + char d_name[1]; +}; /* * IA-32 ELF specific definitions for IA-64. @@ -252,7 +308,7 @@ #define ELF_ARCH EM_386 #define IA32_PAGE_OFFSET 0xc0000000 -#define IA32_STACK_TOP ((IA32_PAGE_OFFSET/3) * 2) +#define IA32_STACK_TOP IA32_PAGE_OFFSET /* * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can @@ -322,6 +378,10 @@ #define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) #define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3)) +#define IA32_SEGSEL_RPL (0x3 << 0) +#define IA32_SEGSEL_TI (0x1 << 2) +#define IA32_SEGSEL_INDEX_SHIFT 3 + #define IA32_SEG_BASE 16 #define IA32_SEG_TYPE 40 #define IA32_SEG_SYS 44 @@ -377,7 +437,7 @@ */ #define IA32_FSR_DEFAULT 0x55550000 /* set all tag bits */ -#define IA32_FCR_DEFAULT 0x17800000037fULL /* extended precision, all masks */ +#define IA32_FCR_DEFAULT 0x17800000037fUL /* extended precision, all masks */ #define IA32_PTRACE_GETREGS 12 #define IA32_PTRACE_SETREGS 13 @@ -421,6 +481,9 @@ extern void ia32_init_addr_space (struct pt_regs *regs); extern int ia32_setup_arg_pages (struct linux_binprm *bprm); extern int ia32_exception (struct pt_regs *regs, unsigned long isr); +extern int ia32_intercept (struct pt_regs *regs, unsigned long isr); +extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t); +extern void ia32_load_segment_descriptors (struct task_struct *task); #endif /* !CONFIG_IA32_SUPPORT */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/io.h linux/include/asm-ia64/io.h --- v2.4.14/linux/include/asm-ia64/io.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/io.h Fri Nov 9 14:26:17 2001 @@ -14,7 +14,7 @@ * mistake somewhere. * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com> * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> */ @@ -25,7 +25,12 @@ #define __IA64_UNCACHED_OFFSET 0xc000000000000000 /* region 6 */ -#define IO_SPACE_LIMIT 0xffff +/* + * The legacy I/O space defined by the ia64 architecture supports only 65536 ports, but + * large machines may have multiple other I/O spaces so we can't place any a priori limit + * on IO_SPACE_LIMIT. These additional spaces are described in ACPI. + */ +#define IO_SPACE_LIMIT 0xffffffffffffffffUL # ifdef __KERNEL__ @@ -43,7 +48,7 @@ } static inline void* -phys_to_virt(unsigned long address) +phys_to_virt (unsigned long address) { return (void *) (address + PAGE_OFFSET); } @@ -54,6 +59,7 @@ */ #define bus_to_virt phys_to_virt #define virt_to_bus virt_to_phys +#define page_to_bus page_to_phys # endif /* KERNEL */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/iosapic.h linux/include/asm-ia64/iosapic.h --- v2.4.14/linux/include/asm-ia64/iosapic.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/iosapic.h Fri Nov 9 14:26:17 2001 @@ -53,8 +53,17 @@ extern void __init iosapic_init (unsigned long address, unsigned int base_irq, int pcat_compat); +extern int iosapic_register_irq (u32 global_vector, unsigned long polarity, + unsigned long edge_triggered, u32 base_irq, + char *iosapic_address); extern void iosapic_register_legacy_irq (unsigned long irq, unsigned long pin, unsigned long polarity, unsigned long trigger); +extern int iosapic_register_platform_irq (u32 int_type, u32 global_vector, u32 iosapic_vector, + u16 eid, u16 id, unsigned long polarity, + unsigned long edge_triggered, u32 base_irq, + char *iosapic_address); +extern unsigned int iosapic_version (char *addr); + extern void iosapic_pci_fixup (int); # endif /* !__ASSEMBLY__ */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/ipc.h linux/include/asm-ia64/ipc.h --- v2.4.14/linux/include/asm-ia64/ipc.h Sun Feb 6 18:42:40 2000 +++ linux/include/asm-ia64/ipc.h Wed Dec 31 16:00:00 1969 @@ -1,31 +0,0 @@ -#ifndef __i386_IPC_H__ -#define __i386_IPC_H__ - -/* - * These are used to wrap system calls on x86. - * - * See arch/i386/kernel/sys_i386.c for ugly details.. - */ -struct ipc_kludge { - struct msgbuf *msgp; - long msgtyp; -}; - -#define SEMOP 1 -#define SEMGET 2 -#define SEMCTL 3 -#define MSGSND 11 -#define MSGRCV 12 -#define MSGGET 13 -#define MSGCTL 14 -#define SHMAT 21 -#define SHMDT 22 -#define SHMGET 23 -#define SHMCTL 24 - -/* Used by the DIPC package, try and avoid reusing it */ -#define DIPC 25 - -#define IPCCALL(version,op) ((version)<<16 | (op)) - -#endif diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/keyboard.h linux/include/asm-ia64/keyboard.h --- v2.4.14/linux/include/asm-ia64/keyboard.h Fri Apr 21 16:38:40 2000 +++ linux/include/asm-ia64/keyboard.h Fri Nov 9 14:26:17 2001 @@ -2,16 +2,16 @@ #define _ASM_IA64_KEYBOARD_H /* - * This file contains the ia-64 architecture specific keyboard - * definitions. + * This file contains the ia64 architecture specific keyboard definitions. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ # ifdef __KERNEL__ #include <linux/irq.h> +#include <linux/kd.h> #define KEYBOARD_IRQ isa_irq_to_vector(1) #define DISABLE_KBD_DURING_INTERRUPTS 0 @@ -38,6 +38,7 @@ #define INIT_KBD #define SYSRQ_KEY 0x54 +#define E1_PAUSE 119 /* PAUSE key */ /* resource allocation */ #define kbd_request_region() diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/kregs.h linux/include/asm-ia64/kregs.h --- v2.4.14/linux/include/asm-ia64/kregs.h Thu Apr 5 12:51:47 2001 +++ linux/include/asm-ia64/kregs.h Fri Nov 9 14:26:17 2001 @@ -13,6 +13,7 @@ * Kernel registers: */ #define IA64_KR_IO_BASE 0 /* ar.k0: legacy I/O base address */ +#define IA64_KR_TSSD 1 /* ar.k1: IVE uses this as the TSSD */ #define IA64_KR_CURRENT_STACK 4 /* ar.k4: what's mapped in IA64_TR_CURRENT_STACK */ #define IA64_KR_FPU_OWNER 5 /* ar.k5: fpu-owner (UP only, at the moment) */ #define IA64_KR_CURRENT 6 /* ar.k6: "current" task pointer */ @@ -28,6 +29,6 @@ #define IA64_TR_KERNEL 0 /* itr0, dtr0: maps kernel image (code & data) */ #define IA64_TR_PALCODE 1 /* itr1: maps PALcode as required by EFI */ #define IA64_TR_PERCPU_DATA 1 /* dtr1: percpu data */ -#define IA64_TR_CURRENT_STACK 2 /* dtr2: maps kernel memory & register stacks */ +#define IA64_TR_CURRENT_STACK 2 /* dtr2: maps kernel's memory- & register-stacks */ #endif /* _ASM_IA64_kREGS_H */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/machvec.h linux/include/asm-ia64/machvec.h --- v2.4.14/linux/include/asm-ia64/machvec.h Thu Apr 5 12:51:47 2001 +++ linux/include/asm-ia64/machvec.h Fri Nov 9 14:26:17 2001 @@ -1,11 +1,11 @@ /* * Machine vector for IA-64. - * + * * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com> * Copyright (C) Vijay Chander <vijay@engr.sgi.com> * Copyright (C) 1999-2001 Hewlett-Packard Co. - * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> */ #ifndef _ASM_IA64_MACHVEC_H #define _ASM_IA64_MACHVEC_H @@ -28,6 +28,7 @@ typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *); typedef void ia64_mv_log_print_t (void); typedef void ia64_mv_send_ipi_t (int, int, int, int); +typedef void ia64_mv_global_tlb_purge_t (unsigned long, unsigned long, unsigned long); typedef struct irq_desc *ia64_mv_irq_desc (unsigned int); typedef u8 ia64_mv_irq_to_vector (u8); typedef unsigned int ia64_mv_local_vector_to_irq (u8 vector); @@ -67,6 +68,8 @@ # include <asm/machvec_dig.h> # elif defined (CONFIG_IA64_SGI_SN1) # include <asm/machvec_sn1.h> +# elif defined (CONFIG_IA64_SGI_SN2) +# include <asm/machvec_sn2.h> # elif defined (CONFIG_IA64_GENERIC) # ifdef MACHVEC_PLATFORM_HEADER @@ -82,6 +85,7 @@ # define platform_log_print ia64_mv.log_print # define platform_pci_fixup ia64_mv.pci_fixup # define platform_send_ipi ia64_mv.send_ipi +# define platform_global_tlb_purge ia64_mv.global_tlb_purge # define platform_pci_dma_init ia64_mv.dma_init # define platform_pci_alloc_consistent ia64_mv.alloc_consistent # define platform_pci_free_consistent ia64_mv.free_consistent @@ -147,6 +151,7 @@ platform_cmci_handler, \ platform_log_print, \ platform_send_ipi, \ + platform_global_tlb_purge, \ platform_pci_dma_init, \ platform_pci_alloc_consistent, \ platform_pci_free_consistent, \ @@ -216,6 +221,9 @@ #endif #ifndef platform_send_ipi # define platform_send_ipi ia64_send_ipi /* default to architected version */ +#endif +#ifndef platform_global_tlb_purge +# define platform_global_tlb_purge ia64_global_tlb_purge /* default to architected version */ #endif #ifndef platform_pci_dma_init # define platform_pci_dma_init swiotlb_init diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/machvec_sn1.h linux/include/asm-ia64/machvec_sn1.h --- v2.4.14/linux/include/asm-ia64/machvec_sn1.h Thu Apr 5 12:51:47 2001 +++ linux/include/asm-ia64/machvec_sn1.h Fri Nov 9 14:26:17 2001 @@ -5,6 +5,7 @@ extern ia64_mv_irq_init_t sn1_irq_init; extern ia64_mv_map_nr_t sn1_map_nr; extern ia64_mv_send_ipi_t sn1_send_IPI; +extern ia64_mv_global_tlb_purge_t sn1_global_tlb_purge; extern ia64_mv_pci_fixup_t sn1_pci_fixup; extern ia64_mv_inb_t sn1_inb; extern ia64_mv_inw_t sn1_inw; @@ -34,6 +35,7 @@ #define platform_irq_init sn1_irq_init #define platform_map_nr sn1_map_nr #define platform_send_ipi sn1_send_IPI +#define platform_global_tlb_purge sn1_global_tlb_purge #define platform_pci_fixup sn1_pci_fixup #define platform_inb sn1_inb #define platform_inw sn1_inw diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/mca.h linux/include/asm-ia64/mca.h --- v2.4.14/linux/include/asm-ia64/mca.h Thu Apr 5 12:51:47 2001 +++ linux/include/asm-ia64/mca.h Fri Nov 9 14:26:17 2001 @@ -8,7 +8,7 @@ */ /* XXX use this temporary define for MP systems trying to INIT */ -#define SAL_MPINIT_WORKAROUND +#undef SAL_MPINIT_WORKAROUND #ifndef _ASM_IA64_MCA_H #define _ASM_IA64_MCA_H @@ -61,8 +61,6 @@ IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1 }; -#define IA64_MAXCPUS 64 /* Need to do something about this */ - /* Information maintained by the MC infrastructure */ typedef struct ia64_mc_info_s { u64 imi_mca_handler; @@ -71,7 +69,7 @@ size_t imi_monarch_init_handler_size; u64 imi_slave_init_handler; size_t imi_slave_init_handler_size; - u8 imi_rendez_checkin[IA64_MAXCPUS]; + u8 imi_rendez_checkin[NR_CPUS]; } ia64_mc_info_t; @@ -128,18 +126,22 @@ extern void ia64_mca_rendez_int_handler(int,void *,struct pt_regs *); extern void ia64_mca_wakeup_int_handler(int,void *,struct pt_regs *); extern void ia64_mca_cmc_int_handler(int,void *,struct pt_regs *); -extern void ia64_log_print(int,int,prfunc_t); +extern void ia64_mca_cpe_int_handler(int,void *,struct pt_regs *); +extern void ia64_log_print(int,prfunc_t); +extern void ia64_mca_cmc_vector_setup(void); +extern void ia64_mca_check_errors( void ); +extern u64 ia64_log_get(int, prfunc_t); #define PLATFORM_CALL(fn, args) printk("Platform call TBD\n") #undef MCA_TEST -#define IA64_MCA_DEBUG_INFO 1 +#undef IA64_MCA_DEBUG_INFO #if defined(IA64_MCA_DEBUG_INFO) -# define IA64_MCA_DEBUG printk +# define IA64_MCA_DEBUG(fmt...) printk(fmt) #else -# define IA64_MCA_DEBUG +# define IA64_MCA_DEBUG(fmt...) #endif #endif /* !__ASSEMBLY__ */ #endif /* _ASM_IA64_MCA_H */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/mca_asm.h linux/include/asm-ia64/mca_asm.h --- v2.4.14/linux/include/asm-ia64/mca_asm.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/mca_asm.h Fri Nov 9 14:26:17 2001 @@ -41,7 +41,7 @@ */ #define DATA_PA_TO_VA(addr,temp) \ mov temp = 0x7 ;; \ - dep addr = temp, addr, 61, 3; + dep addr = temp, addr, 61, 3;; /* * This macro jumps to the instruction at the given virtual address @@ -74,6 +74,7 @@ \ mov ar.rsc = 0 ; \ ;; \ + srlz.d; \ mov temp2 = ar.bspstore; \ ;; \ DATA_VA_TO_PA(temp2); \ @@ -102,6 +103,8 @@ ;; \ dep temp1 = 0, temp1, PSR_I, 1; \ ;; \ + dep temp1 = 0, temp1, PSR_IC, 1; \ + ;; \ movl temp2 = start_addr; \ mov cr.ipsr = temp1; \ ;; \ @@ -145,6 +148,8 @@ #define VIRTUAL_MODE_ENTER(temp1, temp2, start_addr, old_psr) \ mov temp2 = psr; \ ;; \ + mov old_psr = temp2; \ + ;; \ dep temp2 = 0, temp2, PSR_IC, 2; \ ;; \ mov psr.l = temp2; \ @@ -163,7 +168,7 @@ ;; \ mov temp1 = old_psr; \ ;; \ - mov temp2 = 1 \ + mov temp2 = 1; \ ;; \ dep temp1 = temp2, temp1, PSR_I, 1; \ ;; \ @@ -182,8 +187,10 @@ movl temp2 = start_addr; \ ;; \ mov cr.iip = temp2; \ + ;; \ DATA_PA_TO_VA(sp, temp1); \ DATA_PA_TO_VA(gp, temp2); \ + srlz.i; \ ;; \ nop 1; \ nop 2; \ @@ -246,7 +253,7 @@ mov ar.bspstore=p_bspstore;; \ mov temp=ar.bsp;; \ sub temp=temp,p_bspstore;; \ - st8 [p_stackframe]=temp,8 + st8 [p_stackframe]=temp,8;; /* * rse_return_context @@ -278,28 +285,20 @@ mov ar.rnat=temp;; \ add p_stackframe=-rse_rnat_offset+rse_pfs_offset,p_stackframe;; \ ld8 temp=[p_stackframe];; \ - mov ar.pfs=temp; \ + mov ar.pfs=temp;; \ add p_stackframe=-rse_pfs_offset+rse_ifs_offset,p_stackframe;; \ ld8 temp=[p_stackframe];; \ - mov cr.ifs=temp; \ + mov cr.ifs=temp;; \ add p_stackframe=-rse_ifs_offset+rse_rsc_offset,p_stackframe;; \ ld8 temp=[p_stackframe];; \ mov ar.rsc=temp ; \ - add p_stackframe=-rse_rsc_offset,p_stackframe; \ - mov temp=cr.ipsr;; \ - st8 [p_stackframe]=temp,8; \ - mov temp=cr.iip;; \ - st8 [p_stackframe]=temp,-8; \ mov temp=psr;; \ or temp=temp,psr_mask_reg;; \ mov cr.ipsr=temp;; \ mov temp=ip;; \ add temp=0x30,temp;; \ mov cr.iip=temp;; \ - rfi;; \ - ld8 temp=[p_stackframe],8;; \ - mov cr.ipsr=temp;; \ - ld8 temp=[p_stackframe];; \ - mov cr.iip=temp + srlz.i;; \ + rfi;; #endif /* _ASM_IA64_MCA_ASM_H */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/mmu_context.h linux/include/asm-ia64/mmu_context.h --- v2.4.14/linux/include/asm-ia64/mmu_context.h Thu Apr 5 12:51:47 2001 +++ linux/include/asm-ia64/mmu_context.h Fri Nov 9 14:26:17 2001 @@ -60,7 +60,6 @@ static inline void get_mmu_context (struct mm_struct *mm) { - /* check if our ASN is of an older generation and thus invalid: */ if (mm->context == 0) get_new_mmu_context(mm); } diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/module.h linux/include/asm-ia64/module.h --- v2.4.14/linux/include/asm-ia64/module.h Tue Oct 9 17:06:53 2001 +++ linux/include/asm-ia64/module.h Fri Nov 9 14:26:17 2001 @@ -14,13 +14,6 @@ #define module_map(x) vmalloc(x) #define module_unmap(x) ia64_module_unmap(x) #define module_arch_init(x) ia64_module_init(x) -#define arch_init_modules(x) { static struct archdata archdata; \ - register char *kernel_gp asm ("gp");\ - archdata.gp = kernel_gp; \ - kernel_module.archdata_start = (const char *) &archdata; \ - kernel_module.archdata_end = (const char *) (&archdata + 1); \ - } - /* * This must match in size and layout the data created by @@ -34,12 +27,23 @@ const char *gp; }; +static inline void +arch_init_modules (struct module *kmod) +{ + static struct archdata archdata; + register char *kernel_gp asm ("gp"); + + archdata.gp = kernel_gp; + kmod->archdata_start = (const char *) &archdata; + kmod->archdata_end = (const char *) (&archdata + 1); +} + /* * functions to add/remove a modules unwind info when * it is loaded or unloaded. */ static inline int -ia64_module_init(struct module *mod) +ia64_module_init (struct module *mod) { struct archdata *archdata; @@ -51,28 +55,23 @@ * Make sure the unwind pointers are sane. */ - if (archdata->unw_table) - { + if (archdata->unw_table) { printk(KERN_ERR "module_arch_init: archdata->unw_table must be zero.\n"); return 1; } - if (!mod_bound(archdata->gp, 0, mod)) - { + if (!mod_bound(archdata->gp, 0, mod)) { printk(KERN_ERR "module_arch_init: archdata->gp out of bounds.\n"); return 1; } - if (!mod_bound(archdata->unw_start, 0, mod)) - { + if (!mod_bound(archdata->unw_start, 0, mod)) { printk(KERN_ERR "module_arch_init: archdata->unw_start out of bounds.\n"); return 1; } - if (!mod_bound(archdata->unw_end, 0, mod)) - { + if (!mod_bound(archdata->unw_end, 0, mod)) { printk(KERN_ERR "module_arch_init: archdata->unw_end out of bounds.\n"); return 1; } - if (!mod_bound(archdata->segment_base, 0, mod)) - { + if (!mod_bound(archdata->segment_base, 0, mod)) { printk(KERN_ERR "module_arch_init: archdata->unw_table out of bounds.\n"); return 1; } @@ -88,7 +87,7 @@ } static inline void -ia64_module_unmap(void * addr) +ia64_module_unmap (void * addr) { struct module *mod = (struct module *) addr; struct archdata *archdata; @@ -96,8 +95,7 @@ /* * Before freeing the module memory remove the unwind table entry */ - if (mod_member_present(mod, archdata_start) && mod->archdata_start) - { + if (mod_member_present(mod, archdata_start) && mod->archdata_start) { archdata = (struct archdata *)(mod->archdata_start); if (archdata->unw_table != NULL) diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/msgbuf.h linux/include/asm-ia64/msgbuf.h --- v2.4.14/linux/include/asm-ia64/msgbuf.h Sun Feb 6 18:42:40 2000 +++ linux/include/asm-ia64/msgbuf.h Fri Nov 9 14:26:17 2001 @@ -1,7 +1,7 @@ #ifndef _ASM_IA64_MSGBUF_H #define _ASM_IA64_MSGBUF_H -/* +/* * The msqid64_ds structure for IA-64 architecture. * Note extra padding because this structure is passed back and forth * between kernel and user space. diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/namei.h linux/include/asm-ia64/namei.h --- v2.4.14/linux/include/asm-ia64/namei.h Sun Apr 2 15:49:07 2000 +++ linux/include/asm-ia64/namei.h Fri Nov 9 14:26:17 2001 @@ -2,15 +2,24 @@ #define _ASM_IA64_NAMEI_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> */ -/* - * This dummy routine maybe changed to something useful - * for /usr/gnemul/ emulation stuff. - * Look at asm-sparc/namei.h for details. - */ -#define __emul_prefix() NULL +#include <asm/ptrace.h> +#include <asm/system.h> + +#define EMUL_PREFIX_LINUX_IA32 "emul/ia32-linux/" + +static inline char * +__emul_prefix (void) +{ + switch (current->personality) { + case PER_LINUX32: + return EMUL_PREFIX_LINUX_IA32; + default: + return NULL; + } +} #endif /* _ASM_IA64_NAMEI_H */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/offsets.h linux/include/asm-ia64/offsets.h --- v2.4.14/linux/include/asm-ia64/offsets.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/offsets.h Fri Nov 9 14:26:17 2001 @@ -8,23 +8,22 @@ */ #define PT_PTRACED_BIT 0 #define PT_TRACESYS_BIT 1 -#define IA64_TASK_SIZE 3904 /* 0xf40 */ +#define IA64_TASK_SIZE 3408 /* 0xd50 */ #define IA64_PT_REGS_SIZE 400 /* 0x190 */ #define IA64_SWITCH_STACK_SIZE 560 /* 0x230 */ #define IA64_SIGINFO_SIZE 128 /* 0x80 */ #define IA64_CPU_SIZE 16384 /* 0x4000 */ -#define SIGFRAME_SIZE 2832 /* 0xb10 */ +#define SIGFRAME_SIZE 2816 /* 0xb00 */ #define UNW_FRAME_INFO_SIZE 448 /* 0x1c0 */ #define IA64_TASK_PTRACE_OFFSET 48 /* 0x30 */ #define IA64_TASK_SIGPENDING_OFFSET 16 /* 0x10 */ #define IA64_TASK_NEED_RESCHED_OFFSET 40 /* 0x28 */ #define IA64_TASK_PROCESSOR_OFFSET 100 /* 0x64 */ -#define IA64_TASK_THREAD_OFFSET 1456 /* 0x5b0 */ -#define IA64_TASK_THREAD_KSP_OFFSET 1456 /* 0x5b0 */ -#define IA64_TASK_THREAD_SIGMASK_OFFSET 1568 /* 0x620 */ -#define IA64_TASK_PFM_NOTIFY_OFFSET 2088 /* 0x828 */ -#define IA64_TASK_PID_OFFSET 196 /* 0xc4 */ +#define IA64_TASK_THREAD_OFFSET 976 /* 0x3d0 */ +#define IA64_TASK_THREAD_KSP_OFFSET 976 /* 0x3d0 */ +#define IA64_TASK_PFM_MUST_BLOCK_OFFSET 1600 /* 0x640 */ +#define IA64_TASK_PID_OFFSET 220 /* 0xdc */ #define IA64_TASK_MM_OFFSET 88 /* 0x58 */ #define IA64_PT_REGS_CR_IPSR_OFFSET 0 /* 0x0 */ #define IA64_PT_REGS_CR_IIP_OFFSET 8 /* 0x8 */ @@ -126,12 +125,13 @@ #define IA64_SIGCONTEXT_FR6_OFFSET 560 /* 0x230 */ #define IA64_SIGCONTEXT_PR_OFFSET 128 /* 0x80 */ #define IA64_SIGCONTEXT_R12_OFFSET 296 /* 0x128 */ +#define IA64_SIGCONTEXT_RBS_BASE_OFFSET 2512 /* 0x9d0 */ +#define IA64_SIGCONTEXT_LOADRS_OFFSET 2520 /* 0x9d8 */ #define IA64_SIGFRAME_ARG0_OFFSET 0 /* 0x0 */ #define IA64_SIGFRAME_ARG1_OFFSET 8 /* 0x8 */ #define IA64_SIGFRAME_ARG2_OFFSET 16 /* 0x10 */ -#define IA64_SIGFRAME_RBS_BASE_OFFSET 24 /* 0x18 */ -#define IA64_SIGFRAME_HANDLER_OFFSET 32 /* 0x20 */ -#define IA64_SIGFRAME_SIGCONTEXT_OFFSET 176 /* 0xb0 */ +#define IA64_SIGFRAME_HANDLER_OFFSET 24 /* 0x18 */ +#define IA64_SIGFRAME_SIGCONTEXT_OFFSET 160 /* 0xa0 */ #define IA64_CLONE_VFORK 16384 /* 0x4000 */ #define IA64_CLONE_VM 256 /* 0x100 */ #define IA64_CPU_IRQ_COUNT_OFFSET 0 /* 0x0 */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/page.h linux/include/asm-ia64/page.h --- v2.4.14/linux/include/asm-ia64/page.h Thu Apr 5 12:51:47 2001 +++ linux/include/asm-ia64/page.h Fri Nov 9 14:26:17 2001 @@ -55,12 +55,15 @@ #ifdef CONFIG_IA64_GENERIC # include <asm/machvec.h> # define virt_to_page(kaddr) (mem_map + platform_map_nr(kaddr)) +# define page_to_phys(page) XXX fix me #elif defined (CONFIG_IA64_SGI_SN1) # ifndef CONFIG_DISCONTIGMEM # define virt_to_page(kaddr) (mem_map + MAP_NR_DENSE(kaddr)) +# define page_to_phys(page) XXX fix me # endif #else # define virt_to_page(kaddr) (mem_map + MAP_NR_DENSE(kaddr)) +# define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) #endif #define VALID_PAGE(page) ((page - mem_map) < max_mapnr) diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/pal.h linux/include/asm-ia64/pal.h --- v2.4.14/linux/include/asm-ia64/pal.h Thu Apr 5 12:51:47 2001 +++ linux/include/asm-ia64/pal.h Fri Nov 9 14:26:17 2001 @@ -7,9 +7,9 @@ * This is based on Intel IA-64 Architecture Software Developer's Manual rev 1.0 * chapter 11 IA-64 Processor Abstraction Layer * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> + * Stephane Eranian <eranian@hpl.hp.com> * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Srinivasa Prasad Thirumalachar <sprasad@sprasad.engr.sgi.com> @@ -17,7 +17,7 @@ * 99/10/01 davidm Make sure we pass zero for reserved parameters. * 00/03/07 davidm Updated pal_cache_flush() to be in sync with PAL v2.6. * 00/03/23 cfleck Modified processor min-state save area to match updated PAL & SAL info - * 00/05/24 eranian Updated to latest PAL spec, fix structures bugs, added + * 00/05/24 eranian Updated to latest PAL spec, fix structures bugs, added * 00/05/25 eranian Support for stack calls, and static physical calls * 00/06/18 eranian Support for stacked physical calls */ @@ -91,9 +91,9 @@ #define PAL_STATUS_UNIMPLEMENTED -1 /* Unimplemented procedure */ #define PAL_STATUS_EINVAL -2 /* Invalid argument */ #define PAL_STATUS_ERROR -3 /* Error */ -#define PAL_STATUS_CACHE_INIT_FAIL -4 /* Could not initialize the +#define PAL_STATUS_CACHE_INIT_FAIL -4 /* Could not initialize the * specified level and type of - * cache without sideeffects + * cache without sideeffects * and "restrict" was 1 */ @@ -189,8 +189,8 @@ #define PAL_CACHE_ATTR_WT 0 /* Write through cache */ #define PAL_CACHE_ATTR_WB 1 /* Write back cache */ -#define PAL_CACHE_ATTR_WT_OR_WB 2 /* Either write thru or write - * back depending on TLB +#define PAL_CACHE_ATTR_WT_OR_WB 2 /* Either write thru or write + * back depending on TLB * memory attributes */ @@ -211,13 +211,13 @@ tagprot_lsb : 6, /* Least -do- */ tagprot_msb : 6, /* Most Sig. tag address - * bit that this + * bit that this * protection covers. */ prot_bits : 6, /* # of protection bits */ method : 4, /* Protection method */ - t_d : 2; /* Indicates which part - * of the cache this + t_d : 2; /* Indicates which part + * of the cache this * protection encoding * applies. */ @@ -239,7 +239,7 @@ */ #define PAL_CACHE_PROT_PART_DATA_TAG 3 /* Data+tag protection (data is * more significant ) - */ + */ #define PAL_CACHE_PROT_PART_MAX 6 @@ -247,7 +247,7 @@ pal_status_t pcpi_status; pal_cache_protection_element_t pcp_info[PAL_CACHE_PROT_PART_MAX]; } pal_cache_protection_info_t; - + /* Processor cache protection method encodings */ #define PAL_CACHE_PROT_METHOD_NONE 0 /* No protection */ @@ -262,41 +262,41 @@ struct { u64 cache_type : 8, /* 7-0 cache type */ level : 8, /* 15-8 level of the - * cache in the + * cache in the * heirarchy. */ way : 8, /* 23-16 way in the set */ part : 8, /* 31-24 part of the - * cache + * cache */ reserved : 32; /* 63-32 is reserved*/ } pclid_info_read; struct { u64 cache_type : 8, /* 7-0 cache type */ level : 8, /* 15-8 level of the - * cache in the + * cache in the * heirarchy. */ way : 8, /* 23-16 way in the set */ part : 8, /* 31-24 part of the - * cache + * cache */ - mesi : 8, /* 39-32 cache line + mesi : 8, /* 39-32 cache line * state */ start : 8, /* 47-40 lsb of data to * invert */ length : 8, /* 55-48 #bits to - * invert + * invert */ trigger : 8; /* 63-56 Trigger error - * by doing a load - * after the write - */ - + * by doing a load + * after the write + */ + } pclid_info_write; } pal_cache_line_id_u_t; @@ -319,11 +319,11 @@ #define PAL_CACHE_LINE_ID_PART_TAG 1 /* Tag */ #define PAL_CACHE_LINE_ID_PART_DATA_PROT 2 /* Data protection */ #define PAL_CACHE_LINE_ID_PART_TAG_PROT 3 /* Tag protection */ -#define PAL_CACHE_LINE_ID_PART_DATA_TAG_PROT 4 /* Data+tag +#define PAL_CACHE_LINE_ID_PART_DATA_TAG_PROT 4 /* Data+tag * protection */ typedef struct pal_cache_line_info_s { - pal_status_t pcli_status; /* Return status of the read cache line + pal_status_t pcli_status; /* Return status of the read cache line * info call. */ u64 pcli_data; /* 64-bit data, tag, protection bits .. */ @@ -351,15 +351,15 @@ #define PAL_MC_INFO_REQ_ADDR 4 /* Requestor address */ #define PAL_MC_INFO_RESP_ADDR 5 /* Responder address */ #define PAL_MC_INFO_TARGET_ADDR 6 /* Target address */ -#define PAL_MC_INFO_IMPL_DEP 7 /* Implementation - * dependent +#define PAL_MC_INFO_IMPL_DEP 7 /* Implementation + * dependent */ typedef struct pal_process_state_info_s { u64 reserved1 : 2, rz : 1, /* PAL_CHECK processor - * rendezvous + * rendezvous * successful. */ @@ -370,13 +370,13 @@ * errors occurred */ - mn : 1, /* Min. state save - * area has been + mn : 1, /* Min. state save + * area has been * registered with PAL */ sy : 1, /* Storage integrity - * synched + * synched */ @@ -389,8 +389,8 @@ hd : 1, /* Non-essential hw * lost (no loss of - * functionality) - * causing the + * functionality) + * causing the * processor to run in * degraded mode. */ @@ -398,9 +398,9 @@ tl : 1, /* 1 => MC occurred * after an instr was * executed but before - * the trap that + * the trap that * resulted from instr - * execution was + * execution was * generated. * (Trap Lost ) */ @@ -410,7 +410,7 @@ */ dy : 1, /* Processor dynamic - * state valid + * state valid */ @@ -441,10 +441,10 @@ * are valid */ gr : 1, /* General registers - * are valid + * are valid * (excl. banked regs) */ - dsize : 16, /* size of dynamic + dsize : 16, /* size of dynamic * state returned * by the processor */ @@ -459,8 +459,8 @@ typedef struct pal_cache_check_info_s { u64 reserved1 : 16, - way : 5, /* Way in which the - * error occurred + way : 5, /* Way in which the + * error occurred */ reserved2 : 1, mc : 1, /* Machine check corrected */ @@ -469,8 +469,8 @@ */ wv : 1, /* Way field valid */ - op : 3, /* Type of cache - * operation that + op : 3, /* Type of cache + * operation that * caused the machine * check. */ @@ -493,7 +493,7 @@ typedef struct pal_tlb_check_info_s { u64 tr_slot : 8, /* Slot# of TR where - * error occurred + * error occurred */ reserved2 : 8, dtr : 1, /* Fail in data TR */ @@ -509,7 +509,7 @@ u64 size : 5, /* Xaction size*/ ib : 1, /* Internal bus error */ eb : 1, /* External bus error */ - cc : 1, /* Error occurred + cc : 1, /* Error occurred * during cache-cache * transfer. */ @@ -518,7 +518,7 @@ tv : 1, /* Targ addr valid */ rp : 1, /* Resp addr valid */ rq : 1, /* Req addr valid */ - bsi : 8, /* Bus error status + bsi : 8, /* Bus error status * info */ mc : 1, /* Machine check corrected */ @@ -601,8 +601,8 @@ #define pmci_bus_external_error pme_bus.eb #define pmci_bus_mc pme_bus.mc -/* - * NOTE: this min_state_save area struct only includes the 1KB +/* + * NOTE: this min_state_save area struct only includes the 1KB * architectural state save area. The other 3 KB is scratch space * for PAL. */ @@ -703,12 +703,12 @@ u64 pbf_disable_bus_addr_err_signal : 1; u64 pbf_disable_bus_data_err_check : 1; } pal_bus_features_s; -} pal_bus_features_u_t; +} pal_bus_features_u_t; extern void pal_bus_features_print (u64); /* Provide information about configurable processor bus features */ -static inline s64 +static inline s64 ia64_pal_bus_get_features (pal_bus_features_u_t *features_avail, pal_bus_features_u_t *features_status, pal_bus_features_u_t *features_control) @@ -721,13 +721,13 @@ features_status->pal_bus_features_val = iprv.v1; if (features_control) features_control->pal_bus_features_val = iprv.v2; - return iprv.status; + return iprv.status; } /* Enables/disables specific processor bus features */ -static inline s64 -ia64_pal_bus_set_features (pal_bus_features_u_t feature_select) -{ +static inline s64 +ia64_pal_bus_set_features (pal_bus_features_u_t feature_select) +{ struct ia64_pal_retval iprv; PAL_CALL_PHYS(iprv, PAL_BUS_SET_FEATURES, feature_select.pal_bus_features_val, 0, 0); return iprv.status; @@ -739,7 +739,7 @@ { struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_CACHE_INFO, cache_level, cache_type, 0); + PAL_CALL(iprv, PAL_CACHE_INFO, cache_level, cache_type, 0); if (iprv.status == 0) { conf->pcci_status = iprv.status; @@ -747,7 +747,7 @@ conf->pcci_info_2.pcci2_data = iprv.v1; conf->pcci_reserved = iprv.v2; } - return iprv.status; + return iprv.status; } @@ -757,7 +757,7 @@ { struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_CACHE_PROT_INFO, cache_level, cache_type, 0); + PAL_CALL(iprv, PAL_CACHE_PROT_INFO, cache_level, cache_type, 0); if (iprv.status == 0) { prot->pcpi_status = iprv.status; @@ -768,106 +768,108 @@ prot->pcp_info[4].pcpi_data = iprv.v2 & 0xffffffff; prot->pcp_info[5].pcpi_data = iprv.v2 >> 32; } - return iprv.status; + return iprv.status; } - + /* * Flush the processor instruction or data caches. *PROGRESS must be * initialized to zero before calling this for the first time.. */ -static inline s64 -ia64_pal_cache_flush (u64 cache_type, u64 invalidate, u64 *progress) -{ +static inline s64 +ia64_pal_cache_flush (u64 cache_type, u64 invalidate, u64 *progress, u64 *vector) +{ struct ia64_pal_retval iprv; - PAL_CALL_IC_OFF(iprv, PAL_CACHE_FLUSH, cache_type, invalidate, *progress); + PAL_CALL_IC_OFF(iprv, PAL_CACHE_FLUSH, cache_type, invalidate, *progress); + if (vector) + *vector = iprv.v0; *progress = iprv.v1; - return iprv.status; + return iprv.status; } /* Initialize the processor controlled caches */ -static inline s64 -ia64_pal_cache_init (u64 level, u64 cache_type, u64 restrict) -{ +static inline s64 +ia64_pal_cache_init (u64 level, u64 cache_type, u64 restrict) +{ struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_CACHE_INIT, level, cache_type, restrict); - return iprv.status; + PAL_CALL(iprv, PAL_CACHE_INIT, level, cache_type, restrict); + return iprv.status; } -/* Initialize the tags and data of a data or unified cache line of - * processor controlled cache to known values without the availability +/* Initialize the tags and data of a data or unified cache line of + * processor controlled cache to known values without the availability * of backing memory. */ -static inline s64 -ia64_pal_cache_line_init (u64 physical_addr, u64 data_value) -{ +static inline s64 +ia64_pal_cache_line_init (u64 physical_addr, u64 data_value) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_CACHE_LINE_INIT, physical_addr, data_value, 0); - return iprv.status; + return iprv.status; } /* Read the data and tag of a processor controlled cache line for diags */ -static inline s64 -ia64_pal_cache_read (pal_cache_line_id_u_t line_id, u64 physical_addr) -{ +static inline s64 +ia64_pal_cache_read (pal_cache_line_id_u_t line_id, u64 physical_addr) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_CACHE_READ, line_id.pclid_data, physical_addr, 0); - return iprv.status; + return iprv.status; } /* Return summary information about the heirarchy of caches controlled by the processor */ -static inline s64 -ia64_pal_cache_summary (u64 *cache_levels, u64 *unique_caches) -{ +static inline s64 +ia64_pal_cache_summary (u64 *cache_levels, u64 *unique_caches) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_CACHE_SUMMARY, 0, 0, 0); if (cache_levels) *cache_levels = iprv.v0; if (unique_caches) *unique_caches = iprv.v1; - return iprv.status; + return iprv.status; } /* Write the data and tag of a processor-controlled cache line for diags */ -static inline s64 -ia64_pal_cache_write (pal_cache_line_id_u_t line_id, u64 physical_addr, u64 data) -{ - struct ia64_pal_retval iprv; +static inline s64 +ia64_pal_cache_write (pal_cache_line_id_u_t line_id, u64 physical_addr, u64 data) +{ + struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_CACHE_WRITE, line_id.pclid_data, physical_addr, data); - return iprv.status; + return iprv.status; } /* Return the parameters needed to copy relocatable PAL procedures from ROM to memory */ -static inline s64 +static inline s64 ia64_pal_copy_info (u64 copy_type, u64 num_procs, u64 num_iopics, - u64 *buffer_size, u64 *buffer_align) -{ + u64 *buffer_size, u64 *buffer_align) +{ struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_COPY_INFO, copy_type, num_procs, num_iopics); + PAL_CALL(iprv, PAL_COPY_INFO, copy_type, num_procs, num_iopics); if (buffer_size) *buffer_size = iprv.v0; if (buffer_align) *buffer_align = iprv.v1; - return iprv.status; + return iprv.status; } /* Copy relocatable PAL procedures from ROM to memory */ -static inline s64 -ia64_pal_copy_pal (u64 target_addr, u64 alloc_size, u64 processor, u64 *pal_proc_offset) -{ +static inline s64 +ia64_pal_copy_pal (u64 target_addr, u64 alloc_size, u64 processor, u64 *pal_proc_offset) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_COPY_PAL, target_addr, alloc_size, processor); if (pal_proc_offset) *pal_proc_offset = iprv.v0; - return iprv.status; + return iprv.status; } /* Return the number of instruction and data debug register pairs */ -static inline s64 -ia64_pal_debug_info (u64 *inst_regs, u64 *data_regs) -{ +static inline s64 +ia64_pal_debug_info (u64 *inst_regs, u64 *data_regs) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_DEBUG_INFO, 0, 0, 0); if (inst_regs) @@ -875,50 +877,50 @@ if (data_regs) *data_regs = iprv.v1; - return iprv.status; + return iprv.status; } #ifdef TBD /* Switch from IA64-system environment to IA-32 system environment */ -static inline s64 -ia64_pal_enter_ia32_env (ia32_env1, ia32_env2, ia32_env3) -{ +static inline s64 +ia64_pal_enter_ia32_env (ia32_env1, ia32_env2, ia32_env3) +{ struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_ENTER_IA_32_ENV, ia32_env1, ia32_env2, ia32_env3); - return iprv.status; + PAL_CALL(iprv, PAL_ENTER_IA_32_ENV, ia32_env1, ia32_env2, ia32_env3); + return iprv.status; } #endif /* Get unique geographical address of this processor on its bus */ -static inline s64 -ia64_pal_fixed_addr (u64 *global_unique_addr) -{ +static inline s64 +ia64_pal_fixed_addr (u64 *global_unique_addr) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_FIXED_ADDR, 0, 0, 0); if (global_unique_addr) *global_unique_addr = iprv.v0; - return iprv.status; + return iprv.status; } /* Get base frequency of the platform if generated by the processor */ -static inline s64 -ia64_pal_freq_base (u64 *platform_base_freq) -{ +static inline s64 +ia64_pal_freq_base (u64 *platform_base_freq) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_FREQ_BASE, 0, 0, 0); if (platform_base_freq) *platform_base_freq = iprv.v0; - return iprv.status; + return iprv.status; } /* * Get the ratios for processor frequency, bus frequency and interval timer to - * to base frequency of the platform + * to base frequency of the platform */ -static inline s64 +static inline s64 ia64_pal_freq_ratios (struct pal_freq_ratio *proc_ratio, struct pal_freq_ratio *bus_ratio, - struct pal_freq_ratio *itc_ratio) -{ + struct pal_freq_ratio *itc_ratio) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_FREQ_RATIOS, 0, 0, 0); if (proc_ratio) @@ -927,20 +929,21 @@ *(u64 *)bus_ratio = iprv.v1; if (itc_ratio) *(u64 *)itc_ratio = iprv.v2; - return iprv.status; + return iprv.status; } -/* Make the processor enter HALT or one of the implementation dependent low +/* Make the processor enter HALT or one of the implementation dependent low * power states where prefetching and execution are suspended and cache and * TLB coherency is not maintained. */ -static inline s64 -ia64_pal_halt (u64 halt_state) -{ +static inline s64 +ia64_pal_halt (u64 halt_state) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_HALT, halt_state, 0, 0); - return iprv.status; + return iprv.status; } + typedef union pal_power_mgmt_info_u { u64 ppmi_data; struct { @@ -954,87 +957,87 @@ } pal_power_mgmt_info_u_t; /* Return information about processor's optional power management capabilities. */ -static inline s64 -ia64_pal_halt_info (pal_power_mgmt_info_u_t *power_buf) -{ +static inline s64 +ia64_pal_halt_info (pal_power_mgmt_info_u_t *power_buf) +{ struct ia64_pal_retval iprv; PAL_CALL_STK(iprv, PAL_HALT_INFO, (unsigned long) power_buf, 0, 0); - return iprv.status; + return iprv.status; } /* Cause the processor to enter LIGHT HALT state, where prefetching and execution are * suspended, but cache and TLB coherency is maintained. */ -static inline s64 -ia64_pal_halt_light (void) -{ +static inline s64 +ia64_pal_halt_light (void) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_HALT_LIGHT, 0, 0, 0); - return iprv.status; + return iprv.status; } /* Clear all the processor error logging registers and reset the indicator that allows * the error logging registers to be written. This procedure also checks the pending * machine check bit and pending INIT bit and reports their states. */ -static inline s64 -ia64_pal_mc_clear_log (u64 *pending_vector) -{ +static inline s64 +ia64_pal_mc_clear_log (u64 *pending_vector) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_MC_CLEAR_LOG, 0, 0, 0); if (pending_vector) *pending_vector = iprv.v0; - return iprv.status; + return iprv.status; } -/* Ensure that all outstanding transactions in a processor are completed or that any +/* Ensure that all outstanding transactions in a processor are completed or that any * MCA due to thes outstanding transaction is taken. */ -static inline s64 -ia64_pal_mc_drain (void) -{ +static inline s64 +ia64_pal_mc_drain (void) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_MC_DRAIN, 0, 0, 0); - return iprv.status; + return iprv.status; } /* Return the machine check dynamic processor state */ -static inline s64 -ia64_pal_mc_dynamic_state (u64 offset, u64 *size, u64 *pds) -{ +static inline s64 +ia64_pal_mc_dynamic_state (u64 offset, u64 *size, u64 *pds) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_MC_DYNAMIC_STATE, offset, 0, 0); if (size) *size = iprv.v0; if (pds) *pds = iprv.v1; - return iprv.status; + return iprv.status; } /* Return processor machine check information */ -static inline s64 -ia64_pal_mc_error_info (u64 info_index, u64 type_index, u64 *size, u64 *error_info) -{ +static inline s64 +ia64_pal_mc_error_info (u64 info_index, u64 type_index, u64 *size, u64 *error_info) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_MC_ERROR_INFO, info_index, type_index, 0); if (size) *size = iprv.v0; if (error_info) - *error_info = iprv.v1; - return iprv.status; + *error_info = iprv.v1; + return iprv.status; } /* Inform PALE_CHECK whether a machine check is expected so that PALE_CHECK willnot * attempt to correct any expected machine checks. */ -static inline s64 -ia64_pal_mc_expected (u64 expected, u64 *previous) -{ +static inline s64 +ia64_pal_mc_expected (u64 expected, u64 *previous) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_MC_EXPECTED, expected, 0, 0); if (previous) *previous = iprv.v0; - return iprv.status; + return iprv.status; } /* Register a platform dependent location with PAL to which it can save @@ -1042,39 +1045,39 @@ * event. */ static inline s64 -ia64_pal_mc_register_mem (u64 physical_addr) -{ +ia64_pal_mc_register_mem (u64 physical_addr) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_MC_REGISTER_MEM, physical_addr, 0, 0); - return iprv.status; + return iprv.status; } /* Restore minimal architectural processor state, set CMC interrupt if necessary * and resume execution */ -static inline s64 -ia64_pal_mc_resume (u64 set_cmci, u64 save_ptr) -{ +static inline s64 +ia64_pal_mc_resume (u64 set_cmci, u64 save_ptr) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_MC_RESUME, set_cmci, save_ptr, 0); - return iprv.status; + return iprv.status; } /* Return the memory attributes implemented by the processor */ -static inline s64 -ia64_pal_mem_attrib (u64 *mem_attrib) -{ +static inline s64 +ia64_pal_mem_attrib (u64 *mem_attrib) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_MEM_ATTRIB, 0, 0, 0); if (mem_attrib) *mem_attrib = iprv.v0 & 0xff; - return iprv.status; + return iprv.status; } /* Return the amount of memory needed for second phase of processor * self-test and the required alignment of memory. */ -static inline s64 +static inline s64 ia64_pal_mem_for_test (u64 *bytes_needed, u64 *alignment) { struct ia64_pal_retval iprv; @@ -1083,60 +1086,60 @@ *bytes_needed = iprv.v0; if (alignment) *alignment = iprv.v1; - return iprv.status; + return iprv.status; } typedef union pal_perf_mon_info_u { u64 ppmi_data; struct { u64 generic : 8, - width : 8, - cycles : 8, + width : 8, + cycles : 8, retired : 8, reserved : 32; } pal_perf_mon_info_s; } pal_perf_mon_info_u_t; - + /* Return the performance monitor information about what can be counted * and how to configure the monitors to count the desired events. */ -static inline s64 -ia64_pal_perf_mon_info (u64 *pm_buffer, pal_perf_mon_info_u_t *pm_info) -{ +static inline s64 +ia64_pal_perf_mon_info (u64 *pm_buffer, pal_perf_mon_info_u_t *pm_info) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_PERF_MON_INFO, (unsigned long) pm_buffer, 0, 0); if (pm_info) pm_info->ppmi_data = iprv.v0; - return iprv.status; + return iprv.status; } /* Specifies the physical address of the processor interrupt block * and I/O port space. */ -static inline s64 -ia64_pal_platform_addr (u64 type, u64 physical_addr) -{ +static inline s64 +ia64_pal_platform_addr (u64 type, u64 physical_addr) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_PLATFORM_ADDR, type, physical_addr, 0); - return iprv.status; + return iprv.status; } /* Set the SAL PMI entrypoint in memory */ -static inline s64 -ia64_pal_pmi_entrypoint (u64 sal_pmi_entry_addr) -{ +static inline s64 +ia64_pal_pmi_entrypoint (u64 sal_pmi_entry_addr) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_PMI_ENTRYPOINT, sal_pmi_entry_addr, 0, 0); - return iprv.status; + return iprv.status; } struct pal_features_s; /* Provide information about configurable processor features */ -static inline s64 -ia64_pal_proc_get_features (u64 *features_avail, - u64 *features_status, +static inline s64 +ia64_pal_proc_get_features (u64 *features_avail, + u64 *features_status, u64 *features_control) -{ +{ struct ia64_pal_retval iprv; PAL_CALL_PHYS(iprv, PAL_PROC_GET_FEATURES, 0, 0, 0); if (iprv.status == 0) { @@ -1144,16 +1147,16 @@ *features_status = iprv.v1; *features_control = iprv.v2; } - return iprv.status; + return iprv.status; } /* Enable/disable processor dependent features */ -static inline s64 -ia64_pal_proc_set_features (u64 feature_select) -{ +static inline s64 +ia64_pal_proc_set_features (u64 feature_select) +{ struct ia64_pal_retval iprv; PAL_CALL_PHYS(iprv, PAL_PROC_SET_FEATURES, feature_select, 0, 0); - return iprv.status; + return iprv.status; } /* @@ -1162,7 +1165,7 @@ */ typedef struct ia64_ptce_info_s { u64 base; - u32 count[2]; + u32 count[2]; u32 stride[2]; } ia64_ptce_info_t; @@ -1189,9 +1192,9 @@ } /* Return info about implemented application and control registers. */ -static inline s64 -ia64_pal_register_info (u64 info_request, u64 *reg_info_1, u64 *reg_info_2) -{ +static inline s64 +ia64_pal_register_info (u64 info_request, u64 *reg_info_1, u64 *reg_info_2) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_REGISTER_INFO, info_request, 0, 0); if (reg_info_1) @@ -1199,7 +1202,7 @@ if (reg_info_2) *reg_info_2 = iprv.v1; return iprv.status; -} +} typedef union pal_hints_u { u64 ph_data; @@ -1210,62 +1213,62 @@ } pal_hints_s; } pal_hints_u_t; -/* Return information about the register stack and RSE for this processor +/* Return information about the register stack and RSE for this processor * implementation. */ -static inline s64 +static inline s64 ia64_pal_rse_info (u64 *num_phys_stacked, pal_hints_u_t *hints) -{ +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_RSE_INFO, 0, 0, 0); if (num_phys_stacked) *num_phys_stacked = iprv.v0; if (hints) hints->ph_data = iprv.v1; - return iprv.status; + return iprv.status; } -/* Cause the processor to enter SHUTDOWN state, where prefetching and execution are +/* Cause the processor to enter SHUTDOWN state, where prefetching and execution are * suspended, but cause cache and TLB coherency to be maintained. * This is usually called in IA-32 mode. */ -static inline s64 -ia64_pal_shutdown (void) -{ +static inline s64 +ia64_pal_shutdown (void) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_SHUTDOWN, 0, 0, 0); - return iprv.status; + return iprv.status; } /* Perform the second phase of processor self-test. */ -static inline s64 +static inline s64 ia64_pal_test_proc (u64 test_addr, u64 test_size, u64 attributes, u64 *self_test_state) { struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_TEST_PROC, test_addr, test_size, attributes); if (self_test_state) *self_test_state = iprv.v0; - return iprv.status; + return iprv.status; } typedef union pal_version_u { u64 pal_version_val; struct { - u64 pv_pal_b_rev : 8; + u64 pv_pal_b_rev : 8; u64 pv_pal_b_model : 8; u64 pv_reserved1 : 8; u64 pv_pal_vendor : 8; u64 pv_pal_a_rev : 8; u64 pv_pal_a_model : 8; - u64 pv_reserved2 : 16; + u64 pv_reserved2 : 16; } pal_version_s; } pal_version_u_t; /* Return PAL version information */ -static inline s64 -ia64_pal_version (pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) -{ +static inline s64 +ia64_pal_version (pal_version_u_t *pal_min_version, pal_version_u_t *pal_cur_version) +{ struct ia64_pal_retval iprv; PAL_CALL_PHYS(iprv, PAL_VERSION, 0, 0, 0); if (pal_min_version) @@ -1274,7 +1277,7 @@ if (pal_cur_version) pal_cur_version->pal_version_val = iprv.v1; - return iprv.status; + return iprv.status; } typedef union pal_tc_info_u { @@ -1288,8 +1291,8 @@ reduce_tr : 1, reserved : 29; } pal_tc_info_s; -} pal_tc_info_u_t; - +} pal_tc_info_u_t; + #define tc_reduce_tr pal_tc_info_s.reduce_tr #define tc_unified pal_tc_info_s.unified #define tc_pf pal_tc_info_s.pf @@ -1298,10 +1301,10 @@ #define tc_num_sets pal_tc_info_s.num_sets -/* Return information about the virtual memory characteristics of the processor +/* Return information about the virtual memory characteristics of the processor * implementation. */ -static inline s64 +static inline s64 ia64_pal_vm_info (u64 tc_level, u64 tc_type, pal_tc_info_u_t *tc_info, u64 *tc_pages) { struct ia64_pal_retval iprv; @@ -1309,14 +1312,14 @@ if (tc_info) tc_info->pti_val = iprv.v0; if (tc_pages) - *tc_pages = iprv.v1; - return iprv.status; + *tc_pages = iprv.v1; + return iprv.status; } -/* Get page size information about the virtual memory characteristics of the processor +/* Get page size information about the virtual memory characteristics of the processor * implementation. */ -static inline s64 +static inline s64 ia64_pal_vm_page_size (u64 *tr_pages, u64 *vw_pages) { struct ia64_pal_retval iprv; @@ -1324,8 +1327,8 @@ if (tr_pages) *tr_pages = iprv.v0; if (vw_pages) - *vw_pages = iprv.v1; - return iprv.status; + *vw_pages = iprv.v1; + return iprv.status; } typedef union pal_vm_info_1_u { @@ -1348,23 +1351,23 @@ struct { u64 impl_va_msb : 8, rid_size : 8, - reserved : 48; + reserved : 48; } pal_vm_info_2_s; } pal_vm_info_2_u_t; - -/* Get summary information about the virtual memory characteristics of the processor + +/* Get summary information about the virtual memory characteristics of the processor * implementation. */ -static inline s64 -ia64_pal_vm_summary (pal_vm_info_1_u_t *vm_info_1, pal_vm_info_2_u_t *vm_info_2) -{ +static inline s64 +ia64_pal_vm_summary (pal_vm_info_1_u_t *vm_info_1, pal_vm_info_2_u_t *vm_info_2) +{ struct ia64_pal_retval iprv; PAL_CALL(iprv, PAL_VM_SUMMARY, 0, 0, 0); if (vm_info_1) vm_info_1->pvi1_val = iprv.v0; if (vm_info_2) vm_info_2->pvi2_val = iprv.v1; - return iprv.status; + return iprv.status; } typedef union pal_itr_valid_u { @@ -1379,14 +1382,14 @@ } pal_tr_valid_u_t; /* Read a translation register */ -static inline s64 +static inline s64 ia64_pal_tr_read (u64 reg_num, u64 tr_type, u64 *tr_buffer, pal_tr_valid_u_t *tr_valid) { struct ia64_pal_retval iprv; PAL_CALL_PHYS_STK(iprv, PAL_VM_TR_READ, reg_num, tr_type,(u64)__pa(tr_buffer)); if (tr_valid) tr_valid->piv_val = iprv.v0; - return iprv.status; + return iprv.status; } static inline s64 diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/pci.h linux/include/asm-ia64/pci.h --- v2.4.14/linux/include/asm-ia64/pci.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-ia64/pci.h Fri Nov 9 14:26:17 2001 @@ -10,9 +10,9 @@ #include <asm/scatterlist.h> /* - * Can be used to override the logic in pci_scan_bus for skipping - * already-configured bus numbers - to be used for buggy BIOSes or - * architectures with incomplete PCI setup by the loader. + * Can be used to override the logic in pci_scan_bus for skipping already-configured bus + * numbers - to be used for buggy BIOSes or architectures with incomplete PCI setup by the + * loader. */ #define pcibios_assign_all_busses() 0 @@ -57,9 +57,26 @@ return 1; } +#define pci_map_page(dev,pg,off,size,dir) \ + pci_map_single((dev), page_address(pg) + (off), (size), (dir)) +#define pci_unmap_page(dev,dma_addr,size,dir) \ + pci_unmap_single((dev), (dma_addr), (size), (dir)) + +/* The ia64 platform always supports 64-bit addressing. */ +#define pci_dac_dma_supported(pci_dev, mask) (1) + +#define pci_dac_page_to_dma(dev,pg,off,dir) ((dma64_addr_t) page_to_bus(pg) + (off)) +#define pci_dac_dma_to_page(dev,dma_addr) (virt_to_page(bus_to_virt(dma_addr))) +#define pci_dac_dma_to_offset(dev,dma_addr) ((dma_addr) & ~PAGE_MASK) +#define pci_dac_dma_sync_single(dev,dma_addr,len,dir) do { /* nothing */ } while (0) + /* Return the index of the PCI controller for device PDEV. */ #define pci_controller_num(PDEV) (0) #define sg_dma_len(sg) ((sg)->length) + +#define HAVE_PCI_MMAP +extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine); #endif /* _ASM_IA64_PCI_H */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/perfmon.h linux/include/asm-ia64/perfmon.h --- v2.4.14/linux/include/asm-ia64/perfmon.h Thu Apr 5 12:51:47 2001 +++ linux/include/asm-ia64/perfmon.h Fri Nov 9 14:26:17 2001 @@ -9,7 +9,7 @@ #include <linux/types.h> /* - * Structure used to define a context + * Request structure used to define a context */ typedef struct { unsigned long smpl_entries; /* how many entries in sampling buffer */ @@ -23,7 +23,7 @@ } pfreq_context_t; /* - * Structure used to configure a PMC or PMD + * Request structure used to write/read a PMC or PMD */ typedef struct { unsigned long reg_num; /* which register */ @@ -41,11 +41,16 @@ pfreq_reg_t pfr_reg; /* request to configure a PMD/PMC */ } perfmon_req_t; +#ifdef __KERNEL__ + extern void pfm_save_regs (struct task_struct *); extern void pfm_load_regs (struct task_struct *); -extern int pfm_inherit (struct task_struct *); +extern int pfm_inherit (struct task_struct *, struct pt_regs *); extern void pfm_context_exit (struct task_struct *); extern void pfm_flush_regs (struct task_struct *); +extern void pfm_cleanup_notifiers (struct task_struct *); + +#endif /* __KERNEL__ */ #endif /* _ASM_IA64_PERFMON_H */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/pgalloc.h linux/include/asm-ia64/pgalloc.h --- v2.4.14/linux/include/asm-ia64/pgalloc.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/pgalloc.h Fri Nov 9 14:26:17 2001 @@ -9,7 +9,7 @@ * in <asm/page.h> (currently 8192). * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 2000, Goutham Rao <goutham.rao@intel.com> */ @@ -164,11 +164,6 @@ #else # define flush_tlb_all() __flush_tlb_all() #endif - -/* - * Serialize usage of ptc.g: - */ -extern spinlock_t ptcg_lock; /* * Flush a specified user mapping diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/pgtable.h linux/include/asm-ia64/pgtable.h --- v2.4.14/linux/include/asm-ia64/pgtable.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/pgtable.h Fri Nov 9 14:26:17 2001 @@ -9,7 +9,7 @@ * in <asm/page.h> (currently 8192). * * Copyright (C) 1998-2001 Hewlett-Packard Co - * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/config.h> @@ -466,11 +466,21 @@ # endif /* !__ASSEMBLY__ */ /* - * Identity-mapped regions use a large page size. KERNEL_PG_NUM is the - * number of the (large) page frame that mapps the kernel. + * Identity-mapped regions use a large page size. We'll call such large pages + * "granules". If you can think of a better name that's unambiguous, let me + * know... + */ +#if defined(CONFIG_IA64_GRANULE_64MB) +# define IA64_GRANULE_SHIFT _PAGE_SIZE_64M +#elif defined(CONFIG_IA64_GRANULE_16MB) +# define IA64_GRANULE_SHIFT _PAGE_SIZE_16M +#endif +#define IA64_GRANULE_SIZE (1 << IA64_GRANULE_SHIFT) +/* + * log2() of the page size we use to map the kernel image (IA64_TR_KERNEL): */ -#define KERNEL_PG_SHIFT _PAGE_SIZE_64M -#define KERNEL_PG_SIZE (1 << KERNEL_PG_SHIFT) -#define KERNEL_PG_NUM ((KERNEL_START - PAGE_OFFSET) / KERNEL_PG_SIZE) +#define KERNEL_TR_PAGE_SHIFT _PAGE_SIZE_64M +#define KERNEL_TR_PAGE_SIZE (1 << KERNEL_TR_PAGE_SHIFT) +#define KERNEL_TR_PAGE_NUM ((KERNEL_START - PAGE_OFFSET) / KERNEL_TR_PAGE_SIZE) #endif /* _ASM_IA64_PGTABLE_H */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/processor.h linux/include/asm-ia64/processor.h --- v2.4.14/linux/include/asm-ia64/processor.h Tue Oct 9 17:06:53 2001 +++ linux/include/asm-ia64/processor.h Fri Nov 9 14:26:17 2001 @@ -168,10 +168,13 @@ #define IA64_THREAD_UAC_NOPRINT (__IA64_UL(1) << 3) /* don't log unaligned accesses */ #define IA64_THREAD_UAC_SIGBUS (__IA64_UL(1) << 4) /* generate SIGBUS on unaligned acc. */ #define IA64_THREAD_KRBS_SYNCED (__IA64_UL(1) << 5) /* krbs synced with process vm? */ -#define IA64_KERNEL_DEATH (__IA64_UL(1) << 63) /* see die_if_kernel()... */ +#define IA64_THREAD_FPEMU_NOPRINT (__IA64_UL(1) << 6) /* don't log any fpswa faults */ +#define IA64_THREAD_FPEMU_SIGFPE (__IA64_UL(1) << 7) /* send a SIGFPE for fpswa faults */ #define IA64_THREAD_UAC_SHIFT 3 #define IA64_THREAD_UAC_MASK (IA64_THREAD_UAC_NOPRINT | IA64_THREAD_UAC_SIGBUS) +#define IA64_THREAD_FPEMU_SHIFT 6 +#define IA64_THREAD_FPEMU_MASK (IA64_THREAD_FPEMU_NOPRINT | IA64_THREAD_FPEMU_SIGFPE) /* @@ -190,6 +193,7 @@ #include <asm/page.h> #include <asm/rse.h> #include <asm/unwind.h> +#include <asm/atomic.h> /* like above but expressed as bitfields for more efficient access: */ struct ia64_psr { @@ -324,6 +328,18 @@ (int *) (addr)); \ }) +#define SET_FPEMU_CTL(task,value) \ +({ \ + (task)->thread.flags = (((task)->thread.flags & ~IA64_THREAD_FPEMU_MASK) \ + | (((value) << IA64_THREAD_FPEMU_SHIFT) & IA64_THREAD_FPEMU_MASK)); \ + 0; \ +}) +#define GET_FPEMU_CTL(task,addr) \ +({ \ + put_user(((task)->thread.flags & IA64_THREAD_FPEMU_MASK) >> IA64_THREAD_FPEMU_SHIFT, \ + (int *) (addr)); \ +}) + struct siginfo; struct thread_struct { @@ -341,21 +357,19 @@ __u64 fdr; /* IA32 fp except. data reg */ __u64 csd; /* IA32 code selector descriptor */ __u64 ssd; /* IA32 stack selector descriptor */ - __u64 tssd; /* IA32 TSS descriptor */ + __u64 old_k1; /* old value of ar.k1 */ __u64 old_iob; /* old IOBase value */ - union { - __u64 sigmask; /* aligned mask for sigsuspend scall */ - } un; -# define INIT_THREAD_IA32 0, 0, 0x17800000037fULL, 0, 0, 0, 0, 0, 0, {0}, +# define INIT_THREAD_IA32 0, 0, 0x17800000037fULL, 0, 0, 0, 0, 0, 0, #else # define INIT_THREAD_IA32 #endif /* CONFIG_IA32_SUPPORT */ #ifdef CONFIG_PERFMON __u64 pmc[IA64_NUM_PMC_REGS]; __u64 pmd[IA64_NUM_PMD_REGS]; - unsigned long pfm_pend_notify; /* non-zero if we need to notify and block */ + unsigned long pfm_must_block; /* non-zero if we need to block on overflow */ void *pfm_context; /* pointer to detailed PMU context */ -# define INIT_THREAD_PM {0, }, {0, }, 0, 0, + atomic_t pfm_notifiers_check; /* indicate if release_thread much check tasklist */ +# define INIT_THREAD_PM {0, }, {0, }, 0, 0, {0}, #else # define INIT_THREAD_PM #endif @@ -628,10 +642,11 @@ } /* - * Save the processor status flags in FLAGS and then clear the - * interrupt collection and interrupt enable bits. + * Save the processor status flags in FLAGS and then clear the interrupt collection and + * interrupt enable bits. Don't trigger any mandatory RSE references while this bit is + * off! */ -#define ia64_clear_ic(flags) \ +#define ia64_clear_ic(flags) \ asm volatile ("mov %0=psr;; rsm psr.i | psr.ic;; srlz.i;;" \ : "=r"(flags) :: "memory"); @@ -720,6 +735,8 @@ asm volatile ("mov cr.lrr0=%0;; srlz.d" :: "r"(val) : "memory"); } +#define cpu_relax() do { } while (0) + static inline void ia64_set_lrr1 (unsigned long val) @@ -816,7 +833,7 @@ /* NOTE: The task struct and the stacks are allocated together. */ #define alloc_task_struct() \ ((struct task_struct *) __get_free_pages(GFP_KERNEL, IA64_TASK_STRUCT_LOG_NUM_PAGES)) -#define free_task_struct(p) free_pages((unsigned long)(p), IA64_TASK_STRUCT_LOG_NUM_PAGES) +#define free_task_struct(p) free_pages((unsigned long)(p), IA64_TASK_STRUCT_LOG_NUM_PAGES) #define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count) #define init_task (init_task_union.task) @@ -942,6 +959,42 @@ return val; } +static inline void +ia64_set_ibr (__u64 regnum, __u64 value) +{ + asm volatile ("mov ibr[%0]=%1" :: "r"(regnum), "r"(value)); +} + +static inline void +ia64_set_dbr (__u64 regnum, __u64 value) +{ + asm volatile ("mov dbr[%0]=%1" :: "r"(regnum), "r"(value)); +#ifdef CONFIG_ITANIUM + asm volatile (";; srlz.d"); +#endif +} + +static inline __u64 +ia64_get_ibr (__u64 regnum) +{ + __u64 retval; + + asm volatile ("mov %0=ibr[%1]" : "=r"(retval) : "r"(regnum)); + return retval; +} + +static inline __u64 +ia64_get_dbr (__u64 regnum) +{ + __u64 retval; + + asm volatile ("mov %0=dbr[%1]" : "=r"(retval) : "r"(regnum)); +#ifdef CONFIG_ITANIUM + asm volatile (";; srlz.d"); +#endif + return retval; +} + /* XXX remove the handcoded version once we have a sufficiently clever compiler... */ #ifdef SMART_COMPILER # define ia64_rotr(w,n) \ @@ -969,27 +1022,33 @@ return result; } -#define cpu_relax() do { } while (0) - +static inline __u64 +ia64_tpa (__u64 addr) +{ + __u64 result; + asm ("tpa %0=%1" : "=r"(result) : "r"(addr)); + return result; +} #define ARCH_HAS_PREFETCH #define ARCH_HAS_PREFETCHW #define ARCH_HAS_SPINLOCK_PREFETCH #define PREFETCH_STRIDE 256 -extern inline void prefetch(const void *x) +extern inline void +prefetch (const void *x) { __asm__ __volatile__ ("lfetch [%0]" : : "r"(x)); } - -extern inline void prefetchw(const void *x) + +extern inline void +prefetchw (const void *x) { __asm__ __volatile__ ("lfetch.excl [%0]" : : "r"(x)); } -#define spin_lock_prefetch(x) prefetchw(x) +#define spin_lock_prefetch(x) prefetchw(x) - #endif /* !__ASSEMBLY__ */ #endif /* _ASM_IA64_PROCESSOR_H */ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/sal.h linux/include/asm-ia64/sal.h --- v2.4.14/linux/include/asm-ia64/sal.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/sal.h Fri Nov 9 14:26:17 2001 @@ -7,10 +7,14 @@ * This is based on version 2.5 of the manual "IA-64 System * Abstraction Layer". * + * Copyright (C) 2001 Intel + * Copyright (C) 2001 Fred Lewis <frederick.v.lewis@intel.com> * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 Srinivasa Prasad Thirumalachar <sprasad@sprasad.engr.sgi.com> * + * 01/01/03 fvlewis Updated Error Record Structures to conform with Nov. 2000 + * revision of the SAL spec. * 99/09/29 davidm Updated for SAL 2.6. * 00/03/29 cfleck Updated SAL Error Logging info for processor (SAL 2.6) * (plus examples of platform error info structures from smariset @ Intel) @@ -19,7 +23,9 @@ #include <linux/spinlock.h> #include <asm/pal.h> +#include <asm/efi.h> #include <asm/system.h> +#include <asm/fpu.h> extern spinlock_t sal_lock; @@ -173,10 +179,8 @@ } ia64_sal_ptc_domain_info_t; typedef struct ia64_sal_ptc_domain_proc_entry { - u64 reserved : 16; - u64 eid : 8; /* eid of processor */ u64 id : 8; /* id of processor */ - u64 ignored : 32; + u64 eid : 8; /* eid of processor */ } ia64_sal_ptc_domain_proc_entry_t; @@ -199,19 +203,15 @@ enum { SAL_INFO_TYPE_MCA = 0, /* Machine check abort information */ SAL_INFO_TYPE_INIT = 1, /* Init information */ - SAL_INFO_TYPE_CMC = 2 /* Corrected machine check information */ -}; - -/* Sub information type encodings */ -enum { - SAL_SUB_INFO_TYPE_PROCESSOR = 0, /* Processor information */ - SAL_SUB_INFO_TYPE_PLATFORM = 1 /* Platform information */ + SAL_INFO_TYPE_CMC = 2, /* Corrected machine check information */ + SAL_INFO_TYPE_CPE = 3 /* Corrected platform error information */ }; /* Encodings for machine check parameter types */ enum { SAL_MC_PARAM_RENDEZ_INT = 1, /* Rendezevous interrupt */ - SAL_MC_PARAM_RENDEZ_WAKEUP = 2 /* Wakeup */ + SAL_MC_PARAM_RENDEZ_WAKEUP = 2, /* Wakeup */ + SAL_MC_PARAM_CPE_INT = 3 /* Corrected Platform Error Int */ }; /* Encodings for rendezvous mechanisms */ @@ -227,174 +227,389 @@ SAL_VECTOR_OS_BOOT_RENDEZ = 2 }; -/* Definition of the SAL Error Log from the SAL spec */ +/* +** Definition of the SAL Error Log from the SAL spec +*/ + +/* SAL Error Record Section GUID Definitions */ +#define SAL_PROC_DEV_ERR_SECT_GUID \ + ((efi_guid_t) { 0xe429faf1, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 }} ) +#define SAL_PLAT_MEM_DEV_ERR_SECT_GUID \ + ((efi_guid_t) { 0xe429faf2, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 }} ) +#define SAL_PLAT_SEL_DEV_ERR_SECT_GUID \ + ((efi_guid_t) { 0xe429faf3, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 }} ) +#define SAL_PLAT_PCI_BUS_ERR_SECT_GUID \ + ((efi_guid_t) { 0xe429faf4, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 }} ) +#define SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID \ + ((efi_guid_t) { 0xe429faf5, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 }} ) +#define SAL_PLAT_PCI_COMP_ERR_SECT_GUID \ + ((efi_guid_t) { 0xe429faf6, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 }} ) +#define SAL_PLAT_SPECIFIC_ERR_SECT_GUID \ + ((efi_guid_t) { 0xe429faf7, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 }} ) +#define SAL_PLAT_HOST_CTLR_ERR_SECT_GUID \ + ((efi_guid_t) { 0xe429faf8, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 }} ) +#define SAL_PLAT_BUS_ERR_SECT_GUID \ + ((efi_guid_t) { 0xe429faf9, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, \ + 0xc7, 0x3c, 0x88, 0x81 }} ) -/* Definition of timestamp according to SAL spec for logging purposes */ +#define MAX_CACHE_ERRORS 6 +#define MAX_TLB_ERRORS 6 +#define MAX_BUS_ERRORS 1 -typedef struct sal_log_timestamp { - u8 slh_century; /* Century (19, 20, 21, ...) */ - u8 slh_year; /* Year (00..99) */ - u8 slh_month; /* Month (1..12) */ - u8 slh_day; /* Day (1..31) */ - u8 slh_reserved; - u8 slh_hour; /* Hour (0..23) */ - u8 slh_minute; /* Minute (0..59) */ +/* Definition of version according to SAL spec for logging purposes */ +typedef struct sal_log_revision +{ + u8 minor; /* BCD (0..99) */ + u8 major; /* BCD (0..99) */ +} sal_log_revision_t; + +/* Definition of timestamp according to SAL spec for logging purposes */ +typedef struct sal_log_timestamp +{ u8 slh_second; /* Second (0..59) */ + u8 slh_minute; /* Minute (0..59) */ + u8 slh_hour; /* Hour (0..23) */ + u8 slh_reserved; + u8 slh_day; /* Day (1..31) */ + u8 slh_month; /* Month (1..12) */ + u8 slh_year; /* Year (00..99) */ + u8 slh_century; /* Century (19, 20, 21, ...) */ } sal_log_timestamp_t; +/* Definition of log record header structures */ +typedef struct sal_log_record_header +{ + u64 id; /* Unique monotonically increasing ID */ + sal_log_revision_t revision; /* Major and Minor revision of header */ + u16 severity; /* Error Severity */ + u32 len; /* Length of this error log in bytes */ + sal_log_timestamp_t timestamp; /* Timestamp */ + efi_guid_t platform_guid; /* Unique OEM Platform ID */ +} sal_log_record_header_t; -#define MAX_CACHE_ERRORS 6 -#define MAX_TLB_ERRORS 6 -#define MAX_BUS_ERRORS 1 +/* Definition of log section header structures */ +typedef struct sal_log_sec_header +{ + efi_guid_t guid; /* Unique Section ID */ + sal_log_revision_t revision; /* Major and Minor revision of Section */ + u16 reserved; + u32 len; /* Section length */ +} sal_log_section_hdr_t; + +typedef struct sal_log_mod_error_info +{ + struct + { + u64 check_info : 1, + requestor_identifier : 1, + responder_identifier : 1, + target_identifier : 1, + precise_ip : 1, + reserved : 59; + } valid; + u64 check_info; + u64 requestor_identifier; + u64 responder_identifier; + u64 target_identifier; + u64 precise_ip; +} sal_log_mod_error_info_t; + +typedef struct sal_processor_static_info +{ + struct + { + u64 minstate : 1, + br : 1, + cr : 1, + ar : 1, + rr : 1, + fr : 1, + reserved : 58; + } valid; + pal_min_state_area_t min_state_area; + u64 br[8]; + u64 cr[128]; + u64 ar[128]; + u64 rr[8]; + struct ia64_fpreg fr[128]; +} sal_processor_static_info_t; -typedef struct sal_log_processor_info { - struct { - u64 slpi_psi : 1, - slpi_cache_check: MAX_CACHE_ERRORS, - slpi_tlb_check : MAX_TLB_ERRORS, - slpi_bus_check : MAX_BUS_ERRORS, - slpi_reserved2 : (31 - (MAX_TLB_ERRORS + MAX_CACHE_ERRORS - + MAX_BUS_ERRORS)), - slpi_minstate : 1, - slpi_bank1_gr : 1, - slpi_br : 1, - slpi_cr : 1, - slpi_ar : 1, - slpi_rr : 1, - slpi_fr : 1, - slpi_reserved1 : 25; - } slpi_valid; - - pal_processor_state_info_t slpi_processor_state_info; - - struct { - pal_cache_check_info_t slpi_cache_check; - u64 slpi_target_address; - } slpi_cache_check_info[MAX_CACHE_ERRORS]; - - pal_tlb_check_info_t slpi_tlb_check_info[MAX_TLB_ERRORS]; - - struct { - pal_bus_check_info_t slpi_bus_check; - u64 slpi_requestor_addr; - u64 slpi_responder_addr; - u64 slpi_target_addr; - } slpi_bus_check_info[MAX_BUS_ERRORS]; - - pal_min_state_area_t slpi_min_state_area; - u64 slpi_br[8]; - u64 slpi_cr[128]; - u64 slpi_ar[128]; - u64 slpi_rr[8]; - u64 slpi_fr[128]; +typedef struct sal_log_processor_info +{ + sal_log_section_hdr_t header; + struct + { + u64 proc_error_map : 1, + proc_state_param : 1, + proc_cr_lid : 1, + psi_static_struct : 1, + num_cache_check : 4, + num_tlb_check : 4, + num_bus_check : 4, + num_reg_file_check : 4, + num_ms_check : 4, + cpuid_info : 1, + reserved1 : 39; + } valid; + u64 proc_error_map; + u64 proc_state_parameter; + u64 proc_cr_lid; + sal_log_mod_error_info_t cache_check_info[16]; + sal_log_mod_error_info_t tlb_check_info[16]; + sal_log_mod_error_info_t bus_check_info[16]; + sal_log_mod_error_info_t reg_file_check_info[16]; + sal_log_mod_error_info_t ms_check_info[16]; + struct + { + u64 regs[5]; + u64 reserved; + } cpuid_info; + sal_processor_static_info_t processor_static_info; } sal_log_processor_info_t; /* platform error log structures */ -typedef struct platerr_logheader { - u64 nextlog; /* next log offset if present */ - u64 loglength; /* log length */ - u64 logsubtype; /* log subtype memory/bus/component */ - u64 eseverity; /* error severity */ -} ehdr_t; - -typedef struct sysmem_errlog { - ehdr_t lhdr; /* header */ - u64 vflag; /* valid bits for each field in the log */ - u64 addr; /* memory address */ - u64 data; /* memory data */ - u64 cmd; /* command bus value if any */ - u64 ctrl; /* control bus value if any */ - u64 addrsyndrome; /* memory address ecc/parity syndrome bits */ - u64 datasyndrome; /* data ecc/parity syndrome */ - u64 cacheinfo; /* platform cache info as defined in pal spec. table 7-34 */ -} merrlog_t; - -typedef struct sysbus_errlog { - ehdr_t lhdr; /* linkded list header */ - u64 vflag; /* valid bits for each field in the log */ - u64 busnum; /* bus number in error */ - u64 reqaddr; /* requestor address */ - u64 resaddr; /* responder address */ - u64 taraddr; /* target address */ - u64 data; /* requester r/w data */ - u64 cmd; /* bus commands */ - u64 ctrl; /* bus controls (be# &-0) */ - u64 addrsyndrome; /* addr bus ecc/parity bits */ - u64 datasyndrome; /* data bus ecc/parity bits */ - u64 cmdsyndrome; /* command bus ecc/parity bits */ - u64 ctrlsyndrome; /* control bus ecc/parity bits */ -} berrlog_t; -/* platform error log structures */ -typedef struct syserr_chdr { /* one header per component */ - u64 busnum; /* bus number on which the component resides */ - u64 devnum; /* same as device select */ - u64 funcid; /* function id of the device */ - u64 devid; /* pci device id */ - u64 classcode; /* pci class code for the device */ - u64 cmdreg; /* pci command reg value */ - u64 statreg; /* pci status reg value */ -} chdr_t; - -typedef struct cfginfo { - u64 cfgaddr; - u64 cfgval; -} cfginfo_t; - -typedef struct sys_comperr { /* per component */ - ehdr_t lhdr; /* linked list header */ - u64 vflag; /* valid bits for each field in the log */ - chdr_t scomphdr; - u64 numregpair; /* number of reg addr/value pairs */ - cfginfo_t cfginfo; -} cerrlog_t; - -typedef struct sel_records { - ehdr_t lhdr; - u64 seldata; -} isel_t; - -typedef struct plat_errlog { - u64 mbcsvalid; /* valid bits for each type of log */ - merrlog_t smemerrlog; /* platform memory error logs */ - berrlog_t sbuserrlog; /* platform bus error logs */ - cerrlog_t scomperrlog; /* platform chipset error logs */ - isel_t selrecord; /* ipmi sel record */ -} platforminfo_t; - -/* over all log structure (processor+platform) */ - -typedef union udev_specific_log { - sal_log_processor_info_t proclog; - platforminfo_t platlog; -} devicelog_t; - - -#define sal_log_processor_info_psi_valid slpi_valid.spli_psi -#define sal_log_processor_info_cache_check_valid slpi_valid.spli_cache_check -#define sal_log_processor_info_tlb_check_valid slpi_valid.spli_tlb_check -#define sal_log_processor_info_bus_check_valid slpi_valid.spli_bus_check -#define sal_log_processor_info_minstate_valid slpi_valid.spli_minstate -#define sal_log_processor_info_bank1_gr_valid slpi_valid.slpi_bank1_gr -#define sal_log_processor_info_br_valid slpi_valid.slpi_br -#define sal_log_processor_info_cr_valid slpi_valid.slpi_cr -#define sal_log_processor_info_ar_valid slpi_valid.slpi_ar -#define sal_log_processor_info_rr_valid slpi_valid.slpi_rr -#define sal_log_processor_info_fr_valid slpi_valid.slpi_fr - -typedef struct sal_log_header { - u64 slh_next_log; /* Offset of the next log from the beginning of this structure */ - u32 slh_log_len; /* Length of this error log in bytes */ - u16 slh_log_type; /* Type of log (0 - cpu ,1 - platform) */ - u16 slh_log_sub_type; /* SGI specific sub type */ - sal_log_timestamp_t slh_log_timestamp; /* Timestamp */ -} sal_log_header_t; - -/* SAL PSI log structure */ -typedef struct psilog { - sal_log_header_t sal_elog_header; - devicelog_t devlog; -} ia64_psilog_t; +typedef struct sal_log_mem_dev_err_info +{ + sal_log_section_hdr_t header; + struct + { + u64 error_status : 1, + physical_addr : 1, + addr_mask : 1, + node : 1, + card : 1, + module : 1, + bank : 1, + device : 1, + row : 1, + column : 1, + bit_position : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + bus_spec_data : 1, + oem_id : 1, + oem_data : 1, + reserved : 47; + } valid; + u64 error_status; + u64 physical_addr; + u64 addr_mask; + u16 node; + u16 card; + u16 module; + u16 bank; + u16 device; + u16 row; + u16 column; + u16 bit_position; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u64 bus_spec_data; + u8 oem_id[16]; + u8 oem_data[1]; /* Variable length data */ +} sal_log_mem_dev_err_info_t; + +typedef struct sal_log_sel_dev_err_info +{ + sal_log_section_hdr_t header; + struct + { + u64 record_id : 1, + record_type : 1, + generator_id : 1, + evm_rev : 1, + sensor_type : 1, + sensor_num : 1, + event_dir : 1, + event_data1 : 1, + event_data2 : 1, + event_data3 : 1, + reserved : 54; + } valid; + u16 record_id; + u8 record_type; + u8 timestamp[4]; + u16 generator_id; + u8 evm_rev; + u8 sensor_type; + u8 sensor_num; + u8 event_dir; + u8 event_data1; + u8 event_data2; + u8 event_data3; +} sal_log_sel_dev_err_info_t; + +typedef struct sal_log_pci_bus_err_info +{ + sal_log_section_hdr_t header; + struct + { + u64 err_status : 1, + err_type : 1, + bus_id : 1, + bus_address : 1, + bus_data : 1, + bus_cmd : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + oem_data : 1, + reserved : 54; + } valid; + u64 err_status; + u16 err_type; + u16 bus_id; + u32 reserved; + u64 bus_address; + u64 bus_data; + u64 bus_cmd; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u8 oem_data[1]; /* Variable length data */ +} sal_log_pci_bus_err_info_t; + +typedef struct sal_log_smbios_dev_err_info +{ + sal_log_section_hdr_t header; + struct + { + u64 event_type : 1, + length : 1, + time_stamp : 1, + data : 1, + reserved1 : 60; + } valid; + u8 event_type; + u8 length; + u8 time_stamp[6]; + u8 data[1]; // data of variable length, length == slsmb_length +} sal_log_smbios_dev_err_info_t; + +typedef struct sal_log_pci_comp_err_info +{ + sal_log_section_hdr_t header; + struct + { + u64 err_status : 1, + comp_info : 1, + num_mem_regs : 1, + num_io_regs : 1, + reg_data_pairs : 1, + oem_data : 1, + reserved : 58; + } valid; + u64 err_status; + struct + { + u16 vendor_id; + u16 device_id; + u16 class_code; + u8 func_num; + u8 dev_num; + u8 bus_num; + u8 seg_num; + u8 reserved[6]; + } comp_info; + u32 num_mem_regs; + u32 num_io_regs; + u64 reg_data_pairs[1]; + /* array of address/data register pairs is num_mem_regs + num_io_regs + elements long. Each array element consists of a u64 address followed + by a u64 data value. The oem_data array immediately follows the the + reg_data_pairs array */ + u8 oem_data[1]; /* Variable length data */ +} sal_log_pci_comp_err_info_t; + +typedef struct sal_log_plat_specific_err_info +{ + sal_log_section_hdr_t header; + struct + { + u64 err_status : 1, + guid : 1, + oem_data : 1, + reserved : 61; + } valid; + u64 err_status; + efi_guid_t guid; + u8 oem_data[1]; /* platform specific variable length data */ +} sal_log_plat_specific_err_info_t; + +typedef struct sal_log_host_ctlr_err_info +{ + sal_log_section_hdr_t header; + struct + { + u64 err_status : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + bus_spec_data : 1, + oem_data : 1, + reserved : 58; + } valid; + u64 err_status; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u64 bus_spec_data; + u8 oem_data[1]; /* Variable length OEM data */ +} sal_log_host_ctlr_err_info_t; + +typedef struct sal_log_plat_bus_err_info +{ + sal_log_section_hdr_t header; + struct + { + u64 err_status : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + bus_spec_data : 1, + oem_data : 1, + reserved : 58; + } valid; + u64 err_status; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u64 bus_spec_data; + u8 oem_data[1]; /* Variable length OEM data */ +} sal_log_plat_bus_err_info_t; + +/* Overall platform error section structure */ +typedef union sal_log_platform_err_info +{ + sal_log_mem_dev_err_info_t mem_dev_err; + sal_log_sel_dev_err_info_t sel_dev_err; + sal_log_pci_bus_err_info_t pci_bus_err; + sal_log_smbios_dev_err_info_t smbios_dev_err; + sal_log_pci_comp_err_info_t pci_comp_err; + sal_log_plat_specific_err_info_t plat_specific_err; + sal_log_host_ctlr_err_info_t host_ctlr_err; + sal_log_plat_bus_err_info_t plat_bus_err; +} sal_log_platform_err_info_t; + +/* SAL log over-all, multi-section error record structure (processor+platform) */ +typedef struct err_rec +{ + sal_log_record_header_t sal_elog_header; + sal_log_processor_info_t proc_err; + sal_log_platform_err_info_t plat_err; + u8 oem_data_pad[1024]; +} ia64_err_rec_t; /* * Now define a couple of inline functions for improved type checking @@ -433,19 +648,20 @@ } /* Clear the processor and platform information logged by SAL with respect to the - * machine state at the time of MCA's, INITs or CMCs + * machine state at the time of MCA's, INITs, CMCs, or CPEs. */ static inline s64 ia64_sal_clear_state_info (u64 sal_info_type) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_CLEAR_STATE_INFO, sal_info_type, 0, 0, 0, 0, 0, 0); + SAL_CALL(isrv, SAL_CLEAR_STATE_INFO, sal_info_type, 0, + 0, 0, 0, 0, 0); return isrv.status; } /* Get the processor and platform information logged by SAL with respect to the machine - * state at the time of the MCAs, INITs or CMCs. + * state at the time of the MCAs, INITs, CMCs, or CPEs. */ static inline u64 ia64_sal_get_state_info (u64 sal_info_type, u64 *sal_info) @@ -455,16 +671,18 @@ sal_info, 0, 0, 0, 0); if (isrv.status) return 0; + return isrv.v0; } /* Get the maximum size of the information logged by SAL with respect to the machine - * state at the time of MCAs, INITs or CMCs + * state at the time of MCAs, INITs, CMCs, or CPEs. */ static inline u64 ia64_sal_get_state_info_size (u64 sal_info_type) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_GET_STATE_INFO_SIZE, sal_info_type, 0, 0, 0, 0, 0, 0); + SAL_CALL(isrv, SAL_GET_STATE_INFO_SIZE, sal_info_type, 0, + 0, 0, 0, 0, 0); if (isrv.status) return 0; return isrv.v0; diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/scatterlist.h linux/include/asm-ia64/scatterlist.h --- v2.4.14/linux/include/asm-ia64/scatterlist.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-ia64/scatterlist.h Fri Nov 9 14:26:17 2001 @@ -2,13 +2,13 @@ #define _ASM_IA64_SCATTERLIST_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> */ struct scatterlist { char *address; /* location data is to be transferred to */ - char *orig_address; /* Save away the original buffer address (used by pci-dma.c) */ + void *page; /* stupid: SCSI code insists on a member of this name... */ unsigned int length; /* buffer length */ }; diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/semaphore.h linux/include/asm-ia64/semaphore.h --- v2.4.14/linux/include/asm-ia64/semaphore.h Tue Apr 17 17:19:31 2001 +++ linux/include/asm-ia64/semaphore.h Fri Nov 9 14:26:17 2001 @@ -63,8 +63,6 @@ extern int __down_trylock (struct semaphore * sem); extern void __up (struct semaphore * sem); -extern spinlock_t semaphore_wake_lock; - /* * Atomically decrement the semaphore's count. If it goes negative, * block the calling thread in the TASK_UNINTERRUPTIBLE state. diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/sembuf.h linux/include/asm-ia64/sembuf.h --- v2.4.14/linux/include/asm-ia64/sembuf.h Sun Feb 6 18:42:40 2000 +++ linux/include/asm-ia64/sembuf.h Fri Nov 9 14:26:17 2001 @@ -1,7 +1,7 @@ #ifndef _ASM_IA64_SEMBUF_H #define _ASM_IA64_SEMBUF_H -/* +/* * The semid64_ds structure for IA-64 architecture. * Note extra padding because this structure is passed back and forth * between kernel and user space. diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/shmbuf.h linux/include/asm-ia64/shmbuf.h --- v2.4.14/linux/include/asm-ia64/shmbuf.h Sun Feb 6 18:42:40 2000 +++ linux/include/asm-ia64/shmbuf.h Fri Nov 9 14:26:17 2001 @@ -1,7 +1,7 @@ #ifndef _ASM_IA64_SHMBUF_H #define _ASM_IA64_SHMBUF_H -/* +/* * The shmid64_ds structure for IA-64 architecture. * Note extra padding because this structure is passed back and forth * between kernel and user space. diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/sigcontext.h linux/include/asm-ia64/sigcontext.h --- v2.4.14/linux/include/asm-ia64/sigcontext.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/sigcontext.h Fri Nov 9 14:26:17 2001 @@ -2,13 +2,13 @@ #define _ASM_IA64_SIGCONTEXT_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/fpu.h> -#define IA64_SC_FLAG_ONSTACK_BIT 1 /* is handler running on signal stack? */ +#define IA64_SC_FLAG_ONSTACK_BIT 0 /* is handler running on signal stack? */ #define IA64_SC_FLAG_IN_SYSCALL_BIT 1 /* did signal interrupt a syscall? */ #define IA64_SC_FLAG_FPH_VALID_BIT 2 /* is state in f[32]-f[127] valid? */ @@ -18,6 +18,19 @@ # ifndef __ASSEMBLY__ +/* + * Note on handling of register backing store: sc_ar_bsp contains the address that would + * be found in ar.bsp after executing a "cover" instruction the context in which the + * signal was raised. If signal delivery required switching to an alternate signal stack + * (sc_rbs_base is not NULL), the "dirty" partition (as it would exist after executing the + * imaginary "cover" instruction) is backed by the *alternate* signal stack, not the + * original one. In this case, sc_rbs_base contains the base address of the new register + * backing store. The number of registers in the dirty partition can be calculated as: + * + * ndirty = ia64_rse_num_regs(sc_rbs_base, sc_rbs_base + (sc_loadrs >> 16)) + * + */ + struct sigcontext { unsigned long sc_flags; /* see manifest constants above */ unsigned long sc_nat; /* bit i == 1 iff scratch reg gr[i] is a NaT */ @@ -40,8 +53,10 @@ unsigned long sc_gr[32]; /* general registers (static partition) */ struct ia64_fpreg sc_fr[128]; /* floating-point registers */ - unsigned long sc_rsvd[16]; /* reserved for future use */ + unsigned long sc_rbs_base; /* NULL or new base of sighandler's rbs */ + unsigned long sc_loadrs; /* see description above */ + unsigned long sc_rsvd[14]; /* reserved for future use */ /* * The mask must come last so we can increase _NSIG_WORDS * without breaking binary compatibility. diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/signal.h linux/include/asm-ia64/signal.h --- v2.4.14/linux/include/asm-ia64/signal.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/signal.h Fri Nov 9 14:26:17 2001 @@ -2,8 +2,8 @@ #define _ASM_IA64_SIGNAL_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> * * Unfortunately, this file is being included by bits/signal.h in * glibc-2.x. Hence the #ifdef __KERNEL__ ugliness. @@ -80,14 +80,24 @@ #define SA_RESTORER 0x04000000 -/* +/* * sigaltstack controls */ #define SS_ONSTACK 1 #define SS_DISABLE 2 -#define MINSIGSTKSZ 2048 -#define SIGSTKSZ 8192 +/* + * The minimum stack size needs to be fairly large because we want to + * be sure that an app compiled for today's CPUs will continue to run + * on all future CPU models. The CPU model matters because the signal + * frame needs to have space for the complete machine state, including + * all physical stacked registers. The number of physical stacked + * registers is CPU model dependent, but given that the width of + * ar.rsc.loadrs is 14 bits, we can assume that they'll never take up + * more than 16KB of space. + */ +#define MINSIGSTKSZ 131027 /* min. stack size for sigaltstack() */ +#define SIGSTKSZ 262144 /* default stack size for sigaltstack() */ #ifdef __KERNEL__ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/smp.h linux/include/asm-ia64/smp.h --- v2.4.14/linux/include/asm-ia64/smp.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/smp.h Fri Nov 9 14:26:17 2001 @@ -4,7 +4,7 @@ * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 2001 Hewlett-Packard Co - * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> + * David Mosberger-Tang <davidm@hpl.hp.com> */ #ifndef _ASM_IA64_SMP_H #define _ASM_IA64_SMP_H @@ -18,6 +18,7 @@ #include <linux/kernel.h> #include <asm/io.h> +#include <asm/param.h> #include <asm/processor.h> #include <asm/ptrace.h> @@ -107,7 +108,12 @@ return lid.f.id << 8 | lid.f.eid; } -#define NO_PROC_ID (-1) +#define NO_PROC_ID 0xffffffff /* no processor magic marker */ + +/* + * Extra overhead to move a task from one cpu to another (due to TLB and cache misses). + * Expressed in "negative nice value" units (larger number means higher priority/penalty). + */ #define PROC_CHANGE_PENALTY 20 extern void __init init_smp_config (void); diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/smplock.h linux/include/asm-ia64/smplock.h --- v2.4.14/linux/include/asm-ia64/smplock.h Thu Apr 5 12:51:47 2001 +++ linux/include/asm-ia64/smplock.h Fri Nov 9 14:26:17 2001 @@ -17,7 +17,7 @@ /* * Release global kernel lock and global interrupt lock */ -static __inline__ void +static __inline__ void release_kernel_lock(struct task_struct *task, int cpu) { if (task->lock_depth >= 0) @@ -29,7 +29,7 @@ /* * Re-acquire the kernel lock */ -static __inline__ void +static __inline__ void reacquire_kernel_lock(struct task_struct *task) { if (task->lock_depth >= 0) @@ -43,14 +43,14 @@ * so we only need to worry about other * CPU's. */ -static __inline__ void +static __inline__ void lock_kernel(void) { if (!++current->lock_depth) spin_lock(&kernel_flag); } -static __inline__ void +static __inline__ void unlock_kernel(void) { if (--current->lock_depth < 0) diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/spinlock.h linux/include/asm-ia64/spinlock.h --- v2.4.14/linux/include/asm-ia64/spinlock.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/spinlock.h Fri Nov 9 14:26:17 2001 @@ -2,8 +2,8 @@ #define _ASM_IA64_SPINLOCK_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * * This file is used for SMP configurations only. @@ -39,7 +39,7 @@ "mov r30=1\n" \ "mov ar.ccv=r0\n" \ ";;\n" \ - IA64_SEMFIX"cmpxchg4.acq r30=[%0],r30,ar.ccv\n" \ + "cmpxchg4.acq r30=[%0],r30,ar.ccv\n" \ ";;\n" \ "cmp.ne p15,p0=r30,r0\n" \ "(p15) br.call.spnt.few b7=ia64_spinlock_contention\n" \ @@ -56,7 +56,7 @@ __asm__ __volatile__ ( \ "mov ar.ccv=r0\n" \ ";;\n" \ - IA64_SEMFIX"cmpxchg4.acq %0=[%2],%1,ar.ccv\n" \ + "cmpxchg4.acq %0=[%2],%1,ar.ccv\n" \ : "=r"(result) : "r"(1), "r"(&(x)->lock) : "ar.ccv", "memory"); \ (result == 0); \ }) @@ -84,11 +84,11 @@ "mov r29 = 1\n" \ ";;\n" \ "1:\n" \ - "ld4 r2 = [%0]\n" \ + "ld4.bias r2 = [%0]\n" \ ";;\n" \ "cmp4.eq p0,p7 = r0,r2\n" \ "(p7) br.cond.spnt.few 1b \n" \ - IA64_SEMFIX"cmpxchg4.acq r2 = [%0], r29, ar.ccv\n" \ + "cmpxchg4.acq r2 = [%0], r29, ar.ccv\n" \ ";;\n" \ "cmp4.eq p0,p7 = r0, r2\n" \ "(p7) br.cond.spnt.few 1b\n" \ @@ -108,15 +108,17 @@ } rwlock_t; #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) + #define read_lock(rw) \ do { \ int tmp = 0; \ - __asm__ __volatile__ ("1:\t"IA64_SEMFIX"fetchadd4.acq %0 = [%1], 1\n" \ + __asm__ __volatile__ ("1:\tfetchadd4.acq %0 = [%1], 1\n" \ ";;\n" \ "tbit.nz p6,p0 = %0, 31\n" \ "(p6) br.cond.sptk.few 2f\n" \ ".section .text.lock,\"ax\"\n" \ - "2:\t"IA64_SEMFIX"fetchadd4.rel %0 = [%1], -1\n" \ + "2:\tfetchadd4.rel %0 = [%1], -1\n" \ ";;\n" \ "3:\tld4.acq %0 = [%1]\n" \ ";;\n" \ @@ -132,7 +134,7 @@ #define read_unlock(rw) \ do { \ int tmp = 0; \ - __asm__ __volatile__ (IA64_SEMFIX"fetchadd4.rel %0 = [%1], -1\n" \ + __asm__ __volatile__ ("fetchadd4.rel %0 = [%1], -1\n" \ : "=r" (tmp) \ : "r" (rw) \ : "memory"); \ @@ -142,14 +144,14 @@ do { \ __asm__ __volatile__ ( \ "mov ar.ccv = r0\n" \ - "movl r29 = 0x80000000\n" \ + "dep r29 = -1, r0, 31, 1\n" \ ";;\n" \ "1:\n" \ "ld4 r2 = [%0]\n" \ ";;\n" \ "cmp4.eq p0,p7 = r0,r2\n" \ "(p7) br.cond.spnt.few 1b \n" \ - IA64_SEMFIX"cmpxchg4.acq r2 = [%0], r29, ar.ccv\n" \ + "cmpxchg4.acq r2 = [%0], r29, ar.ccv\n" \ ";;\n" \ "cmp4.eq p0,p7 = r0, r2\n" \ "(p7) br.cond.spnt.few 1b\n" \ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/system.h linux/include/asm-ia64/system.h --- v2.4.14/linux/include/asm-ia64/system.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/system.h Fri Nov 9 14:26:17 2001 @@ -29,15 +29,6 @@ #define GATE_ADDR (0xa000000000000000 + PAGE_SIZE) #define PERCPU_ADDR (0xa000000000000000 + 2*PAGE_SIZE) -#if defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) - /* Workaround for Errata 97. */ -# define IA64_SEMFIX_INSN mf; -# define IA64_SEMFIX "mf;" -#else -# define IA64_SEMFIX_INSN -# define IA64_SEMFIX "" -#endif - #ifndef __ASSEMBLY__ #include <linux/kernel.h> @@ -210,12 +201,12 @@ ({ \ switch (sz) { \ case 4: \ - __asm__ __volatile__ (IA64_SEMFIX"fetchadd4.rel %0=[%1],%2" \ + __asm__ __volatile__ ("fetchadd4.rel %0=[%1],%2" \ : "=r"(tmp) : "r"(v), "i"(n) : "memory"); \ break; \ \ case 8: \ - __asm__ __volatile__ (IA64_SEMFIX"fetchadd8.rel %0=[%1],%2" \ + __asm__ __volatile__ ("fetchadd8.rel %0=[%1],%2" \ : "=r"(tmp) : "r"(v), "i"(n) : "memory"); \ break; \ \ @@ -257,22 +248,22 @@ switch (size) { case 1: - __asm__ __volatile (IA64_SEMFIX"xchg1 %0=[%1],%2" : "=r" (result) + __asm__ __volatile ("xchg1 %0=[%1],%2" : "=r" (result) : "r" (ptr), "r" (x) : "memory"); return result; case 2: - __asm__ __volatile (IA64_SEMFIX"xchg2 %0=[%1],%2" : "=r" (result) + __asm__ __volatile ("xchg2 %0=[%1],%2" : "=r" (result) : "r" (ptr), "r" (x) : "memory"); return result; case 4: - __asm__ __volatile (IA64_SEMFIX"xchg4 %0=[%1],%2" : "=r" (result) + __asm__ __volatile ("xchg4 %0=[%1],%2" : "=r" (result) : "r" (ptr), "r" (x) : "memory"); return result; case 8: - __asm__ __volatile (IA64_SEMFIX"xchg8 %0=[%1],%2" : "=r" (result) + __asm__ __volatile ("xchg8 %0=[%1],%2" : "=r" (result) : "r" (ptr), "r" (x) : "memory"); return result; } @@ -313,22 +304,22 @@ __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \ switch (size) { \ case 1: \ - __asm__ __volatile__ (IA64_SEMFIX"cmpxchg1."sem" %0=[%1],%2,ar.ccv" \ + __asm__ __volatile__ ("cmpxchg1."sem" %0=[%1],%2,ar.ccv" \ : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \ break; \ \ case 2: \ - __asm__ __volatile__ (IA64_SEMFIX"cmpxchg2."sem" %0=[%1],%2,ar.ccv" \ + __asm__ __volatile__ ("cmpxchg2."sem" %0=[%1],%2,ar.ccv" \ : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \ break; \ \ case 4: \ - __asm__ __volatile__ (IA64_SEMFIX"cmpxchg4."sem" %0=[%1],%2,ar.ccv" \ + __asm__ __volatile__ ("cmpxchg4."sem" %0=[%1],%2,ar.ccv" \ : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \ break; \ \ case 8: \ - __asm__ __volatile__ (IA64_SEMFIX"cmpxchg8."sem" %0=[%1],%2,ar.ccv" \ + __asm__ __volatile__ ("cmpxchg8."sem" %0=[%1],%2,ar.ccv" \ : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \ break; \ \ diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/unistd.h linux/include/asm-ia64/unistd.h --- v2.4.14/linux/include/asm-ia64/unistd.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-ia64/unistd.h Fri Nov 9 14:26:17 2001 @@ -4,8 +4,8 @@ /* * IA-64 Linux syscall numbers and inline-functions. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998-2001 Hewlett-Packard Co + * David Mosberger-Tang <davidm@hpl.hp.com> */ #include <asm/break.h> @@ -93,7 +93,7 @@ #define __NR_setpriority 1102 #define __NR_statfs 1103 #define __NR_fstatfs 1104 -/* unused; used to be __NR_ioperm */ +#define __NR_gettid 1105 #define __NR_semget 1106 #define __NR_semop 1107 #define __NR_semctl 1108 @@ -205,6 +205,7 @@ #define __NR_clone2 1213 #define __NR_getdents64 1214 #define __NR_getunwind 1215 +#define __NR_readahead 1216 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) diff -u --recursive --new-file v2.4.14/linux/include/asm-ia64/user.h linux/include/asm-ia64/user.h --- v2.4.14/linux/include/asm-ia64/user.h Sun Feb 6 18:42:40 2000 +++ linux/include/asm-ia64/user.h Fri Nov 9 14:26:17 2001 @@ -24,11 +24,12 @@ * current->start_stack, so we round each of these in order to be able * to write an integer number of pages. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> + * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co + * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> */ #include <linux/ptrace.h> +#include <linux/types.h> #include <asm/page.h> diff -u --recursive --new-file v2.4.14/linux/include/asm-s390/atomic.h linux/include/asm-s390/atomic.h --- v2.4.14/linux/include/asm-s390/atomic.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-s390/atomic.h Fri Nov 9 14:11:15 2001 @@ -20,7 +20,7 @@ * S390 uses 'Compare And Swap' for atomicity in SMP enviroment */ -typedef struct { volatile int counter; } atomic_t __attribute__ ((aligned (4))); +typedef struct { volatile int counter; } __attribute__ ((aligned (4))) atomic_t; #define ATOMIC_INIT(i) { (i) } #define atomic_eieio() __asm__ __volatile__ ("BCR 15,0") diff -u --recursive --new-file v2.4.14/linux/include/asm-s390/fcntl.h linux/include/asm-s390/fcntl.h --- v2.4.14/linux/include/asm-s390/fcntl.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/fcntl.h Fri Nov 9 14:11:15 2001 @@ -23,7 +23,7 @@ #define O_NDELAY O_NONBLOCK #define O_SYNC 010000 #define FASYNC 020000 /* fcntl, for BSD compatibility */ -#define O_DIRECT 040000 /* direct disk access hint - currently ignored */ +#define O_DIRECT 040000 /* direct disk access hint */ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ diff -u --recursive --new-file v2.4.14/linux/include/asm-s390/gdb-stub.h linux/include/asm-s390/gdb-stub.h --- v2.4.14/linux/include/asm-s390/gdb-stub.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-s390/gdb-stub.h Fri Nov 9 14:11:15 2001 @@ -14,7 +14,7 @@ extern int gdb_stub_initialised; extern void gdb_stub_handle_exception(struct gdb_pt_regs *regs,int sigval); struct net_device; -struct net_device *gdb_dev; +extern struct net_device *gdb_dev; void gdb_do_timers(void); extern int putDebugChar(char c); /* write a single character */ extern char getDebugChar(void); /* read and return a single char */ diff -u --recursive --new-file v2.4.14/linux/include/asm-s390/irq.h linux/include/asm-s390/irq.h --- v2.4.14/linux/include/asm-s390/irq.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-s390/irq.h Fri Nov 9 14:11:15 2001 @@ -313,7 +313,7 @@ scsw_t scsw; /* subchannel status word */ esw_t esw; /* extended status word */ __u8 ecw[32]; /* extended control word */ - } irb_t __attribute__ ((packed,aligned(4))); + } __attribute__ ((packed,aligned(4))) irb_t; #ifdef __KERNEL__ /* diff -u --recursive --new-file v2.4.14/linux/include/asm-s390/sigcontext.h linux/include/asm-s390/sigcontext.h --- v2.4.14/linux/include/asm-s390/sigcontext.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390/sigcontext.h Fri Nov 9 14:11:15 2001 @@ -26,14 +26,14 @@ { unsigned long mask; unsigned long addr; -} _psw_t __attribute__ ((aligned(8))); +} __attribute__ ((aligned(8))) _psw_t; typedef struct { _psw_t psw; unsigned long gprs[__NUM_GPRS]; unsigned int acrs[__NUM_ACRS]; -} _s390_regs_common __attribute__ ((packed)); +} _s390_regs_common; typedef struct { diff -u --recursive --new-file v2.4.14/linux/include/asm-s390/vtoc.h linux/include/asm-s390/vtoc.h --- v2.4.14/linux/include/asm-s390/vtoc.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-s390/vtoc.h Fri Nov 9 14:11:15 2001 @@ -190,7 +190,7 @@ ds5ext_t DS5EXTAV[7]; /* seven available extents */ __u8 DS5FMTID; /* format identifier */ ds5ext_t DS5MAVET[18]; /* eighteen available extents */ - cchhb_t DS5PTRDS[5]; /* pointer to next format5 DSCB */ + cchhb_t DS5PTRDS; /* pointer to next format5 DSCB */ } __attribute__ ((packed)) format5_label_t; diff -u --recursive --new-file v2.4.14/linux/include/asm-s390x/atomic.h linux/include/asm-s390x/atomic.h --- v2.4.14/linux/include/asm-s390x/atomic.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-s390x/atomic.h Fri Nov 9 14:11:15 2001 @@ -20,7 +20,7 @@ * S390 uses 'Compare And Swap' for atomicity in SMP enviroment */ -typedef struct { volatile int counter; } atomic_t __attribute__ ((aligned (4))); +typedef struct { volatile int counter; } __attribute__ ((aligned (4))) atomic_t; #define ATOMIC_INIT(i) { (i) } #define atomic_eieio() __asm__ __volatile__ ("BCR 15,0") diff -u --recursive --new-file v2.4.14/linux/include/asm-s390x/fcntl.h linux/include/asm-s390x/fcntl.h --- v2.4.14/linux/include/asm-s390x/fcntl.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/fcntl.h Fri Nov 9 14:11:15 2001 @@ -23,7 +23,7 @@ #define O_NDELAY O_NONBLOCK #define O_SYNC 010000 #define FASYNC 020000 /* fcntl, for BSD compatibility */ -#define O_DIRECT 040000 /* direct disk access hint - currently ignored */ +#define O_DIRECT 040000 /* direct disk access hint */ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ diff -u --recursive --new-file v2.4.14/linux/include/asm-s390x/irq.h linux/include/asm-s390x/irq.h --- v2.4.14/linux/include/asm-s390x/irq.h Sun Aug 12 13:28:00 2001 +++ linux/include/asm-s390x/irq.h Fri Nov 9 14:11:15 2001 @@ -313,7 +313,7 @@ scsw_t scsw; /* subchannel status word */ esw_t esw; /* extended status word */ __u8 ecw[32]; /* extended control word */ - } irb_t __attribute__ ((packed,aligned(4))); + } __attribute__ ((packed,aligned(4))) irb_t; #ifdef __KERNEL__ /* diff -u --recursive --new-file v2.4.14/linux/include/asm-s390x/s390-regs-common.h linux/include/asm-s390x/s390-regs-common.h --- v2.4.14/linux/include/asm-s390x/s390-regs-common.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/s390-regs-common.h Wed Dec 31 16:00:00 1969 @@ -1,115 +0,0 @@ -/* - * include/asm-s390/s390-regs-common.h - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * - * this file is designed to keep as much compatibility between - * gdb's representation of registers & the kernels representation of registers - * as possible so as to minimise translation between gdb registers & - * kernel registers please keep this matched with gdb & strace - */ - -#ifndef _S390_REGS_COMMON_H -#define _S390_REGS_COMMON_H -#ifndef __ASSEMBLY__ -#include <asm/types.h> -#endif -#if defined(WANT_S390_TGT_DEFS) || defined(__KERNEL__) -#define REGISTER_SIZE 8 -#endif -#define NUM_GPRS 16 -#define GPR_SIZE 8 -#define PSW_MASK_SIZE 8 -#define PSW_ADDR_SIZE 8 -#define NUM_FPRS 16 -#define FPR_SIZE 8 -#define FPC_SIZE 4 -#define FPC_PAD_SIZE 4 /* gcc insists on aligning the fpregs */ -#define NUM_CRS 16 -#define CR_SIZE 8 -#define NUM_ACRS 16 -#define ACR_SIZE 4 - -#define STACK_FRAME_OVERHEAD 160 /* size of minimum stack frame */ - -#ifndef __ASSEMBLY__ -/* this typedef defines how a Program Status Word looks like */ -typedef struct -{ - __u64 mask; - __u64 addr; -} psw_t __attribute__ ((aligned(8))); - -typedef __u64 gpr_t; - -/* 2 __u32's are used for floats instead to compile with a __STRICT_ANSI__ defined */ -typedef union -{ -#ifdef __KERNEL__ - __u64 d; /* mathemu.h gets upset otherwise */ -#else - double d; /* ansi c dosen't like long longs & make sure that */ - /* alignments are identical for both compiles */ -#endif - struct - { - __u32 hi; - __u32 lo; - } fp; - __u32 f; -} freg_t; - -typedef struct -{ -/* - The compiler appears to like aligning freg_t on an 8 byte boundary - so I always access fpregs, this was causing fun when I was doing - coersions. - */ - __u32 fpc; - freg_t fprs[NUM_FPRS]; -} s390_fp_regs; - -#define FPC_EXCEPTION_MASK 0xF8000000 -#define FPC_FLAGS_MASK 0x00F80000 -#define FPC_DXC_MASK 0x0000FF00 -#define FPC_RM_MASK 0x00000003 -#define FPC_VALID_MASK ((FPC_EXCEPTION_MASK|FPC_FLAGS_MASK| \ - FPC_DXC_MASK|FPC_RM_MASK)) - - -/* - gdb structures & the kernel have this much always in common - */ -#define S390_REGS_COMMON \ -psw_t psw; \ -__u64 gprs[NUM_GPRS]; \ -__u32 acrs[NUM_ACRS]; \ - -typedef struct -{ - S390_REGS_COMMON -} s390_regs_common __attribute__ ((packed)); - - -/* Sequence of bytes for breakpoint illegal instruction. */ -#define S390_BREAKPOINT {0x0,0x1} -#define S390_BREAKPOINT_U16 ((__u16)0x0001) -#define S390_SYSCALL_OPCODE ((__u16)0x0a00) -#define S390_SYSCALL_SIZE 2 -#if defined(WANT_S390_TGT_DEFS) || defined(__KERNEL__) -#define ADDR_BITS_REMOVE(addr) ((addr)) -#endif -#endif -#endif - - - - - - - - - diff -u --recursive --new-file v2.4.14/linux/include/asm-s390x/sigcontext.h linux/include/asm-s390x/sigcontext.h --- v2.4.14/linux/include/asm-s390x/sigcontext.h Tue Feb 13 14:13:44 2001 +++ linux/include/asm-s390x/sigcontext.h Fri Nov 9 14:11:15 2001 @@ -24,14 +24,14 @@ { unsigned long mask; unsigned long addr; -} _psw_t __attribute__ ((aligned(8))); +} __attribute__ ((aligned(8))) _psw_t; typedef struct { _psw_t psw; unsigned long gprs[__NUM_GPRS]; unsigned int acrs[__NUM_ACRS]; -} _s390_regs_common __attribute__ ((packed)); +} _s390_regs_common; typedef struct { diff -u --recursive --new-file v2.4.14/linux/include/asm-s390x/spinlock.h linux/include/asm-s390x/spinlock.h --- v2.4.14/linux/include/asm-s390x/spinlock.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-s390x/spinlock.h Fri Nov 9 14:11:15 2001 @@ -20,7 +20,7 @@ typedef struct { volatile unsigned int lock; -} spinlock_t __attribute__ ((aligned (8))); +} __attribute__ ((aligned (4))) spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } #define spin_lock_init(lp) do { (lp)->lock = 0; } while(0) diff -u --recursive --new-file v2.4.14/linux/include/asm-s390x/vtoc.h linux/include/asm-s390x/vtoc.h --- v2.4.14/linux/include/asm-s390x/vtoc.h Sun Aug 12 13:28:01 2001 +++ linux/include/asm-s390x/vtoc.h Fri Nov 9 14:11:15 2001 @@ -39,135 +39,6 @@ #define VTOC_ERROR "VTOC error:" -enum failure {unable_to_open, - unable_to_seek, - unable_to_write, - unable_to_read}; - -unsigned char ASCtoEBC[256] = -{ - /*00 NL SH SX EX ET NQ AK BL */ - 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, - /*08 BS HT LF VT FF CR SO SI */ - 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - /*10 DL D1 D2 D3 D4 NK SN EB */ - 0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26, - /*18 CN EM SB EC FS GS RS US */ - 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, - /*20 SP ! " # $ % & ' */ - 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, - /*28 ( ) * + , - . / */ - 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, - /*30 0 1 2 3 4 5 6 7 */ - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - /*38 8 9 : ; < = > ? */ - 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, - /*40 @ A B C D E F G */ - 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - /*48 H I J K L M N O */ - 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, - /*50 P Q R S T U V W */ - 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, - /*58 X Y Z [ \ ] ^ _ */ - 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, - /*60 ` a b c d e f g */ - 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - /*68 h i j k l m n o */ - 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - /*70 p q r s t u v w */ - 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - /*78 x y z { | } ~ DL */ - 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF -}; - - -unsigned char EBCtoASC[256] = -{ - /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */ - 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, - /* 0x08 -GE -SPS -RPT VT FF CR SO SI */ - 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC - -ENP ->LF */ - 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, - /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB - -IUS */ - 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC - -INP */ - 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, - /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL - -SW */ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, - /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */ - 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, - /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */ - 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, - /* 0x40 SP RSP ä ---- */ - 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, - /* 0x48 . < ( + | */ - 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, - /* 0x50 & ---- */ - 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, - /* 0x58 ß ! $ * ) ; */ - 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA, - /* 0x60 - / ---- Ä ---- ---- ---- */ - 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, - /* 0x68 ---- , % _ > ? */ - 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, - /* 0x70 ---- ---- ---- ---- ---- ---- ---- */ - 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - /* 0x78 * ` : # @ ' = " */ - 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, - /* 0x80 * a b c d e f g */ - 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - /* 0x88 h i ---- ---- ---- */ - 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, - /* 0x90 ° j k l m n o p */ - 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - /* 0x98 q r ---- ---- */ - 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, - /* 0xA0 ~ s t u v w x */ - 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - /* 0xA8 y z ---- ---- ---- ---- */ - 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, - /* 0xB0 ^ ---- § ---- */ - 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, - /* 0xB8 ---- [ ] ---- ---- ---- ---- */ - 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07, - /* 0xC0 { A B C D E F G */ - 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - /* 0xC8 H I ---- ö ---- */ - 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, - /* 0xD0 } J K L M N O P */ - 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, - /* 0xD8 Q R ---- ü */ - 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, - /* 0xE0 \ S T U V W X */ - 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - /* 0xE8 Y Z ---- Ö ---- ---- ---- */ - 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, - /* 0xF0 0 1 2 3 4 5 6 7 */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */ - 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07 -}; typedef struct ttr { @@ -319,7 +190,7 @@ ds5ext_t DS5EXTAV[7]; /* seven available extents */ __u8 DS5FMTID; /* format identifier */ ds5ext_t DS5MAVET[18]; /* eighteen available extents */ - cchhb_t DS5PTRDS[5]; /* pointer to next format5 DSCB */ + cchhb_t DS5PTRDS; /* pointer to next format5 DSCB */ } __attribute__ ((packed)) format5_label_t; diff -u --recursive --new-file v2.4.14/linux/include/asm-sparc/pci.h linux/include/asm-sparc/pci.h --- v2.4.14/linux/include/asm-sparc/pci.h Tue Oct 23 22:48:53 2001 +++ linux/include/asm-sparc/pci.h Wed Nov 7 14:39:36 2001 @@ -113,6 +113,8 @@ return 1; } +#define pci_dac_dma_supported(dev, mask) (0) + /* Return the index of the PCI controller for device PDEV. */ #define pci_controller_num(PDEV) (0) diff -u --recursive --new-file v2.4.14/linux/include/linux/acpi_serial.h linux/include/linux/acpi_serial.h --- v2.4.14/linux/include/linux/acpi_serial.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/acpi_serial.h Fri Nov 9 14:11:15 2001 @@ -0,0 +1,103 @@ +/* + * linux/include/linux/acpi_serial.h + * + * Copyright (C) 2000 Hewlett-Packard Co. + * Copyright (C) 2000 Khalid Aziz <khalid_aziz@hp.com> + * + * Definitions for ACPI defined serial ports (headless console and + * debug ports) + * + */ + +extern void setup_serial_acpi(void *); + +/* ACPI table signatures */ +#define ACPI_SPCRT_SIGNATURE "SPCR" +#define ACPI_DBGPT_SIGNATURE "DBGP" + +/* Interface type as defined in ACPI serial port tables */ +#define ACPI_SERIAL_INTFC_16550 0 +#define ACPI_SERIAL_INTFC_16450 1 + +/* Interrupt types for ACPI serial port tables */ +#define ACPI_SERIAL_INT_PCAT 0x01 +#define ACPI_SERIAL_INT_APIC 0x02 +#define ACPI_SERIAL_INT_SAPIC 0x04 + +/* Baud rates as defined in ACPI serial port tables */ +#define ACPI_SERIAL_BAUD_9600 3 +#define ACPI_SERIAL_BAUD_19200 4 +#define ACPI_SERIAL_BAUD_57600 6 +#define ACPI_SERIAL_BAUD_115200 7 + +/* Parity as defined in ACPI serial port tables */ +#define ACPI_SERIAL_PARITY_NONE 0 + +/* Flow control methods as defined in ACPI serial port tables */ +#define ACPI_SERIAL_FLOW_DCD 0x01 +#define ACPI_SERIAL_FLOW_RTS 0x02 +#define ACPI_SERIAL_FLOW_XON 0x04 + +/* Terminal types as defined in ACPI serial port tables */ +#define ACPI_SERIAL_TERM_VT100 0 +#define ACPI_SERIAL_TERM_VT100X 1 + +/* PCI Flags as defined by SPCR table */ +#define ACPI_SERIAL_PCIFLAG_PNP 0x00000001 + +/* Space ID as defined in base address structure in ACPI serial port tables */ +#define ACPI_SERIAL_MEM_SPACE 0 +#define ACPI_SERIAL_IO_SPACE 1 +#define ACPI_SERIAL_PCICONF_SPACE 2 + +/* + * Generic Register Address Structure - as defined by Microsoft + * in http://www.microsoft.com/hwdev/onnow/download/LFreeACPI.doc + * +*/ +typedef struct { + u8 space_id; + u8 bit_width; + u8 bit_offset; + u8 resv; + u32 addrl; + u32 addrh; +} gen_regaddr; + +/* Space ID for generic register address structure */ +#define REGADDR_SPACE_SYSMEM 0 +#define REGADDR_SPACE_SYSIO 1 +#define REGADDR_SPACE_PCICONFIG 2 + +/* Serial Port Console Redirection and Debug Port Table formats */ +typedef struct { + u8 signature[4]; + u32 length; + u8 rev; + u8 chksum; + u8 oemid[6]; + u8 oem_tabid[8]; + u32 oem_rev; + u8 creator_id[4]; + u32 creator_rev; + u8 intfc_type; + u8 resv1[3]; + gen_regaddr base_addr; + u8 int_type; + u8 irq; + u8 global_int[4]; + u8 baud; + u8 parity; + u8 stop_bits; + u8 flow_ctrl; + u8 termtype; + u8 language; + u16 pci_dev_id; + u16 pci_vendor_id; + u8 pci_bus; + u8 pci_dev; + u8 pci_func; + u8 pci_flags[4]; + u8 pci_seg; + u32 resv2; +} acpi_ser_t; diff -u --recursive --new-file v2.4.14/linux/include/linux/agp_backend.h linux/include/linux/agp_backend.h --- v2.4.14/linux/include/linux/agp_backend.h Tue Oct 9 17:06:53 2001 +++ linux/include/linux/agp_backend.h Fri Nov 9 14:11:15 2001 @@ -46,9 +46,12 @@ INTEL_GX, INTEL_I810, INTEL_I815, + INTEL_I820, INTEL_I830_M, INTEL_I840, + INTEL_I845, INTEL_I850, + INTEL_I860, VIA_GENERIC, VIA_VP3, VIA_MVP3, diff -u --recursive --new-file v2.4.14/linux/include/linux/atm.h linux/include/linux/atm.h --- v2.4.14/linux/include/linux/atm.h Thu Oct 18 13:49:56 2001 +++ linux/include/linux/atm.h Fri Nov 9 14:49:54 2001 @@ -235,6 +235,7 @@ void *arg; }; +typedef unsigned short atm_backend_t; #ifdef __KERNEL__ diff -u --recursive --new-file v2.4.14/linux/include/linux/atmapi.h linux/include/linux/atmapi.h --- v2.4.14/linux/include/linux/atmapi.h Tue Feb 8 18:23:13 2000 +++ linux/include/linux/atmapi.h Fri Nov 9 14:11:15 2001 @@ -6,7 +6,7 @@ #ifndef _LINUX_ATMAPI_H #define _LINUX_ATMAPI_H -#ifdef __sparc__ +#if defined(__sparc__) || defined(__ia64__) /* such alignment is not required on 32 bit sparcs, but we can't figure that we are on a sparc64 while compiling user-space programs. */ #define __ATM_API_ALIGN __attribute__((aligned(8))) @@ -24,6 +24,6 @@ * Convention: NULL pointers are passed as a field of all zeroes. */ -typedef struct { unsigned char _[8]; } atm_kptr_t; +typedef struct { unsigned char _[8]; } __ATM_API_ALIGN atm_kptr_t; #endif diff -u --recursive --new-file v2.4.14/linux/include/linux/atmdev.h linux/include/linux/atmdev.h --- v2.4.14/linux/include/linux/atmdev.h Thu Oct 18 13:50:55 2001 +++ linux/include/linux/atmdev.h Fri Nov 9 15:02:19 2001 @@ -93,6 +93,17 @@ /* query supported loopback modes */ #define ATM_SETSC _IOW('a',ATMIOC_SPECIAL+1,int) /* enable or disable single-copy */ +#define ATM_SETBACKEND _IOW('a',ATMIOC_SPECIAL+2,atm_backend_t) + /* set backend handler */ + +/* + * These are backend handkers that can be set via the ATM_SETBACKEND call + * above. In the future we may support dynamic loading of these - for now, + * they're just being used to share the ATMIOC_BACKEND ioctls + */ +#define ATM_BACKEND_RAW 0 +#define ATM_BACKEND_PPP 1 /* PPPoATM - RFC2364 */ +#define ATM_BACKEND_BR_2684 2 /* Bridged RFC1483/2684 */ /* for ATM_GETTYPE */ #define ATM_ITFTYP_LEN 8 /* maximum length of interface type name */ diff -u --recursive --new-file v2.4.14/linux/include/linux/atmioc.h linux/include/linux/atmioc.h --- v2.4.14/linux/include/linux/atmioc.h Tue Feb 8 18:23:13 2000 +++ linux/include/linux/atmioc.h Fri Nov 9 14:11:15 2001 @@ -27,7 +27,9 @@ #define ATMIOC_SARPRV_END 0x7f #define ATMIOC_ITF 0x80 /* Interface ioctls, globally unique */ #define ATMIOC_ITF_END 0x8f -/* 0x90-0xbf: Reserved for future use */ +#define ATMIOC_BACKEND 0x90 /* ATM generic backend ioctls, u. per backend */ +#define ATMIOC_BACKEND_END 0xaf +/* 0xb0-0xbf: Reserved for future use */ #define ATMIOC_AREQUIPA 0xc0 /* Application requested IP over ATM, glob. u. */ #define ATMIOC_LANE 0xd0 /* LAN Emulation, globally unique */ #define ATMIOC_MPOA 0xd8 /* MPOA, globally unique */ diff -u --recursive --new-file v2.4.14/linux/include/linux/atmppp.h linux/include/linux/atmppp.h --- v2.4.14/linux/include/linux/atmppp.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/atmppp.h Fri Nov 9 14:11:15 2001 @@ -0,0 +1,24 @@ +/* atmppp.h - RFC2364 PPPoATM */ + +/* Written 2000 by Mitchell Blank Jr */ + +#ifndef _LINUX_ATMPPP_H +#define _LINUX_ATMPPP_H + +#include <linux/atm.h> + +#define PPPOATM_ENCAPS_AUTODETECT (0) +#define PPPOATM_ENCAPS_VC (1) +#define PPPOATM_ENCAPS_LLC (2) + +/* + * This is for the ATM_SETBACKEND call - these are like socket families: + * the first element of the structure is the backend number and the rest + * is per-backend specific + */ +struct atm_backend_ppp { + atm_backend_t backend_num; /* ATM_BACKEND_PPP */ + int encaps; /* PPPOATM_ENCAPS_* */ +}; + +#endif /* _LINUX_ATMPPP_H */ diff -u --recursive --new-file v2.4.14/linux/include/linux/blk.h linux/include/linux/blk.h --- v2.4.14/linux/include/linux/blk.h Thu Oct 18 13:49:48 2001 +++ linux/include/linux/blk.h Fri Nov 9 14:55:40 2001 @@ -46,11 +46,13 @@ extern int bpcd_init(void); extern int ps2esdi_init(void); extern int jsfd_init(void); +extern int viodasd_init(void); +extern int viocd_init(void); #if defined(CONFIG_ARCH_S390) -extern int mdisk_init(void); extern int dasd_init(void); extern int xpram_init(void); +extern int tapeblock_init(void); #endif /* CONFIG_ARCH_S390 */ extern void set_device_ro(kdev_t dev,int flag); diff -u --recursive --new-file v2.4.14/linux/include/linux/capability.h linux/include/linux/capability.h --- v2.4.14/linux/include/linux/capability.h Thu Oct 18 13:47:38 2001 +++ linux/include/linux/capability.h Fri Nov 9 14:55:33 2001 @@ -249,6 +249,8 @@ /* Override resource limits. Set resource limits. */ /* Override quota limits. */ /* Override reserved space on ext2 filesystem */ +/* Modify data journaling mode on ext3 filesystem (uses journaling + resources) */ /* NOTE: ext2 honors fsuid when checking for resource overrides, so you can override using fsuid too */ /* Override size restrictions on IPC message queues */ diff -u --recursive --new-file v2.4.14/linux/include/linux/ethtool.h linux/include/linux/ethtool.h --- v2.4.14/linux/include/linux/ethtool.h Tue Oct 23 22:48:53 2001 +++ linux/include/linux/ethtool.h Fri Nov 9 13:45:35 2001 @@ -3,6 +3,7 @@ * * Copyright (C) 1998 David S. Miller (davem@redhat.com) * Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com> + * Portions Copyright 2001 Sun Microsystems (thockin@sun.com) */ #ifndef _LINUX_ETHTOOL_H @@ -25,17 +26,18 @@ u32 reserved[4]; }; +#define ETHTOOL_BUSINFO_LEN 32 /* these strings are set to whatever the driver author decides... */ struct ethtool_drvinfo { u32 cmd; char driver[32]; /* driver short name, "tulip", "eepro100" */ char version[32]; /* driver version string */ char fw_version[32]; /* firmware version string, if applicable */ - char bus_info[32]; /* Bus info for this interface. For PCI - * devices, use pci_dev->slot_name. */ + char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */ + /* For PCI devices, use pci_dev->slot_name. */ char reserved1[32]; char reserved2[28]; - u32 regdump_len; /* Amount of data from ETHTOOL_GREGS */ + u32 regdump_len; /* Amount of data from ETHTOOL_GREGS (u32s) */ }; #define SOPASS_MAX 6 @@ -47,6 +49,20 @@ u8 sopass[SOPASS_MAX]; /* SecureOn(tm) password */ }; +/* for passing single values */ +struct ethtool_value { + u32 cmd; + u32 data; +}; + +/* for passing big chunks of data */ +struct ethtool_regs { + u32 cmd; + u32 version; /* driver-specific, indicates different chips/revs */ + u32 len; /* in u32 increments */ + u32 data[0]; +}; + /* CMDs currently supported */ #define ETHTOOL_GSET 0x00000001 /* Get settings. */ #define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */ @@ -56,7 +72,8 @@ #define ETHTOOL_SWOL 0x00000006 /* Set wake-on-lan options, priv. */ #define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */ #define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level, priv. */ -#define ETHTOOL_NWAY_RST 0X00000009 /* Restart autonegotiation, priv. */ +#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv. */ +#define ETHTOOL_GLINK 0x0000000a /* Get link status */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET @@ -74,7 +91,7 @@ #define SUPPORTED_AUI (1 << 8) #define SUPPORTED_MII (1 << 9) #define SUPPORTED_FIBRE (1 << 10) -#define SUPPORTED_10base2 (1 << 11) +#define SUPPORTED_BNC (1 << 11) /* Indicates what features are advertised by the interface. */ #define ADVERTISED_10baseT_Half (1 << 0) @@ -88,7 +105,7 @@ #define ADVERTISED_AUI (1 << 8) #define ADVERTISED_MII (1 << 9) #define ADVERTISED_FIBRE (1 << 10) -#define ADVERTISED_10base2 (1 << 11) +#define ADVERTISED_BNC (1 << 11) /* The following are all involved in forcing a particular link * mode for the device for setting things. When getting the diff -u --recursive --new-file v2.4.14/linux/include/linux/ext3_fs.h linux/include/linux/ext3_fs.h --- v2.4.14/linux/include/linux/ext3_fs.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/ext3_fs.h Fri Nov 9 14:25:04 2001 @@ -0,0 +1,715 @@ +/* + * linux/include/linux/ext3_fs.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT3_FS_H +#define _LINUX_EXT3_FS_H + +#include <linux/types.h> + +/* + * The second extended filesystem constants/structures + */ + +/* + * Define EXT3FS_DEBUG to produce debug messages + */ +#undef EXT3FS_DEBUG + +/* + * Define EXT3_PREALLOCATE to preallocate data blocks for expanding files + */ +#undef EXT3_PREALLOCATE /* @@@ Fix this! */ +#define EXT3_DEFAULT_PREALLOC_BLOCKS 8 + +/* + * The second extended file system version + */ +#define EXT3FS_DATE "06 Nov 2001" +#define EXT3FS_VERSION "2.4-0.9.15" + +/* + * Debug code + */ +#ifdef EXT3FS_DEBUG +#define ext3_debug(f, a...) \ + do { \ + printk (KERN_DEBUG "EXT3-fs DEBUG (%s, %d): %s:", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (KERN_DEBUG f, ## a); \ + } while (0) +#else +#define ext3_debug(f, a...) do {} while (0) +#endif + +/* + * Special inodes numbers + */ +#define EXT3_BAD_INO 1 /* Bad blocks inode */ +#define EXT3_ROOT_INO 2 /* Root inode */ +#define EXT3_ACL_IDX_INO 3 /* ACL inode */ +#define EXT3_ACL_DATA_INO 4 /* ACL inode */ +#define EXT3_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT3_UNDEL_DIR_INO 6 /* Undelete directory inode */ +#define EXT3_RESIZE_INO 7 /* Reserved group descriptors inode */ +#define EXT3_JOURNAL_INO 8 /* Journal inode */ + +/* First non-reserved inode for old ext3 filesystems */ +#define EXT3_GOOD_OLD_FIRST_INO 11 + +/* + * The second extended file system magic number + */ +#define EXT3_SUPER_MAGIC 0xEF53 + +/* + * Maximal count of links to a file + */ +#define EXT3_LINK_MAX 32000 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT3_MIN_BLOCK_SIZE 1024 +#define EXT3_MAX_BLOCK_SIZE 4096 +#define EXT3_MIN_BLOCK_LOG_SIZE 10 +#ifdef __KERNEL__ +# define EXT3_BLOCK_SIZE(s) ((s)->s_blocksize) +#else +# define EXT3_BLOCK_SIZE(s) (EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#endif +#define EXT3_ACLE_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_acl_entry)) +#define EXT3_ADDR_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (__u32)) +#ifdef __KERNEL__ +# define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) +#else +# define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#endif +#ifdef __KERNEL__ +#define EXT3_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext3_sb.s_addr_per_block_bits) +#define EXT3_INODE_SIZE(s) ((s)->u.ext3_sb.s_inode_size) +#define EXT3_FIRST_INO(s) ((s)->u.ext3_sb.s_first_ino) +#else +#define EXT3_INODE_SIZE(s) (((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \ + EXT3_GOOD_OLD_INODE_SIZE : \ + (s)->s_inode_size) +#define EXT3_FIRST_INO(s) (((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \ + EXT3_GOOD_OLD_FIRST_INO : \ + (s)->s_first_ino) +#endif + +/* + * Macro-instructions used to manage fragments + */ +#define EXT3_MIN_FRAG_SIZE 1024 +#define EXT3_MAX_FRAG_SIZE 4096 +#define EXT3_MIN_FRAG_LOG_SIZE 10 +#ifdef __KERNEL__ +# define EXT3_FRAG_SIZE(s) ((s)->u.ext3_sb.s_frag_size) +# define EXT3_FRAGS_PER_BLOCK(s) ((s)->u.ext3_sb.s_frags_per_block) +#else +# define EXT3_FRAG_SIZE(s) (EXT3_MIN_FRAG_SIZE << (s)->s_log_frag_size) +# define EXT3_FRAGS_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / EXT3_FRAG_SIZE(s)) +#endif + +/* + * ACL structures + */ +struct ext3_acl_header /* Header of Access Control Lists */ +{ + __u32 aclh_size; + __u32 aclh_file_count; + __u32 aclh_acle_count; + __u32 aclh_first_acle; +}; + +struct ext3_acl_entry /* Access Control List Entry */ +{ + __u32 acle_size; + __u16 acle_perms; /* Access permissions */ + __u16 acle_type; /* Type of entry */ + __u16 acle_tag; /* User or group identity */ + __u16 acle_pad1; + __u32 acle_next; /* Pointer on next entry for the */ + /* same inode or on next free entry */ +}; + +/* + * Structure of a blocks group descriptor + */ +struct ext3_group_desc +{ + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_pad; + __u32 bg_reserved[3]; +}; + +/* + * Macro-instructions used to manage group descriptors + */ +#ifdef __KERNEL__ +# define EXT3_BLOCKS_PER_GROUP(s) ((s)->u.ext3_sb.s_blocks_per_group) +# define EXT3_DESC_PER_BLOCK(s) ((s)->u.ext3_sb.s_desc_per_block) +# define EXT3_INODES_PER_GROUP(s) ((s)->u.ext3_sb.s_inodes_per_group) +# define EXT3_DESC_PER_BLOCK_BITS(s) ((s)->u.ext3_sb.s_desc_per_block_bits) +#else +# define EXT3_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +# define EXT3_DESC_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_group_desc)) +# define EXT3_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) +#endif + +/* + * Constants relative to the data blocks + */ +#define EXT3_NDIR_BLOCKS 12 +#define EXT3_IND_BLOCK EXT3_NDIR_BLOCKS +#define EXT3_DIND_BLOCK (EXT3_IND_BLOCK + 1) +#define EXT3_TIND_BLOCK (EXT3_DIND_BLOCK + 1) +#define EXT3_N_BLOCKS (EXT3_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define EXT3_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT3_UNRM_FL 0x00000002 /* Undelete */ +#define EXT3_COMPR_FL 0x00000004 /* Compress file */ +#define EXT3_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT3_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT3_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT3_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT3_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define EXT3_DIRTY_FL 0x00000100 +#define EXT3_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define EXT3_NOCOMPR_FL 0x00000400 /* Don't compress */ +#define EXT3_ECOMPR_FL 0x00000800 /* Compression error */ +/* End compression flags --- maybe not all used */ +#define EXT3_INDEX_FL 0x00001000 /* hash-indexed directory */ +#define EXT3_IMAGIC_FL 0x00002000 /* AFS directory */ +#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */ +#define EXT3_RESERVED_FL 0x80000000 /* reserved for ext3 lib */ + +#define EXT3_FL_USER_VISIBLE 0x00005FFF /* User visible flags */ +#define EXT3_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */ + +/* + * Inode dynamic state flags + */ +#define EXT3_STATE_JDATA 0x00000001 /* journaled data exists */ +#define EXT3_STATE_NEW 0x00000002 /* inode is newly created */ + +/* + * ioctl commands + */ +#define EXT3_IOC_GETFLAGS _IOR('f', 1, long) +#define EXT3_IOC_SETFLAGS _IOW('f', 2, long) +#define EXT3_IOC_GETVERSION _IOR('f', 3, long) +#define EXT3_IOC_SETVERSION _IOW('f', 4, long) +#define EXT3_IOC_GETVERSION_OLD _IOR('v', 1, long) +#define EXT3_IOC_SETVERSION_OLD _IOW('v', 2, long) +#ifdef CONFIG_JBD_DEBUG +#define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long) +#endif + +/* + * Structure of an inode on the disk + */ +struct ext3_inode { + __u16 i_mode; /* File mode */ + __u16 i_uid; /* Low 16 bits of Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Creation time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Low 16 bits of Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_reserved1; + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + struct { + __u32 m_i_reserved1; + } masix1; + } osd1; /* OS dependent 1 */ + __u32 i_block[EXT3_N_BLOCKS];/* Pointers to blocks */ + __u32 i_generation; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_dir_acl; /* Directory ACL */ + __u32 i_faddr; /* Fragment address */ + union { + struct { + __u8 l_i_frag; /* Fragment number */ + __u8 l_i_fsize; /* Fragment size */ + __u16 i_pad1; + __u16 l_i_uid_high; /* these 2 fields */ + __u16 l_i_gid_high; /* were reserved2[0] */ + __u32 l_i_reserved2; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + struct { + __u8 m_i_frag; /* Fragment number */ + __u8 m_i_fsize; /* Fragment size */ + __u16 m_pad1; + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ +}; + +#define i_size_high i_dir_acl + +#if defined(__KERNEL__) || defined(__linux__) +#define i_reserved1 osd1.linux1.l_i_reserved1 +#define i_frag osd2.linux2.l_i_frag +#define i_fsize osd2.linux2.l_i_fsize +#define i_uid_low i_uid +#define i_gid_low i_gid +#define i_uid_high osd2.linux2.l_i_uid_high +#define i_gid_high osd2.linux2.l_i_gid_high +#define i_reserved2 osd2.linux2.l_i_reserved2 + +#elif defined(__GNU__) + +#define i_translator osd1.hurd1.h_i_translator +#define i_frag osd2.hurd2.h_i_frag; +#define i_fsize osd2.hurd2.h_i_fsize; +#define i_uid_high osd2.hurd2.h_i_uid_high +#define i_gid_high osd2.hurd2.h_i_gid_high +#define i_author osd2.hurd2.h_i_author + +#elif defined(__masix__) + +#define i_reserved1 osd1.masix1.m_i_reserved1 +#define i_frag osd2.masix2.m_i_frag +#define i_fsize osd2.masix2.m_i_fsize +#define i_reserved2 osd2.masix2.m_i_reserved2 + +#endif /* defined(__KERNEL__) || defined(__linux__) */ + +/* + * File system states + */ +#define EXT3_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT3_ERROR_FS 0x0002 /* Errors detected */ +#define EXT3_ORPHAN_FS 0x0004 /* Orphans being recovered */ + +/* + * Mount flags + */ +#define EXT3_MOUNT_CHECK 0x0001 /* Do mount-time checks */ +#define EXT3_MOUNT_GRPID 0x0004 /* Create files with directory's group */ +#define EXT3_MOUNT_DEBUG 0x0008 /* Some debugging messages */ +#define EXT3_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ +#define EXT3_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ +#define EXT3_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ +#define EXT3_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ +#define EXT3_MOUNT_NOLOAD 0x0100 /* Don't use existing journal*/ +#define EXT3_MOUNT_ABORT 0x0200 /* Fatal error detected */ +#define EXT3_MOUNT_DATA_FLAGS 0x0C00 /* Mode for data writes: */ + #define EXT3_MOUNT_JOURNAL_DATA 0x0400 /* Write data to journal */ + #define EXT3_MOUNT_ORDERED_DATA 0x0800 /* Flush data before commit */ + #define EXT3_MOUNT_WRITEBACK_DATA 0x0C00 /* No data ordering */ +#define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */ +#define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */ + +/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ +#ifndef _LINUX_EXT2_FS_H +#define clear_opt(o, opt) o &= ~EXT3_MOUNT_##opt +#define set_opt(o, opt) o |= EXT3_MOUNT_##opt +#define test_opt(sb, opt) ((sb)->u.ext3_sb.s_mount_opt & \ + EXT3_MOUNT_##opt) +#else +#define EXT2_MOUNT_NOLOAD EXT3_MOUNT_NOLOAD +#define EXT2_MOUNT_ABORT EXT3_MOUNT_ABORT +#endif + +#define ext3_set_bit ext2_set_bit +#define ext3_clear_bit ext2_clear_bit +#define ext3_test_bit ext2_test_bit +#define ext3_find_first_zero_bit ext2_find_first_zero_bit +#define ext3_find_next_zero_bit ext2_find_next_zero_bit + +/* + * Maximal mount counts between two filesystem checks + */ +#define EXT3_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ +#define EXT3_DFL_CHECKINTERVAL 0 /* Don't use interval check */ + +/* + * Behaviour when detecting errors + */ +#define EXT3_ERRORS_CONTINUE 1 /* Continue execution */ +#define EXT3_ERRORS_RO 2 /* Remount fs read-only */ +#define EXT3_ERRORS_PANIC 3 /* Panic */ +#define EXT3_ERRORS_DEFAULT EXT3_ERRORS_CONTINUE + +/* + * Structure of the super block + */ +struct ext3_super_block { +/*00*/ __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ +/*10*/ __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __s32 s_log_frag_size; /* Fragment size */ +/*20*/ __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_frags_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ +/*30*/ __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_minor_rev_level; /* minor revision level */ +/*40*/ __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ +/*50*/ __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT3_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __u32 s_first_ino; /* First non-reserved inode */ + __u16 s_inode_size; /* size of inode structure */ + __u16 s_block_group_nr; /* block group # of this superblock */ + __u32 s_feature_compat; /* compatible feature set */ +/*60*/ __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ +/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */ +/*78*/ char s_volume_name[16]; /* volume name */ +/*88*/ char s_last_mounted[64]; /* directory where last mounted */ +/*C8*/ __u32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT3_FEATURE_COMPAT_DIR_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_padding1; + /* + * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. + */ +/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ +/*E0*/ __u32 s_journal_inum; /* inode number of journal file */ + __u32 s_journal_dev; /* device number of journal file */ + __u32 s_last_orphan; /* start of list of inodes to delete */ + +/*EC*/ __u32 s_reserved[197]; /* Padding to the end of the block */ +}; + +#ifdef __KERNEL__ +#define EXT3_SB(sb) (&((sb)->u.ext3_sb)) +#define EXT3_I(inode) (&((inode)->u.ext3_i)) +#else +/* Assume that user mode programs are passing in an ext3fs superblock, not + * a kernel struct super_block. This will allow us to call the feature-test + * macros from user land. */ +#define EXT3_SB(sb) (sb) +#endif + +#define NEXT_ORPHAN(inode) (inode)->u.ext3_i.i_dtime + +/* + * Codes for operating systems + */ +#define EXT3_OS_LINUX 0 +#define EXT3_OS_HURD 1 +#define EXT3_OS_MASIX 2 +#define EXT3_OS_FREEBSD 3 +#define EXT3_OS_LITES 4 + +/* + * Revision levels + */ +#define EXT3_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT3_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT3_CURRENT_REV EXT3_GOOD_OLD_REV +#define EXT3_MAX_SUPP_REV EXT3_DYNAMIC_REV + +#define EXT3_GOOD_OLD_INODE_SIZE 128 + +/* + * Feature set definitions + */ + +#define EXT3_HAS_COMPAT_FEATURE(sb,mask) \ + ( EXT3_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) +#define EXT3_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( EXT3_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) +#define EXT3_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( EXT3_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) +#define EXT3_SET_COMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) +#define EXT3_SET_RO_COMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) +#define EXT3_SET_INCOMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) +#define EXT3_CLEAR_COMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) +#define EXT3_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) +#define EXT3_CLEAR_INCOMPAT_FEATURE(sb,mask) \ + EXT3_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) + +#define EXT3_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT3_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT3_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT3_FEATURE_COMPAT_RESIZE_INODE 0x0010 +#define EXT3_FEATURE_COMPAT_DIR_INDEX 0x0020 + +#define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT3_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT3_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 + +#define EXT3_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT3_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ + +#define EXT3_FEATURE_COMPAT_SUPP 0 +#define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \ + EXT3_FEATURE_INCOMPAT_RECOVER) +#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT3_FEATURE_RO_COMPAT_BTREE_DIR) + +/* + * Default values for user and/or group using reserved blocks + */ +#define EXT3_DEF_RESUID 0 +#define EXT3_DEF_RESGID 0 + +/* + * Structure of a directory entry + */ +#define EXT3_NAME_LEN 255 + +struct ext3_dir_entry { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u16 name_len; /* Name length */ + char name[EXT3_NAME_LEN]; /* File name */ +}; + +/* + * The new version of the directory entry. Since EXT3 structures are + * stored in intel byte order, and the name_len field could never be + * bigger than 255 chars, it's safe to reclaim the extra byte for the + * file_type field. + */ +struct ext3_dir_entry_2 { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[EXT3_NAME_LEN]; /* File name */ +}; + +/* + * Ext3 directory file types. Only the low 3 bits are used. The + * other bits are reserved for now. + */ +#define EXT3_FT_UNKNOWN 0 +#define EXT3_FT_REG_FILE 1 +#define EXT3_FT_DIR 2 +#define EXT3_FT_CHRDEV 3 +#define EXT3_FT_BLKDEV 4 +#define EXT3_FT_FIFO 5 +#define EXT3_FT_SOCK 6 +#define EXT3_FT_SYMLINK 7 + +#define EXT3_FT_MAX 8 + +/* + * EXT3_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT3_DIR_PAD 4 +#define EXT3_DIR_ROUND (EXT3_DIR_PAD - 1) +#define EXT3_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT3_DIR_ROUND) & \ + ~EXT3_DIR_ROUND) + +#ifdef __KERNEL__ + +/* Filesize hard limits for 64-bit file offsets */ +extern long long ext3_max_sizes[]; + +/* + * Describe an inode's exact location on disk and in memory + */ +struct ext3_iloc +{ + struct buffer_head *bh; + struct ext3_inode *raw_inode; + unsigned long block_group; +}; + +/* + * Function prototypes + */ + +/* + * Ok, these declarations are also in <linux/kernel.h> but none of the + * ext3 source programs needs to include it so they are duplicated here. + */ +# define NORET_TYPE /**/ +# define ATTRIB_NORET __attribute__((noreturn)) +# define NORET_AND noreturn, + +/* acl.c */ +extern int ext3_permission (struct inode *, int); + +/* balloc.c */ +extern int ext3_bg_has_super(struct super_block *sb, int group); +extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group); +extern int ext3_new_block (handle_t *, struct inode *, unsigned long, + __u32 *, __u32 *, int *); +extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long, + unsigned long); +extern unsigned long ext3_count_free_blocks (struct super_block *); +extern void ext3_check_blocks_bitmap (struct super_block *); +extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh); + +/* bitmap.c */ +extern unsigned long ext3_count_free (struct buffer_head *, unsigned); + +/* dir.c */ +extern int ext3_check_dir_entry(const char *, struct inode *, + struct ext3_dir_entry_2 *, struct buffer_head *, + unsigned long); + +/* file.c */ + +/* fsync.c */ +extern int ext3_sync_file (struct file *, struct dentry *, int); + +/* ialloc.c */ +extern struct inode * ext3_new_inode (handle_t *, const struct inode *, int); +extern void ext3_free_inode (handle_t *, struct inode *); +extern struct inode * ext3_orphan_get (struct super_block *, ino_t); +extern unsigned long ext3_count_free_inodes (struct super_block *); +extern void ext3_check_inodes_bitmap (struct super_block *); + +/* inode.c */ + +extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *); +extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *); + +extern int ext3_get_inode_loc (struct inode *, struct ext3_iloc *); +extern void ext3_read_inode (struct inode *); +extern void ext3_write_inode (struct inode *, int); +extern int ext3_setattr (struct dentry *, struct iattr *); +extern void ext3_put_inode (struct inode *); +extern void ext3_delete_inode (struct inode *); +extern int ext3_sync_inode (handle_t *, struct inode *); +extern void ext3_discard_prealloc (struct inode *); +extern void ext3_dirty_inode(struct inode *); +extern int ext3_change_inode_journal_flag(struct inode *, int); + +/* ioctl.c */ +extern int ext3_ioctl (struct inode *, struct file *, unsigned int, + unsigned long); + +/* namei.c */ +extern struct inode_operations ext3_dir_inode_operations; +extern int ext3_orphan_add(handle_t *, struct inode *); +extern int ext3_orphan_del(handle_t *, struct inode *); + +/* super.c */ +extern void ext3_error (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern void __ext3_std_error (struct super_block *, const char *, int); +extern void ext3_abort (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern NORET_TYPE void ext3_panic (struct super_block *, const char *, + const char *, ...) + __attribute__ ((NORET_AND format (printf, 3, 4))); +extern void ext3_warning (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern void ext3_update_dynamic_rev (struct super_block *sb); +extern void ext3_put_super (struct super_block *); +extern void ext3_write_super (struct super_block *); +extern void ext3_write_super_lockfs (struct super_block *); +extern void ext3_unlockfs (struct super_block *); +extern int ext3_remount (struct super_block *, int *, char *); +extern struct super_block * ext3_read_super (struct super_block *,void *,int); +extern int ext3_statfs (struct super_block *, struct statfs *); + +/* truncate.c */ +extern void ext3_truncate (struct inode *); + +#define ext3_std_error(sb, errno) \ +do { \ + if ((errno)) \ + __ext3_std_error((sb), __FUNCTION__, (errno)); \ +} while (0) +extern const char *ext3_decode_error(struct super_block *sb, int errno, char nbuf[16]); + +/* + * Inodes and files operations + */ + +/* dir.c */ +extern struct file_operations ext3_dir_operations; + +/* file.c */ +extern struct inode_operations ext3_file_inode_operations; +extern struct file_operations ext3_file_operations; + +/* symlink.c */ +extern struct inode_operations ext3_fast_symlink_inode_operations; + +extern struct address_space_operations ext3_aops; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_EXT3_FS_H */ diff -u --recursive --new-file v2.4.14/linux/include/linux/ext3_fs_i.h linux/include/linux/ext3_fs_i.h --- v2.4.14/linux/include/linux/ext3_fs_i.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/ext3_fs_i.h Fri Nov 9 14:55:23 2001 @@ -0,0 +1,78 @@ +/* + * linux/include/linux/ext3_fs_i.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs_i.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT3_FS_I +#define _LINUX_EXT3_FS_I + +#include <linux/rwsem.h> + +/* + * second extended file system inode data in memory + */ +struct ext3_inode_info { + __u32 i_data[15]; + __u32 i_flags; +#ifdef EXT3_FRAGMENTS + __u32 i_faddr; + __u8 i_frag_no; + __u8 i_frag_size; + __u16 unused; /* formerly i_osync */ +#endif + __u32 i_file_acl; + __u32 i_dir_acl; + __u32 i_dtime; + __u32 i_block_group; + __u32 i_state; /* Dynamic state flags for ext3 */ + __u32 i_next_alloc_block; + __u32 i_next_alloc_goal; +#ifdef EXT3_PREALLOCATE + __u32 i_prealloc_block; + __u32 i_prealloc_count; +#endif + __u32 i_dir_start_lookup; + + struct list_head i_orphan; /* unlinked but open inodes */ + + /* + * i_disksize keeps track of what the inode size is ON DISK, not + * in memory. During truncate, i_size is set to the new size by + * the VFS prior to calling ext3_truncate(), but the filesystem won't + * set i_disksize to 0 until the truncate is actually under way. + * + * The intent is that i_disksize always represents the blocks which + * are used by this file. This allows recovery to restart truncate + * on orphans if we crash during truncate. We actually write i_disksize + * into the on-disk inode when writing inodes out, instead of i_size. + * + * The only time when i_disksize and i_size may be different is when + * a truncate is in progress. The only things which change i_disksize + * are ext3_get_block (growth) and ext3_truncate (shrinkth). + */ + loff_t i_disksize; + + /* + * truncate_sem is for serialising ext3_truncate() against + * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's + * data tree are chopped off during truncate. We can't do that in + * ext3 because whenever we perform intermediate commits during + * truncate, the inode and all the metadata blocks *must* be in a + * consistent state which allows truncation of the orphans to restart + * during recovery. Hence we must fix the get_block-vs-truncate race + * by other means, so we have truncate_sem. + */ + struct rw_semaphore truncate_sem; +}; + +#endif /* _LINUX_EXT3_FS_I */ diff -u --recursive --new-file v2.4.14/linux/include/linux/ext3_fs_sb.h linux/include/linux/ext3_fs_sb.h --- v2.4.14/linux/include/linux/ext3_fs_sb.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/ext3_fs_sb.h Fri Nov 9 14:47:04 2001 @@ -0,0 +1,77 @@ +/* + * linux/include/linux/ext3_fs_sb.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs_sb.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT3_FS_SB +#define _LINUX_EXT3_FS_SB + +#ifdef __KERNEL__ +#include <linux/timer.h> +#include <linux/wait.h> +#endif + +/* + * The following is not needed anymore since the descriptors buffer + * heads are now dynamically allocated + */ +/* #define EXT3_MAX_GROUP_DESC 8 */ + +#define EXT3_MAX_GROUP_LOADED 8 + +/* + * third extended-fs super-block data in memory + */ +struct ext3_sb_info { + unsigned long s_frag_size; /* Size of a fragment in bytes */ + unsigned long s_frags_per_block;/* Number of fragments per block */ + unsigned long s_inodes_per_block;/* Number of inodes per block */ + unsigned long s_frags_per_group;/* Number of fragments in a group */ + unsigned long s_blocks_per_group;/* Number of blocks in a group */ + unsigned long s_inodes_per_group;/* Number of inodes in a group */ + unsigned long s_itb_per_group; /* Number of inode table blocks per group */ + unsigned long s_gdb_count; /* Number of group descriptor blocks */ + unsigned long s_desc_per_block; /* Number of group descriptors per block */ + unsigned long s_groups_count; /* Number of groups in the fs */ + struct buffer_head * s_sbh; /* Buffer containing the super block */ + struct ext3_super_block * s_es; /* Pointer to the super block in the buffer */ + struct buffer_head ** s_group_desc; + unsigned short s_loaded_inode_bitmaps; + unsigned short s_loaded_block_bitmaps; + unsigned long s_inode_bitmap_number[EXT3_MAX_GROUP_LOADED]; + struct buffer_head * s_inode_bitmap[EXT3_MAX_GROUP_LOADED]; + unsigned long s_block_bitmap_number[EXT3_MAX_GROUP_LOADED]; + struct buffer_head * s_block_bitmap[EXT3_MAX_GROUP_LOADED]; + unsigned long s_mount_opt; + uid_t s_resuid; + gid_t s_resgid; + unsigned short s_mount_state; + unsigned short s_pad; + int s_addr_per_block_bits; + int s_desc_per_block_bits; + int s_inode_size; + int s_first_ino; + + /* Journaling */ + struct inode * s_journal_inode; + struct journal_s * s_journal; + struct list_head s_orphan; + unsigned long s_commit_interval; + struct block_device *journal_bdev; +#ifdef CONFIG_JBD_DEBUG + struct timer_list turn_ro_timer; /* For turning read-only (crash simulation) */ + wait_queue_head_t ro_wait_queue; /* For people waiting for the fs to go read-only */ +#endif +}; + +#endif /* _LINUX_EXT3_FS_SB */ diff -u --recursive --new-file v2.4.14/linux/include/linux/ext3_jbd.h linux/include/linux/ext3_jbd.h --- v2.4.14/linux/include/linux/ext3_jbd.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/ext3_jbd.h Fri Nov 9 14:25:04 2001 @@ -0,0 +1,290 @@ +/* + * linux/include/linux/ext3_jbd.h + * + * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 + * + * Copyright 1998--1999 Red Hat corp --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Ext3-specific journaling extensions. + */ + +#ifndef _LINUX_EXT3_JBD_H +#define _LINUX_EXT3_JBD_H + +#include <linux/fs.h> +#include <linux/jbd.h> +#include <linux/ext3_fs.h> + +#define EXT3_JOURNAL(inode) (EXT3_SB((inode)->i_sb)->s_journal) + +/* Define the number of blocks we need to account to a transaction to + * modify one block of data. + * + * We may have to touch one inode, one bitmap buffer, up to three + * indirection blocks, the group and superblock summaries, and the data + * block to complete the transaction. */ + +#define EXT3_SINGLEDATA_TRANS_BLOCKS 8 + +/* Define the minimum size for a transaction which modifies data. This + * needs to take into account the fact that we may end up modifying two + * quota files too (one for the group, one for the user quota). The + * superblock only gets updated once, of course, so don't bother + * counting that again for the quota updates. */ + +#define EXT3_DATA_TRANS_BLOCKS (3 * EXT3_SINGLEDATA_TRANS_BLOCKS - 2) + +extern int ext3_writepage_trans_blocks(struct inode *inode); + +/* Delete operations potentially hit one directory's namespace plus an + * entire inode, plus arbitrary amounts of bitmap/indirection data. Be + * generous. We can grow the delete transaction later if necessary. */ + +#define EXT3_DELETE_TRANS_BLOCKS (2 * EXT3_DATA_TRANS_BLOCKS + 64) + +/* Define an arbitrary limit for the amount of data we will anticipate + * writing to any given transaction. For unbounded transactions such as + * write(2) and truncate(2) we can write more than this, but we always + * start off at the maximum transaction size and grow the transaction + * optimistically as we go. */ + +#define EXT3_MAX_TRANS_DATA 64 + +/* We break up a large truncate or write transaction once the handle's + * buffer credits gets this low, we need either to extend the + * transaction or to start a new one. Reserve enough space here for + * inode, bitmap, superblock, group and indirection updates for at least + * one block, plus two quota updates. Quota allocations are not + * needed. */ + +#define EXT3_RESERVE_TRANS_BLOCKS 12 + +int +ext3_mark_iloc_dirty(handle_t *handle, + struct inode *inode, + struct ext3_iloc *iloc); + +/* + * On success, We end up with an outstanding reference count against + * iloc->bh. This _must_ be cleaned up later. + */ + +int ext3_reserve_inode_write(handle_t *handle, struct inode *inode, + struct ext3_iloc *iloc); + +int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode); + +/* + * Wrapper functions with which ext3 calls into JBD. The intent here is + * to allow these to be turned into appropriate stubs so ext3 can control + * ext2 filesystems, so ext2+ext3 systems only nee one fs. This work hasn't + * been done yet. + */ + +static inline void ext3_journal_abort_handle(const char *caller, + const char *err_fn, + struct buffer_head *bh, + handle_t *handle, + int err) +{ + char nbuf[16]; + const char *errstr = ext3_decode_error(NULL, err, nbuf); + + printk(KERN_ERR "%s: aborting transaction: %s in %s", + caller, errstr, err_fn); + + if (bh) + BUFFER_TRACE(bh, "abort"); + journal_abort_handle(handle); + if (!handle->h_err) + handle->h_err = err; +} + +static inline int +__ext3_journal_get_undo_access(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = journal_get_undo_access(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext3_journal_get_write_access(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = journal_get_write_access(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext3_journal_dirty_data(const char *where, + handle_t *handle, struct buffer_head *bh, int async) +{ + int err = journal_dirty_data(handle, bh, async); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline void +ext3_journal_forget(handle_t *handle, struct buffer_head *bh) +{ + journal_forget(handle, bh); +} + +static inline int +__ext3_journal_revoke(const char *where, handle_t *handle, + unsigned long blocknr, struct buffer_head *bh) +{ + int err = journal_revoke(handle, blocknr, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext3_journal_get_create_access(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = journal_get_create_access(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + +static inline int +__ext3_journal_dirty_metadata(const char *where, + handle_t *handle, struct buffer_head *bh) +{ + int err = journal_dirty_metadata(handle, bh); + if (err) + ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); + return err; +} + + +#define ext3_journal_get_undo_access(handle, bh) \ + __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh)) +#define ext3_journal_get_write_access(handle, bh) \ + __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh)) +#define ext3_journal_dirty_data(handle, bh, async) \ + __ext3_journal_dirty_data(__FUNCTION__, (handle), (bh), (async)) +#define ext3_journal_revoke(handle, blocknr, bh) \ + __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh)) +#define ext3_journal_get_create_access(handle, bh) \ + __ext3_journal_get_create_access(__FUNCTION__, (handle), (bh)) +#define ext3_journal_dirty_metadata(handle, bh) \ + __ext3_journal_dirty_metadata(__FUNCTION__, (handle), (bh)) + + + +/* + * Wrappers for journal_start/end. + * + * The only special thing we need to do here is to make sure that all + * journal_end calls result in the superblock being marked dirty, so + * that sync() will call the filesystem's write_super callback if + * appropriate. + */ +static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks) +{ + if (inode->i_sb->s_flags & MS_RDONLY) + return ERR_PTR(-EROFS); + return journal_start(EXT3_JOURNAL(inode), nblocks); +} + +static inline handle_t * +ext3_journal_try_start(struct inode *inode, int nblocks) +{ + if (inode->i_sb->s_flags & MS_RDONLY) + return ERR_PTR(-EROFS); + return journal_try_start(EXT3_JOURNAL(inode), nblocks); +} + +/* + * The only special thing we need to do here is to make sure that all + * journal_stop calls result in the superblock being marked dirty, so + * that sync() will call the filesystem's write_super callback if + * appropriate. + */ +static inline int __ext3_journal_stop(const char *where, + handle_t *handle, struct inode *inode) +{ + int err = handle->h_err; + int rc = journal_stop(handle); + + inode->i_sb->s_dirt = 1; + if (!err) + err = rc; + if (err) + __ext3_std_error(inode->i_sb, where, err); + return err; +} +#define ext3_journal_stop(handle, inode) \ + __ext3_journal_stop(__FUNCTION__, (handle), (inode)) + +static inline handle_t *ext3_journal_current_handle(void) +{ + return journal_current_handle(); +} + +static inline void +ext3_log_start_commit(journal_t *journal, transaction_t *transaction) +{ + log_start_commit(journal, transaction); +} + +static inline void ext3_log_wait_commit(journal_t *journal, tid_t tid) +{ + log_wait_commit(journal, tid); +} + +static inline int ext3_journal_extend(handle_t *handle, int nblocks) +{ + return journal_extend(handle, nblocks); +} + +static inline int ext3_journal_restart(handle_t *handle, int nblocks) +{ + return journal_restart(handle, nblocks); +} + +static inline int ext3_journal_blocks_per_page(struct inode *inode) +{ + return journal_blocks_per_page(inode); +} + +static inline int ext3_journal_force_commit(journal_t *journal) +{ + return journal_force_commit(journal); +} + +/* super.c */ +int ext3_force_commit(struct super_block *sb); + +static inline int ext3_should_journal_data(struct inode *inode) +{ + if (!S_ISREG(inode->i_mode)) + return 1; + if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) + return 1; + if (inode->u.ext3_i.i_flags & EXT3_JOURNAL_DATA_FL) + return 1; + return 0; +} + +static inline int ext3_should_order_data(struct inode *inode) +{ + return (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA); +} + + +#endif /* _LINUX_EXT3_JBD_H */ diff -u --recursive --new-file v2.4.14/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.4.14/linux/include/linux/fs.h Mon Nov 5 15:55:35 2001 +++ linux/include/linux/fs.h Fri Nov 9 14:55:27 2001 @@ -216,6 +216,7 @@ BH_Async, /* 1 if the buffer is under end_buffer_io_async I/O */ BH_Wait_IO, /* 1 if we should write out this buffer */ BH_launder, /* 1 if we should throttle on this buffer */ + BH_JBD, /* 1 if it has an attached journal_head */ BH_PrivateStart,/* not a state bit, but the first bit available * for private allocation by other entities @@ -287,6 +288,7 @@ #include <linux/pipe_fs_i.h> #include <linux/minix_fs_i.h> #include <linux/ext2_fs_i.h> +#include <linux/ext3_fs_i.h> #include <linux/hpfs_fs_i.h> #include <linux/ntfs_fs_i.h> #include <linux/msdos_fs_i.h> @@ -376,10 +378,16 @@ int (*writepage)(struct page *); int (*readpage)(struct file *, struct page *); int (*sync_page)(struct page *); + /* + * ext3 requires that a successful prepare_write() call be followed + * by a commit_write() call - they must be balanced + */ int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); int (*commit_write)(struct file *, struct page *, unsigned, unsigned); /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ int (*bmap)(struct address_space *, long); + int (*flushpage) (struct page *, unsigned long); + int (*releasepage) (struct page *, int); #define KERNEL_HAS_O_DIRECT /* this is for modules out of the kernel */ int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int); }; @@ -470,6 +478,7 @@ union { struct minix_inode_info minix_i; struct ext2_inode_info ext2_i; + struct ext3_inode_info ext3_i; struct hpfs_inode_info hpfs_i; struct ntfs_inode_info ntfs_i; struct msdos_inode_info msdos_i; @@ -658,6 +667,7 @@ #include <linux/minix_fs_sb.h> #include <linux/ext2_fs_sb.h> +#include <linux/ext3_fs_sb.h> #include <linux/hpfs_fs_sb.h> #include <linux/ntfs_fs_sb.h> #include <linux/msdos_fs_sb.h> @@ -714,6 +724,7 @@ union { struct minix_sb_info minix_sb; struct ext2_sb_info ext2_sb; + struct ext3_sb_info ext3_sb; struct hpfs_sb_info hpfs_sb; struct ntfs_sb_info ntfs_sb; struct msdos_sb_info msdos_sb; @@ -1088,6 +1099,7 @@ extern int try_to_free_buffers(struct page *, unsigned int); extern void refile_buffer(struct buffer_head * buf); +extern void create_empty_buffers(struct page *, kdev_t, unsigned long); extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate); /* reiserfs_writepage needs this */ @@ -1170,6 +1182,7 @@ buffer_insert_inode_queue(bh, inode); } +extern void set_buffer_flushtime(struct buffer_head *); extern void balance_dirty(void); extern int check_disk_change(kdev_t); extern int invalidate_inodes(struct super_block *); @@ -1349,12 +1362,15 @@ extern int set_blocksize(kdev_t, int); extern struct buffer_head * bread(kdev_t, int, int); extern void wakeup_bdflush(void); +extern void put_unused_buffer_head(struct buffer_head * bh); +extern struct buffer_head * get_unused_buffer_head(int async); extern int brw_page(int, struct page *, kdev_t, int [], int); typedef int (get_block_t)(struct inode*,long,struct buffer_head*,int); /* Generic buffer handling for block filesystems.. */ +extern int try_to_release_page(struct page * page, int gfp_mask); extern int discard_bh_page(struct page *, unsigned long, int); #define block_flushpage(page, offset) discard_bh_page(page, offset, 1) #define block_invalidate_page(page) discard_bh_page(page, 0, 0) @@ -1416,7 +1432,7 @@ extern void mount_root(void); #ifdef CONFIG_BLK_DEV_INITRD -extern kdev_t real_root_dev; +extern unsigned int real_root_dev; extern int change_root(kdev_t, const char *); #endif diff -u --recursive --new-file v2.4.14/linux/include/linux/i2o.h linux/include/linux/i2o.h --- v2.4.14/linux/include/linux/i2o.h Tue Oct 23 22:48:53 2001 +++ linux/include/linux/i2o.h Fri Nov 9 14:11:15 2001 @@ -31,7 +31,6 @@ #include <asm/semaphore.h> /* Needed for MUTEX init macros */ #include <linux/config.h> #include <linux/notifier.h> -#include <linux/ioport.h> /* Needed for struct resource */ #include <asm/atomic.h> /* @@ -82,7 +81,7 @@ struct i2o_pci { int irq; - int queue_buggy:1; /* Don't send a lot of messages */ + int queue_buggy:3; /* Don't send a lot of messages */ int short_req:1; /* Use small block sizes */ int dpt:1; /* Don't quiesce */ #ifdef CONFIG_MTRR diff -u --recursive --new-file v2.4.14/linux/include/linux/if_bonding.h linux/include/linux/if_bonding.h --- v2.4.14/linux/include/linux/if_bonding.h Tue Mar 6 19:44:37 2001 +++ linux/include/linux/if_bonding.h Wed Nov 7 14:39:36 2001 @@ -9,16 +9,94 @@ * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov * * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. + * of the GNU Public License, incorporated herein by reference. * */ #ifndef _LINUX_IF_BONDING_H #define _LINUX_IF_BONDING_H -#define BOND_ENSLAVE (SIOCDEVPRIVATE) -#define BOND_RELEASE (SIOCDEVPRIVATE + 1) -#define BOND_SETHWADDR (SIOCDEVPRIVATE + 2) +#ifdef __KERNEL__ +#include <linux/timer.h> +#include <linux/if.h> +#include <linux/proc_fs.h> +#endif /* __KERNEL__ */ + +#include <linux/types.h> + +/* + * We can remove these ioctl definitions in 2.5. People should use the + * SIOC*** versions of them instead + */ +#define BOND_ENSLAVE_OLD (SIOCDEVPRIVATE) +#define BOND_RELEASE_OLD (SIOCDEVPRIVATE + 1) +#define BOND_SETHWADDR_OLD (SIOCDEVPRIVATE + 2) +#define BOND_SLAVE_INFO_QUERY_OLD (SIOCDEVPRIVATE + 11) +#define BOND_INFO_QUERY_OLD (SIOCDEVPRIVATE + 12) +#define BOND_CHANGE_ACTIVE_OLD (SIOCDEVPRIVATE + 13) + +#define BOND_CHECK_MII_STATUS (SIOCGMIIPHY) + +#define BOND_MODE_ROUNDROBIN 0 +#define BOND_MODE_ACTIVEBACKUP 1 +#define BOND_MODE_XOR 2 + +/* each slave's link has 4 states */ +#define BOND_LINK_UP 0 /* link is up and running */ +#define BOND_LINK_FAIL 1 /* link has just gone down */ +#define BOND_LINK_DOWN 2 /* link has been down for too long time */ +#define BOND_LINK_BACK 3 /* link is going back */ + +/* each slave has several states */ +#define BOND_STATE_ACTIVE 0 /* link is active */ +#define BOND_STATE_BACKUP 1 /* link is backup */ + +#define MAX_BONDS 1 /* Maximum number of devices to support */ + +typedef struct ifbond { + __s32 bond_mode; + __s32 num_slaves; + __s32 miimon; +} ifbond; + +typedef struct ifslave +{ + __s32 slave_id; /* Used as an IN param to the BOND_SLAVE_INFO_QUERY ioctl */ + char slave_name[IFNAMSIZ]; + char link; + char state; + __u32 link_failure_count; +} ifslave; + +#ifdef __KERNEL__ +typedef struct slave { + struct slave *next; + struct slave *prev; + struct net_device *dev; + short delay; + char link; /* one of BOND_LINK_XXXX */ + char state; /* one of BOND_STATE_XXXX */ + u32 link_failure_count; +} slave_t; + +typedef struct bonding { + slave_t *next; + slave_t *prev; + slave_t *current_slave; + __s32 slave_cnt; + rwlock_t lock; + rwlock_t ptrlock; + struct timer_list mii_timer; + struct timer_list arp_timer; + struct net_device_stats *stats; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *bond_proc_dir; + struct proc_dir_entry *bond_proc_info_file; +#endif /* CONFIG_PROC_FS */ + struct bonding *next_bond; + struct net_device *device; +} bonding_t; +#endif /* __KERNEL__ */ #endif /* _LINUX_BOND_H */ diff -u --recursive --new-file v2.4.14/linux/include/linux/irda.h linux/include/linux/irda.h --- v2.4.14/linux/include/linux/irda.h Sun Sep 23 11:41:01 2001 +++ linux/include/linux/irda.h Fri Nov 9 14:11:15 2001 @@ -66,6 +66,7 @@ IRDA_LITELINK_DONGLE = 5, IRDA_AIRPORT_DONGLE = 6, IRDA_OLD_BELKIN_DONGLE = 7, + IRDA_EP7211_IR = 8, } IRDA_DONGLE; /* Protocol types to be used for SOCK_DGRAM */ diff -u --recursive --new-file v2.4.14/linux/include/linux/jbd.h linux/include/linux/jbd.h --- v2.4.14/linux/include/linux/jbd.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/jbd.h Fri Nov 9 14:25:04 2001 @@ -0,0 +1,881 @@ +/* + * linux/include/linux/jbd.h + * + * Written by Stephen C. Tweedie <sct@redhat.com> + * + * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * Definitions for transaction data structures for the buffer cache + * filesystem journaling support. + */ + +#ifndef _LINUX_JBD_H +#define _LINUX_JBD_H + +#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE) || !defined(__KERNEL__) + +/* Allow this file to be included directly into e2fsprogs */ +#ifndef __KERNEL__ +#include "jfs_compat.h" +#define JFS_DEBUG +#define jfs_debug jbd_debug +#else + +#include <linux/journal-head.h> +#include <linux/stddef.h> +#include <asm/semaphore.h> +#endif + +#define journal_oom_retry 1 + +#ifdef CONFIG_JBD_DEBUG +/* + * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal + * consistency checks. By default we don't do this unless + * CONFIG_JBD_DEBUG is on. + */ +#define JBD_EXPENSIVE_CHECKING +extern int journal_enable_debug; + +#define jbd_debug(n, f, a...) \ + do { \ + if ((n) <= journal_enable_debug) { \ + printk (KERN_DEBUG "(%s, %d): %s: ", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (f, ## a); \ + } \ + } while (0) +#else +#define jbd_debug(f, a...) /**/ +#endif + +extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry); +#define jbd_kmalloc(size, flags) \ + __jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry) +#define jbd_rep_kmalloc(size, flags) \ + __jbd_kmalloc(__FUNCTION__, (size), (flags), 1) + +#define JFS_MIN_JOURNAL_BLOCKS 1024 + +#ifdef __KERNEL__ +typedef struct handle_s handle_t; /* Atomic operation type */ +typedef struct journal_s journal_t; /* Journal control structure */ +#endif + +/* + * Internal structures used by the logging mechanism: + */ + +#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ + +/* + * On-disk structures + */ + +/* + * Descriptor block types: + */ + +#define JFS_DESCRIPTOR_BLOCK 1 +#define JFS_COMMIT_BLOCK 2 +#define JFS_SUPERBLOCK_V1 3 +#define JFS_SUPERBLOCK_V2 4 +#define JFS_REVOKE_BLOCK 5 + +/* + * Standard header for all descriptor blocks: + */ +typedef struct journal_header_s +{ + __u32 h_magic; + __u32 h_blocktype; + __u32 h_sequence; +} journal_header_t; + + +/* + * The block tag: used to describe a single buffer in the journal + */ +typedef struct journal_block_tag_s +{ + __u32 t_blocknr; /* The on-disk block number */ + __u32 t_flags; /* See below */ +} journal_block_tag_t; + +/* + * The revoke descriptor: used on disk to describe a series of blocks to + * be revoked from the log + */ +typedef struct journal_revoke_header_s +{ + journal_header_t r_header; + int r_count; /* Count of bytes used in the block */ +} journal_revoke_header_t; + + +/* Definitions for the journal tag flags word: */ +#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */ +#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */ +#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */ +#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ + + +/* + * The journal superblock. All fields are in big-endian byte order. + */ +typedef struct journal_superblock_s +{ +/* 0x0000 */ + journal_header_t s_header; + +/* 0x000C */ + /* Static information describing the journal */ + __u32 s_blocksize; /* journal device blocksize */ + __u32 s_maxlen; /* total blocks in journal file */ + __u32 s_first; /* first block of log information */ + +/* 0x0018 */ + /* Dynamic information describing the current state of the log */ + __u32 s_sequence; /* first commit ID expected in log */ + __u32 s_start; /* blocknr of start of log */ + +/* 0x0020 */ + /* Error value, as set by journal_abort(). */ + __s32 s_errno; + +/* 0x0024 */ + /* Remaining fields are only valid in a version-2 superblock */ + __u32 s_feature_compat; /* compatible feature set */ + __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ +/* 0x0030 */ + __u8 s_uuid[16]; /* 128-bit uuid for journal */ + +/* 0x0040 */ + __u32 s_nr_users; /* Nr of filesystems sharing log */ + + __u32 s_dynsuper; /* Blocknr of dynamic superblock copy*/ + +/* 0x0048 */ + __u32 s_max_transaction; /* Limit of journal blocks per trans.*/ + __u32 s_max_trans_data; /* Limit of data blocks per trans. */ + +/* 0x0050 */ + __u32 s_padding[44]; + +/* 0x0100 */ + __u8 s_users[16*48]; /* ids of all fs'es sharing the log */ +/* 0x0400 */ +} journal_superblock_t; + +#define JFS_HAS_COMPAT_FEATURE(j,mask) \ + ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask)))) +#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \ + ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask)))) +#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \ + ((j)->j_format_version >= 2 && \ + ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask)))) + +#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001 + +/* Features known to this kernel version: */ +#define JFS_KNOWN_COMPAT_FEATURES 0 +#define JFS_KNOWN_ROCOMPAT_FEATURES 0 +#define JFS_KNOWN_INCOMPAT_FEATURES JFS_FEATURE_INCOMPAT_REVOKE + +#ifdef __KERNEL__ + +#include <linux/fs.h> +#include <linux/sched.h> + +#define JBD_ASSERTIONS +#ifdef JBD_ASSERTIONS +#define J_ASSERT(assert) \ +do { \ + if (!(assert)) { \ + printk (KERN_EMERG \ + "Assertion failure in %s() at %s:%d: \"%s\"\n", \ + __FUNCTION__, __FILE__, __LINE__, # assert); \ + BUG(); \ + } \ +} while (0) + +#if defined(CONFIG_BUFFER_DEBUG) +void buffer_assertion_failure(struct buffer_head *bh); +#define J_ASSERT_BH(bh, expr) \ + do { \ + if (!(expr)) \ + buffer_assertion_failure(bh); \ + J_ASSERT(expr); \ + } while (0) +#define J_ASSERT_JH(jh, expr) J_ASSERT_BH(jh2bh(jh), expr) +#else +#define J_ASSERT_BH(bh, expr) J_ASSERT(expr) +#define J_ASSERT_JH(jh, expr) J_ASSERT(expr) +#endif + +#else +#define J_ASSERT(assert) +#endif /* JBD_ASSERTIONS */ + +enum jbd_state_bits { + BH_JWrite + = BH_PrivateStart, /* 1 if being written to log (@@@ DEBUGGING) */ + BH_Freed, /* 1 if buffer has been freed (truncated) */ + BH_Revoked, /* 1 if buffer has been revoked from the log */ + BH_RevokeValid, /* 1 if buffer revoked flag is valid */ + BH_JBDDirty, /* 1 if buffer is dirty but journaled */ +}; + +/* Return true if the buffer is one which JBD is managing */ +static inline int buffer_jbd(struct buffer_head *bh) +{ + return __buffer_state(bh, JBD); +} + +static inline struct buffer_head *jh2bh(struct journal_head *jh) +{ + return jh->b_bh; +} + +static inline struct journal_head *bh2jh(struct buffer_head *bh) +{ + return bh->b_private; +} + +struct jbd_revoke_table_s; + +/* The handle_t type represents a single atomic update being performed + * by some process. All filesystem modifications made by the process go + * through this handle. Recursive operations (such as quota operations) + * are gathered into a single update. + * + * The buffer credits field is used to account for journaled buffers + * being modified by the running process. To ensure that there is + * enough log space for all outstanding operations, we need to limit the + * number of outstanding buffers possible at any time. When the + * operation completes, any buffer credits not used are credited back to + * the transaction, so that at all times we know how many buffers the + * outstanding updates on a transaction might possibly touch. */ + +struct handle_s +{ + /* Which compound transaction is this update a part of? */ + transaction_t * h_transaction; + + /* Number of remaining buffers we are allowed to dirty: */ + int h_buffer_credits; + + /* Reference count on this handle */ + int h_ref; + + /* Field for caller's use to track errors through large fs + operations */ + int h_err; + + /* Flags */ + unsigned int h_sync: 1; /* sync-on-close */ + unsigned int h_jdata: 1; /* force data journaling */ + unsigned int h_aborted: 1; /* fatal error on handle */ +}; + + +/* The transaction_t type is the guts of the journaling mechanism. It + * tracks a compound transaction through its various states: + * + * RUNNING: accepting new updates + * LOCKED: Updates still running but we don't accept new ones + * RUNDOWN: Updates are tidying up but have finished requesting + * new buffers to modify (state not used for now) + * FLUSH: All updates complete, but we are still writing to disk + * COMMIT: All data on disk, writing commit record + * FINISHED: We still have to keep the transaction for checkpointing. + * + * The transaction keeps track of all of the buffers modified by a + * running transaction, and all of the buffers committed but not yet + * flushed to home for finished transactions. + */ + +struct transaction_s +{ + /* Pointer to the journal for this transaction. */ + journal_t * t_journal; + + /* Sequence number for this transaction */ + tid_t t_tid; + + /* Transaction's current state */ + enum { + T_RUNNING, + T_LOCKED, + T_RUNDOWN, + T_FLUSH, + T_COMMIT, + T_FINISHED + } t_state; + + /* Where in the log does this transaction's commit start? */ + unsigned long t_log_start; + + /* Doubly-linked circular list of all inodes owned by this + transaction */ /* AKPM: unused */ + struct inode * t_ilist; + + /* Number of buffers on the t_buffers list */ + int t_nr_buffers; + + /* Doubly-linked circular list of all buffers reserved but not + yet modified by this transaction */ + struct journal_head * t_reserved_list; + + /* Doubly-linked circular list of all metadata buffers owned by this + transaction */ + struct journal_head * t_buffers; + + /* + * Doubly-linked circular list of all data buffers still to be + * flushed before this transaction can be committed. + * Protected by journal_datalist_lock. + */ + struct journal_head * t_sync_datalist; + + /* + * Doubly-linked circular list of all writepage data buffers + * still to be written before this transaction can be committed. + * Protected by journal_datalist_lock. + */ + struct journal_head * t_async_datalist; + + /* Doubly-linked circular list of all forget buffers (superceded + buffers which we can un-checkpoint once this transaction + commits) */ + struct journal_head * t_forget; + + /* + * Doubly-linked circular list of all buffers still to be + * flushed before this transaction can be checkpointed. + */ + /* Protected by journal_datalist_lock */ + struct journal_head * t_checkpoint_list; + + /* Doubly-linked circular list of temporary buffers currently + undergoing IO in the log */ + struct journal_head * t_iobuf_list; + + /* Doubly-linked circular list of metadata buffers being + shadowed by log IO. The IO buffers on the iobuf list and the + shadow buffers on this list match each other one for one at + all times. */ + struct journal_head * t_shadow_list; + + /* Doubly-linked circular list of control buffers being written + to the log. */ + struct journal_head * t_log_list; + + /* Number of outstanding updates running on this transaction */ + int t_updates; + + /* Number of buffers reserved for use by all handles in this + * transaction handle but not yet modified. */ + int t_outstanding_credits; + + /* + * Forward and backward links for the circular list of all + * transactions awaiting checkpoint. + */ + /* Protected by journal_datalist_lock */ + transaction_t *t_cpnext, *t_cpprev; + + /* When will the transaction expire (become due for commit), in + * jiffies ? */ + unsigned long t_expires; + + /* How many handles used this transaction? */ + int t_handle_count; +}; + + +/* The journal_t maintains all of the journaling state information for a + * single filesystem. It is linked to from the fs superblock structure. + * + * We use the journal_t to keep track of all outstanding transaction + * activity on the filesystem, and to manage the state of the log + * writing process. */ + +struct journal_s +{ + /* General journaling state flags */ + unsigned long j_flags; + + /* Is there an outstanding uncleared error on the journal (from + * a prior abort)? */ + int j_errno; + + /* The superblock buffer */ + struct buffer_head * j_sb_buffer; + journal_superblock_t * j_superblock; + + /* Version of the superblock format */ + int j_format_version; + + /* Number of processes waiting to create a barrier lock */ + int j_barrier_count; + + /* The barrier lock itself */ + struct semaphore j_barrier; + + /* Transactions: The current running transaction... */ + transaction_t * j_running_transaction; + + /* ... the transaction we are pushing to disk ... */ + transaction_t * j_committing_transaction; + + /* ... and a linked circular list of all transactions waiting + * for checkpointing. */ + /* Protected by journal_datalist_lock */ + transaction_t * j_checkpoint_transactions; + + /* Wait queue for waiting for a locked transaction to start + committing, or for a barrier lock to be released */ + wait_queue_head_t j_wait_transaction_locked; + + /* Wait queue for waiting for checkpointing to complete */ + wait_queue_head_t j_wait_logspace; + + /* Wait queue for waiting for commit to complete */ + wait_queue_head_t j_wait_done_commit; + + /* Wait queue to trigger checkpointing */ + wait_queue_head_t j_wait_checkpoint; + + /* Wait queue to trigger commit */ + wait_queue_head_t j_wait_commit; + + /* Wait queue to wait for updates to complete */ + wait_queue_head_t j_wait_updates; + + /* Semaphore for locking against concurrent checkpoints */ + struct semaphore j_checkpoint_sem; + + /* The main journal lock, used by lock_journal() */ + struct semaphore j_sem; + + /* Journal head: identifies the first unused block in the journal. */ + unsigned long j_head; + + /* Journal tail: identifies the oldest still-used block in the + * journal. */ + unsigned long j_tail; + + /* Journal free: how many free blocks are there in the journal? */ + unsigned long j_free; + + /* Journal start and end: the block numbers of the first usable + * block and one beyond the last usable block in the journal. */ + unsigned long j_first, j_last; + + /* Device, blocksize and starting block offset for the location + * where we store the journal. */ + kdev_t j_dev; + int j_blocksize; + unsigned int j_blk_offset; + + /* Device which holds the client fs. For internal journal this + * will be equal to j_dev. */ + kdev_t j_fs_dev; + + /* Total maximum capacity of the journal region on disk. */ + unsigned int j_maxlen; + + /* Optional inode where we store the journal. If present, all + * journal block numbers are mapped into this inode via + * bmap(). */ + struct inode * j_inode; + + /* Sequence number of the oldest transaction in the log */ + tid_t j_tail_sequence; + /* Sequence number of the next transaction to grant */ + tid_t j_transaction_sequence; + /* Sequence number of the most recently committed transaction */ + tid_t j_commit_sequence; + /* Sequence number of the most recent transaction wanting commit */ + tid_t j_commit_request; + + /* Journal uuid: identifies the object (filesystem, LVM volume + * etc) backed by this journal. This will eventually be + * replaced by an array of uuids, allowing us to index multiple + * devices within a single journal and to perform atomic updates + * across them. */ + + __u8 j_uuid[16]; + + /* Pointer to the current commit thread for this journal */ + struct task_struct * j_task; + + /* Maximum number of metadata buffers to allow in a single + * compound commit transaction */ + int j_max_transaction_buffers; + + /* What is the maximum transaction lifetime before we begin a + * commit? */ + unsigned long j_commit_interval; + + /* The timer used to wakeup the commit thread: */ + struct timer_list * j_commit_timer; + int j_commit_timer_active; + + /* Link all journals together - system-wide */ + struct list_head j_all_journals; + + /* The revoke table: maintains the list of revoked blocks in the + current transaction. */ + struct jbd_revoke_table_s *j_revoke; +}; + +/* + * Journal flag definitions + */ +#define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */ +#define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */ +#define JFS_ACK_ERR 0x004 /* The errno in the sb has been acked */ +#define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */ +#define JFS_LOADED 0x010 /* The journal superblock has been loaded */ + +/* + * Function declarations for the journaling transaction and buffer + * management + */ + +/* Filing buffers */ +extern void __journal_unfile_buffer(struct journal_head *); +extern void journal_unfile_buffer(struct journal_head *); +extern void __journal_refile_buffer(struct journal_head *); +extern void journal_refile_buffer(struct journal_head *); +extern void __journal_file_buffer(struct journal_head *, transaction_t *, int); +extern void __journal_free_buffer(struct journal_head *bh); +extern void journal_file_buffer(struct journal_head *, transaction_t *, int); +extern void __journal_clean_data_list(transaction_t *transaction); + +/* Log buffer allocation */ +extern struct journal_head * journal_get_descriptor_buffer(journal_t *); +extern unsigned long journal_next_log_block(journal_t *); + +/* Commit management */ +extern void journal_commit_transaction(journal_t *); + +/* Checkpoint list management */ +int __journal_clean_checkpoint_list(journal_t *journal); +extern void journal_remove_checkpoint(struct journal_head *); +extern void __journal_remove_checkpoint(struct journal_head *); +extern void journal_insert_checkpoint(struct journal_head *, transaction_t *); +extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *); + +/* Buffer IO */ +extern int +journal_write_metadata_buffer(transaction_t *transaction, + struct journal_head *jh_in, + struct journal_head **jh_out, + int blocknr); + +/* Transaction locking */ +extern void __wait_on_journal (journal_t *); + +/* + * Journal locking. + * + * We need to lock the journal during transaction state changes so that + * nobody ever tries to take a handle on the running transaction while + * we are in the middle of moving it to the commit phase. + * + * Note that the locking is completely interrupt unsafe. We never touch + * journal structures from interrupts. + * + * In 2.2, the BKL was required for lock_journal. This is no longer + * the case. + */ + +static inline void lock_journal(journal_t *journal) +{ + down(&journal->j_sem); +} + +/* This returns zero if we acquired the semaphore */ +static inline int try_lock_journal(journal_t * journal) +{ + return down_trylock(&journal->j_sem); +} + +static inline void unlock_journal(journal_t * journal) +{ + up(&journal->j_sem); +} + + +static inline handle_t *journal_current_handle(void) +{ + return current->journal_info; +} + +/* The journaling code user interface: + * + * Create and destroy handles + * Register buffer modifications against the current transaction. + */ + +extern handle_t *journal_start(journal_t *, int nblocks); +extern handle_t *journal_try_start(journal_t *, int nblocks); +extern int journal_restart (handle_t *, int nblocks); +extern int journal_extend (handle_t *, int nblocks); +extern int journal_get_write_access (handle_t *, struct buffer_head *); +extern int journal_get_create_access (handle_t *, struct buffer_head *); +extern int journal_get_undo_access (handle_t *, struct buffer_head *); +extern int journal_dirty_data (handle_t *, + struct buffer_head *, int async); +extern int journal_dirty_metadata (handle_t *, struct buffer_head *); +extern void journal_release_buffer (handle_t *, struct buffer_head *); +extern void journal_forget (handle_t *, struct buffer_head *); +extern void journal_sync_buffer (struct buffer_head *); +extern int journal_flushpage(journal_t *, struct page *, unsigned long); +extern int journal_try_to_free_buffers(journal_t *, struct page *, int); +extern int journal_stop(handle_t *); +extern int journal_flush (journal_t *); + +extern void journal_lock_updates (journal_t *); +extern void journal_unlock_updates (journal_t *); + +extern journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev, + int start, int len, int bsize); +extern journal_t * journal_init_inode (struct inode *); +extern int journal_update_format (journal_t *); +extern int journal_check_used_features + (journal_t *, unsigned long, unsigned long, unsigned long); +extern int journal_check_available_features + (journal_t *, unsigned long, unsigned long, unsigned long); +extern int journal_set_features + (journal_t *, unsigned long, unsigned long, unsigned long); +extern int journal_create (journal_t *); +extern int journal_load (journal_t *journal); +extern void journal_destroy (journal_t *); +extern int journal_recover (journal_t *journal); +extern int journal_wipe (journal_t *, int); +extern int journal_skip_recovery (journal_t *); +extern void journal_update_superblock (journal_t *, int); +extern void __journal_abort (journal_t *); +extern void journal_abort (journal_t *, int); +extern int journal_errno (journal_t *); +extern void journal_ack_err (journal_t *); +extern int journal_clear_err (journal_t *); +extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr); +extern int journal_force_commit(journal_t *journal); + +/* + * journal_head management + */ +extern struct journal_head + *journal_add_journal_head(struct buffer_head *bh); +extern void journal_remove_journal_head(struct buffer_head *bh); +extern void __journal_remove_journal_head(struct buffer_head *bh); +extern void journal_unlock_journal_head(struct journal_head *jh); + +/* Primary revoke support */ +#define JOURNAL_REVOKE_DEFAULT_HASH 256 +extern int journal_init_revoke(journal_t *, int); +extern void journal_destroy_revoke_caches(void); +extern int journal_init_revoke_caches(void); + +extern void journal_destroy_revoke(journal_t *); +extern int journal_revoke (handle_t *, + unsigned long, struct buffer_head *); +extern int journal_cancel_revoke(handle_t *, struct journal_head *); +extern void journal_write_revoke_records(journal_t *, transaction_t *); + +/* Recovery revoke support */ +extern int journal_set_revoke(journal_t *, unsigned long, tid_t); +extern int journal_test_revoke(journal_t *, unsigned long, tid_t); +extern void journal_clear_revoke(journal_t *); +extern void journal_brelse_array(struct buffer_head *b[], int n); + +/* The log thread user interface: + * + * Request space in the current transaction, and force transaction commit + * transitions on demand. + */ + +extern int log_space_left (journal_t *); /* Called with journal locked */ +extern tid_t log_start_commit (journal_t *, transaction_t *); +extern void log_wait_commit (journal_t *, tid_t); +extern int log_do_checkpoint (journal_t *, int); + +extern void log_wait_for_space(journal_t *, int nblocks); +extern void __journal_drop_transaction(journal_t *, transaction_t *); +extern int cleanup_journal_tail(journal_t *); + +/* Reduce journal memory usage by flushing */ +extern void shrink_journal_memory(void); + +/* Debugging code only: */ + +#define jbd_ENOSYS() \ +do { \ + printk (KERN_ERR "JBD unimplemented function " __FUNCTION__); \ + current->state = TASK_UNINTERRUPTIBLE; \ + schedule(); \ +} while (1) + +/* + * is_journal_abort + * + * Simple test wrapper function to test the JFS_ABORT state flag. This + * bit, when set, indicates that we have had a fatal error somewhere, + * either inside the journaling layer or indicated to us by the client + * (eg. ext3), and that we and should not commit any further + * transactions. + */ + +static inline int is_journal_aborted(journal_t *journal) +{ + return journal->j_flags & JFS_ABORT; +} + +static inline int is_handle_aborted(handle_t *handle) +{ + if (handle->h_aborted) + return 1; + return is_journal_aborted(handle->h_transaction->t_journal); +} + +static inline void journal_abort_handle(handle_t *handle) +{ + handle->h_aborted = 1; +} + +/* Not all architectures define BUG() */ +#ifndef BUG + #define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + * ((char *) 0) = 0; \ + } while (0) +#endif /* BUG */ + +#endif /* __KERNEL__ */ + +/* Comparison functions for transaction IDs: perform comparisons using + * modulo arithmetic so that they work over sequence number wraps. */ + +static inline int tid_gt(tid_t x, tid_t y) +{ + int difference = (x - y); + return (difference > 0); +} + +static inline int tid_geq(tid_t x, tid_t y) +{ + int difference = (x - y); + return (difference >= 0); +} + +extern int journal_blocks_per_page(struct inode *inode); + +/* + * Definitions which augment the buffer_head layer + */ + +/* journaling buffer types */ +#define BJ_None 0 /* Not journaled */ +#define BJ_SyncData 1 /* Normal data: flush before commit */ +#define BJ_AsyncData 2 /* writepage data: wait on it before commit */ +#define BJ_Metadata 3 /* Normal journaled metadata */ +#define BJ_Forget 4 /* Buffer superceded by this transaction */ +#define BJ_IO 5 /* Buffer is for temporary IO use */ +#define BJ_Shadow 6 /* Buffer contents being shadowed to the log */ +#define BJ_LogCtl 7 /* Buffer contains log descriptors */ +#define BJ_Reserved 8 /* Buffer is reserved for access by journal */ +#define BJ_Types 9 + +extern int jbd_blocks_per_page(struct inode *inode); + +#ifdef __KERNEL__ + +extern spinlock_t jh_splice_lock; +/* + * Once `expr1' has been found true, take jh_splice_lock + * and then reevaluate everything. + */ +#define SPLICE_LOCK(expr1, expr2) \ + ({ \ + int ret = (expr1); \ + if (ret) { \ + spin_lock(&jh_splice_lock); \ + ret = (expr1) && (expr2); \ + spin_unlock(&jh_splice_lock); \ + } \ + ret; \ + }) + +/* + * A number of buffer state predicates. They test for + * buffer_jbd() because they are used in core kernel code. + * + * These will be racy on SMP unless we're *sure* that the + * buffer won't be detached from the journalling system + * in parallel. + */ + +/* Return true if the buffer is on journal list `list' */ +static inline int buffer_jlist_eq(struct buffer_head *bh, int list) +{ + return SPLICE_LOCK(buffer_jbd(bh), bh2jh(bh)->b_jlist == list); +} + +/* Return true if this bufer is dirty wrt the journal */ +static inline int buffer_jdirty(struct buffer_head *bh) +{ + return buffer_jbd(bh) && __buffer_state(bh, JBDDirty); +} + +/* Return true if it's a data buffer which journalling is managing */ +static inline int buffer_jbd_data(struct buffer_head *bh) +{ + return SPLICE_LOCK(buffer_jbd(bh), + bh2jh(bh)->b_jlist == BJ_SyncData || + bh2jh(bh)->b_jlist == BJ_AsyncData); +} + +#ifdef CONFIG_SMP +#define assert_spin_locked(lock) J_ASSERT(spin_is_locked(lock)) +#else +#define assert_spin_locked(lock) do {} while(0) +#endif + +#define buffer_trace_init(bh) do {} while (0) +#define print_buffer_fields(bh) do {} while (0) +#define print_buffer_trace(bh) do {} while (0) +#define BUFFER_TRACE(bh, info) do {} while (0) +#define BUFFER_TRACE2(bh, bh2, info) do {} while (0) +#define JBUFFER_TRACE(jh, info) do {} while (0) + +#endif /* __KERNEL__ */ + +#endif /* CONFIG_JBD || CONFIG_JBD_MODULE || !__KERNEL__ */ + +/* + * Compatibility no-ops which allow the kernel to compile without CONFIG_JBD + * go here. + */ + +#if defined(__KERNEL__) && !(defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE)) + +#define J_ASSERT(expr) do {} while (0) +#define J_ASSERT_BH(bh, expr) do {} while (0) +#define buffer_jbd(bh) 0 +#define buffer_jlist_eq(bh, val) 0 +#define journal_buffer_journal_lru(bh) 0 + +#endif /* defined(__KERNEL__) && !defined(CONFIG_JBD) */ +#endif /* _LINUX_JBD_H */ diff -u --recursive --new-file v2.4.14/linux/include/linux/journal-head.h linux/include/linux/journal-head.h --- v2.4.14/linux/include/linux/journal-head.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/journal-head.h Fri Nov 9 14:25:04 2001 @@ -0,0 +1,70 @@ +/* + * include/linux/journal-head.h + * + * buffer_head fields for JBD + * + * 27 May 2001 ANdrew Morton <andrewm@uow.edu.au> + * Created - pulled out of fs.h + */ + +#ifndef JOURNAL_HEAD_H_INCLUDED +#define JOURNAL_HEAD_H_INCLUDED + +typedef unsigned int tid_t; /* Unique transaction ID */ +typedef struct transaction_s transaction_t; /* Compound transaction type */ +struct buffer_head; + +struct journal_head { +#ifndef CONFIG_JBD_UNIFIED_BUFFERS + /* Points back to our buffer_head. */ + struct buffer_head *b_bh; +#endif + + /* Reference count - see description in journal.c */ + int b_jcount; + + /* Journaling list for this buffer */ + unsigned b_jlist; + + /* Copy of the buffer data frozen for writing to the log. */ + char * b_frozen_data; + + /* Pointer to a saved copy of the buffer containing no + uncommitted deallocation references, so that allocations can + avoid overwriting uncommitted deletes. */ + char * b_committed_data; + + /* Pointer to the compound transaction which owns this buffer's + metadata: either the running transaction or the committing + transaction (if there is one). Only applies to buffers on a + transaction's data or metadata journaling list. */ + /* Protected by journal_datalist_lock */ + transaction_t * b_transaction; + + /* Pointer to the running compound transaction which is + currently modifying the buffer's metadata, if there was + already a transaction committing it when the new transaction + touched it. */ + transaction_t * b_next_transaction; + + /* Doubly-linked list of buffers on a transaction's data, + metadata or forget queue. */ + /* Protected by journal_datalist_lock */ + struct journal_head *b_tnext, *b_tprev; + + /* + * Pointer to the compound transaction against which this buffer + * is checkpointed. Only dirty buffers can be checkpointed. + */ + /* Protected by journal_datalist_lock */ + transaction_t * b_cp_transaction; + + /* + * Doubly-linked list of buffers still remaining to be flushed + * before an old transaction can be checkpointed. + */ + /* Protected by journal_datalist_lock */ + struct journal_head *b_cpnext, *b_cpprev; +}; + +#endif /* JOURNAL_HEAD_H_INCLUDED */ diff -u --recursive --new-file v2.4.14/linux/include/linux/kernel.h linux/include/linux/kernel.h --- v2.4.14/linux/include/linux/kernel.h Thu Oct 18 13:47:37 2001 +++ linux/include/linux/kernel.h Fri Nov 9 14:47:04 2001 @@ -60,9 +60,11 @@ extern long simple_strtol(const char *,char **,unsigned int); extern unsigned long long simple_strtoull(const char *,char **,unsigned int); extern long long simple_strtoll(const char *,char **,unsigned int); -extern int sprintf(char * buf, const char * fmt, ...); +extern int sprintf(char * buf, const char * fmt, ...) + __attribute__ ((format (printf, 2, 3))); extern int vsprintf(char *buf, const char *, va_list); -extern int snprintf(char * buf, size_t size, const char *fmt, ...); +extern int snprintf(char * buf, size_t size, const char * fmt, ...) + __attribute__ ((format (printf, 3, 4))); extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); extern int sscanf(const char *, const char *, ...) diff -u --recursive --new-file v2.4.14/linux/include/linux/malloc.h linux/include/linux/malloc.h --- v2.4.14/linux/include/linux/malloc.h Mon Mar 5 19:29:29 2001 +++ linux/include/linux/malloc.h Fri Nov 9 13:45:35 2001 @@ -1,5 +1,7 @@ #ifndef _LINUX_MALLOC_H #define _LINUX_MALLOC_H +#warning linux/malloc.h is deprecated, use linux/slab.h instead. + #include <linux/slab.h> #endif /* _LINUX_MALLOC_H */ diff -u --recursive --new-file v2.4.14/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.4.14/linux/include/linux/mm.h Mon Nov 5 15:55:35 2001 +++ linux/include/linux/mm.h Fri Nov 9 14:55:40 2001 @@ -271,8 +271,8 @@ #define PG_uptodate 3 #define PG_dirty 4 #define PG_unused 5 -#define PG_active 6 -#define PG_inactive 7 +#define PG_lru 6 +#define PG_active 7 #define PG_slab 8 #define PG_skip 10 #define PG_highmem 11 @@ -320,14 +320,10 @@ #define PageActive(page) test_bit(PG_active, &(page)->flags) #define SetPageActive(page) set_bit(PG_active, &(page)->flags) #define ClearPageActive(page) clear_bit(PG_active, &(page)->flags) -#define TestandSetPageActive(page) test_and_set_bit(PG_active, &(page)->flags) -#define TestandClearPageActive(page) test_and_clear_bit(PG_active, &(page)->flags) -#define PageInactive(page) test_bit(PG_inactive, &(page)->flags) -#define SetPageInactive(page) set_bit(PG_inactive, &(page)->flags) -#define ClearPageInactive(page) clear_bit(PG_inactive, &(page)->flags) -#define TestandSetPageInactive(page) test_and_set_bit(PG_inactive, &(page)->flags) -#define TestandClearPageInactive(page) test_and_clear_bit(PG_inactive, &(page)->flags) +#define PageLRU(page) test_bit(PG_lru, &(page)->flags) +#define TestSetPageLRU(page) test_and_set_bit(PG_lru, &(page)->flags) +#define TestClearPageLRU(page) test_and_clear_bit(PG_lru, &(page)->flags) #ifdef CONFIG_HIGHMEM #define PageHighMem(page) test_bit(PG_highmem, &(page)->flags) diff -u --recursive --new-file v2.4.14/linux/include/linux/module.h linux/include/linux/module.h --- v2.4.14/linux/include/linux/module.h Thu Oct 18 13:47:38 2001 +++ linux/include/linux/module.h Fri Nov 9 14:47:04 2001 @@ -257,8 +257,6 @@ __attribute__ ((unused)) = sizeof(struct gtype##_id); \ static const struct gtype##_id * __module_##gtype##_table \ __attribute__ ((unused)) = name -#define MODULE_DEVICE_TABLE(type,name) \ - MODULE_GENERIC_TABLE(type##_device,name) /* * The following license idents are currently accepted as indicating free @@ -312,8 +310,15 @@ #define MODULE_SUPPORTED_DEVICE(name) #define MODULE_PARM(var,type) #define MODULE_PARM_DESC(var,desc) -#define MODULE_GENERIC_TABLE(gtype,name) -#define MODULE_DEVICE_TABLE(type,name) + +/* Create a dummy reference to the table to suppress gcc unused warnings. Put + * the reference in the .data.exit section which is discarded when code is built + * in, so the reference does not bloat the running kernel. Note: cannot be + * const, other exit data may be writable. + */ +#define MODULE_GENERIC_TABLE(gtype,name) \ +static struct gtype##_id * __module_##gtype##_table \ + __attribute__ ((unused, __section__(".data.exit"))) = name #ifndef __GENKSYMS__ @@ -327,6 +332,9 @@ #endif /* !__GENKSYMS__ */ #endif /* MODULE */ + +#define MODULE_DEVICE_TABLE(type,name) \ + MODULE_GENERIC_TABLE(type##_device,name) /* Export a symbol either from the kernel or a module. diff -u --recursive --new-file v2.4.14/linux/include/linux/mtd/jedec.h linux/include/linux/mtd/jedec.h --- v2.4.14/linux/include/linux/mtd/jedec.h Tue Jul 4 10:10:52 2000 +++ linux/include/linux/mtd/jedec.h Fri Nov 9 14:29:40 2001 @@ -7,7 +7,7 @@ * * See the AMD flash databook for information on how to operate the interface. * - * $Id: jedec.h,v 1.1 2000/07/04 07:21:51 jgg Exp $ + * $Id: jedec.h,v 1.2 2001/11/06 14:37:36 dwmw2 Exp $ */ #ifndef __LINUX_MTD_JEDEC_H__ @@ -63,7 +63,5 @@ struct jedec_flash_chip chips[MAX_JEDEC_CHIPS]; }; - -extern const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); #endif diff -u --recursive --new-file v2.4.14/linux/include/linux/mtio.h linux/include/linux/mtio.h --- v2.4.14/linux/include/linux/mtio.h Thu Oct 18 13:49:26 2001 +++ linux/include/linux/mtio.h Fri Nov 9 14:47:56 2001 @@ -325,7 +325,8 @@ #define GMT_DR_OPEN(x) ((x) & 0x00040000) /* door open (no tape) */ /* #define GMT_ ? ((x) & 0x00020000) */ #define GMT_IM_REP_EN(x) ((x) & 0x00010000) /* immediate report mode */ -/* 16 generic status bits unused */ +#define GMT_CLN(x) ((x) & 0x00008000) /* cleaning requested */ +/* 15 generic status bits unused */ /* SCSI-tape specific definitions */ @@ -349,6 +350,7 @@ #define MT_ST_TIMEOUTS 0x70000000 #define MT_ST_SET_TIMEOUT (MT_ST_TIMEOUTS | 0x000000) #define MT_ST_SET_LONG_TIMEOUT (MT_ST_TIMEOUTS | 0x100000) +#define MT_ST_SET_CLN 0x80000000 #define MT_ST_BUFFER_WRITES 0x1 #define MT_ST_ASYNC_WRITES 0x2 @@ -363,6 +365,7 @@ #define MT_ST_CAN_PARTITIONS 0x400 #define MT_ST_SCSI2LOGICAL 0x800 #define MT_ST_SYSV 0x1000 +#define MT_ST_NOWAIT 0x2000 /* The mode parameters to be controlled. Parameter chosen with bits 20-28 */ #define MT_ST_CLEAR_DEFAULT 0xfffff diff -u --recursive --new-file v2.4.14/linux/include/linux/nfs_flushd.h linux/include/linux/nfs_flushd.h --- v2.4.14/linux/include/linux/nfs_flushd.h Thu Oct 18 13:49:28 2001 +++ linux/include/linux/nfs_flushd.h Fri Nov 9 14:48:15 2001 @@ -9,11 +9,9 @@ /* * Counters of total number and pending number of requests. - * When the total number of requests exceeds the soft limit, we start - * flushing out requests. If it exceeds the hard limit, we stall until - * it drops again. + * When the total number of requests exceeds the hard limit, we stall + * until it drops again. */ -#define MAX_REQUEST_SOFT 192 #define MAX_REQUEST_HARD 256 /* @@ -36,8 +34,6 @@ extern void nfs_reqlist_free(struct nfs_server *); extern int nfs_reqlist_init(struct nfs_server *); extern void nfs_reqlist_exit(struct nfs_server *); -extern void inode_schedule_scan(struct inode *, unsigned long); -extern void inode_remove_flushd(struct inode *); extern void nfs_wake_flushd(void); /* diff -u --recursive --new-file v2.4.14/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h --- v2.4.14/linux/include/linux/nfs_fs.h Thu Oct 18 13:48:45 2001 +++ linux/include/linux/nfs_fs.h Fri Nov 9 15:00:06 2001 @@ -207,10 +207,14 @@ */ extern int nfs_sync_file(struct inode *, struct file *, unsigned long, unsigned int, int); extern int nfs_flush_file(struct inode *, struct file *, unsigned long, unsigned int, int); -extern int nfs_flush_timeout(struct inode *, int); +extern int nfs_flush_list(struct list_head *, int, int); +extern int nfs_scan_lru_dirty(struct nfs_server *, struct list_head *); +extern int nfs_scan_lru_dirty_timeout(struct nfs_server *, struct list_head *); #ifdef CONFIG_NFS_V3 extern int nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int); -extern int nfs_commit_timeout(struct inode *, int); +extern int nfs_commit_list(struct list_head *, int); +extern int nfs_scan_lru_commit(struct nfs_server *, struct list_head *); +extern int nfs_scan_lru_commit_timeout(struct nfs_server *, struct list_head *); #endif static inline int @@ -257,7 +261,9 @@ */ extern int nfs_readpage(struct file *, struct page *); extern int nfs_pagein_inode(struct inode *, unsigned long, unsigned int); -extern int nfs_pagein_timeout(struct inode *); +extern int nfs_pagein_list(struct list_head *, int); +extern int nfs_scan_lru_read(struct nfs_server *, struct list_head *); +extern int nfs_scan_lru_read_timeout(struct nfs_server *, struct list_head *); /* * linux/fs/mount_clnt.c diff -u --recursive --new-file v2.4.14/linux/include/linux/nfs_fs_sb.h linux/include/linux/nfs_fs_sb.h --- v2.4.14/linux/include/linux/nfs_fs_sb.h Tue Apr 25 17:28:56 2000 +++ linux/include/linux/nfs_fs_sb.h Fri Nov 9 14:47:04 2001 @@ -1,6 +1,8 @@ #ifndef _NFS_FS_SB #define _NFS_FS_SB +#include <linux/list.h> + /* * NFS client parameters stored in the superblock. */ @@ -21,6 +23,10 @@ unsigned int namelen; char * hostname; /* remote hostname */ struct nfs_reqlist * rw_requests; /* async read/write requests */ + struct list_head lru_read, + lru_dirty, + lru_commit, + lru_busy; }; /* diff -u --recursive --new-file v2.4.14/linux/include/linux/nfs_page.h linux/include/linux/nfs_page.h --- v2.4.14/linux/include/linux/nfs_page.h Thu Oct 18 13:49:33 2001 +++ linux/include/linux/nfs_page.h Fri Nov 9 15:00:53 2001 @@ -23,6 +23,7 @@ struct nfs_page { struct list_head wb_hash, /* Inode */ + wb_lru, /* superblock lru list */ wb_list, /* Defines state of page: */ *wb_list_head; /* read/write/commit */ struct file *wb_file; @@ -40,33 +41,39 @@ #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) -extern struct nfs_page *nfs_create_request(struct file *file, - struct inode *inode, - struct page *page, - unsigned int offset, - unsigned int count); +extern struct nfs_page *nfs_create_request(struct file *, struct inode *, + struct page *, + unsigned int, unsigned int); extern void nfs_release_request(struct nfs_page *req); -extern void nfs_list_add_request(struct nfs_page *req, - struct list_head *head); -extern void nfs_list_remove_request(struct nfs_page *req); - -extern int nfs_scan_list_timeout(struct list_head *head, - struct list_head *dst, - struct inode *inode); -extern int nfs_scan_list(struct list_head *src, struct list_head *dst, - struct file *file, unsigned long idx_start, - unsigned int npages); -extern int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, - unsigned int maxpages); +extern void nfs_list_add_request(struct nfs_page *, struct list_head *); + +extern int nfs_scan_lru(struct list_head *, struct list_head *, int); +extern int nfs_scan_lru_timeout(struct list_head *, struct list_head *, int); +extern int nfs_scan_list(struct list_head *, struct list_head *, + struct file *, unsigned long, unsigned int); +extern int nfs_coalesce_requests(struct list_head *, struct list_head *, + unsigned int); +extern int nfs_wait_on_request(struct nfs_page *); extern spinlock_t nfs_wreq_lock; /* + * Lock the page of an asynchronous request without incrementing the wb_count + */ +static inline int +nfs_lock_request_dontget(struct nfs_page *req) +{ + if (test_and_set_bit(PG_BUSY, &req->wb_flags)) + return 0; + return 1; +} + +/* * Lock the page of an asynchronous request */ -static __inline__ int +static inline int nfs_lock_request(struct nfs_page *req) { if (test_and_set_bit(PG_BUSY, &req->wb_flags)) @@ -75,7 +82,7 @@ return 1; } -static __inline__ void +static inline void nfs_unlock_request(struct nfs_page *req) { if (!NFS_WBACK_BUSY(req)) { @@ -86,20 +93,57 @@ clear_bit(PG_BUSY, &req->wb_flags); smp_mb__after_clear_bit(); if (waitqueue_active(&req->wb_wait)) - wake_up(&req->wb_wait); + wake_up_all(&req->wb_wait); nfs_release_request(req); } -static __inline__ struct nfs_page * +/** + * nfs_list_remove_request - Remove a request from its wb_list + * @req: request + */ +static inline void +nfs_list_remove_request(struct nfs_page *req) +{ + if (list_empty(&req->wb_list)) + return; + if (!NFS_WBACK_BUSY(req)) { + printk(KERN_ERR "NFS: unlocked request attempted removed from list!\n"); + BUG(); + } + list_del_init(&req->wb_list); + req->wb_list_head = NULL; +} + +static inline struct nfs_page * nfs_list_entry(struct list_head *head) { return list_entry(head, struct nfs_page, wb_list); } -static __inline__ struct nfs_page * +static inline struct nfs_page * nfs_inode_wb_entry(struct list_head *head) { return list_entry(head, struct nfs_page, wb_hash); +} + +static inline void +__nfs_add_lru(struct list_head *head, struct nfs_page *req) +{ + list_add_tail(&req->wb_lru, head); +} + +static inline void +__nfs_del_lru(struct nfs_page *req) +{ + if (list_empty(&req->wb_lru)) + return; + list_del_init(&req->wb_lru); +} + +static inline struct nfs_page * +nfs_lru_entry(struct list_head *head) +{ + return list_entry(head, struct nfs_page, wb_lru); } #endif /* _LINUX_NFS_PAGE_H */ diff -u --recursive --new-file v2.4.14/linux/include/linux/parport.h linux/include/linux/parport.h --- v2.4.14/linux/include/linux/parport.h Thu Oct 11 08:02:26 2001 +++ linux/include/linux/parport.h Fri Nov 9 14:11:15 2001 @@ -11,8 +11,8 @@ /* Start off with user-visible constants */ -/* Maximum of 8 ports per machine */ -#define PARPORT_MAX 8 +/* Maximum of 16 ports per machine */ +#define PARPORT_MAX 16 /* Magic numbers */ #define PARPORT_IRQ_NONE -1 diff -u --recursive --new-file v2.4.14/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h --- v2.4.14/linux/include/linux/pci_ids.h Mon Nov 5 15:55:35 2001 +++ linux/include/linux/pci_ids.h Fri Nov 9 14:11:15 2001 @@ -383,6 +383,11 @@ #define PCI_DEVICE_ID_AMD_VIPER_7411 0x7411 #define PCI_DEVICE_ID_AMD_VIPER_7413 0x7413 #define PCI_DEVICE_ID_AMD_VIPER_7414 0x7414 +#define PCI_DEVICE_ID_AMD_VIPER_7440 0x7440 +#define PCI_DEVICE_ID_AMD_VIPER_7441 0x7441 +#define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443 +#define PCI_DEVICE_ID_AMD_VIPER_7448 0x7448 +#define PCI_DEVICE_ID_AMD_VIPER_7449 0x7449 #define PCI_VENDOR_ID_TRIDENT 0x1023 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 @@ -420,6 +425,7 @@ #define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520 #define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521 #define PCI_DEVICE_ID_MATROX_G400 0x0525 +#define PCI_DEVICE_ID_MATROX_G550 0x2527 #define PCI_DEVICE_ID_MATROX_VIA 0x4536 #define PCI_VENDOR_ID_CT 0x102c @@ -452,6 +458,7 @@ #define PCI_DEVICE_ID_SI_300 0x0300 #define PCI_DEVICE_ID_SI_315H 0x0310 #define PCI_DEVICE_ID_SI_315 0x0315 +#define PCI_DEVICE_ID_SI_315PRO 0x0325 #define PCI_DEVICE_ID_SI_530 0x0530 #define PCI_DEVICE_ID_SI_540 0x0540 #define PCI_DEVICE_ID_SI_550 0x0550 @@ -465,12 +472,12 @@ #define PCI_DEVICE_ID_SI_645 0x0645 #define PCI_DEVICE_ID_SI_650 0x0650 #define PCI_DEVICE_ID_SI_730 0x0730 +#define PCI_DEVICE_ID_SI_630_VGA 0x6300 +#define PCI_DEVICE_ID_SI_730_VGA 0x7300 #define PCI_DEVICE_ID_SI_735 0x0735 #define PCI_DEVICE_ID_SI_740 0x0740 #define PCI_DEVICE_ID_SI_745 0x0745 #define PCI_DEVICE_ID_SI_750 0x0750 -#define PCI_DEVICE_ID_SI_630_VGA 0x6300 -#define PCI_DEVICE_ID_SI_730_VGA 0x7300 #define PCI_DEVICE_ID_SI_900 0x0900 #define PCI_DEVICE_ID_SI_5107 0x5107 #define PCI_DEVICE_ID_SI_5300 0x5300 @@ -595,7 +602,9 @@ #define PCI_DEVICE_ID_PROMISE_20246 0x4d33 #define PCI_DEVICE_ID_PROMISE_20262 0x4d38 #define PCI_DEVICE_ID_PROMISE_20268 0x4d68 -#define PCI_DEVICE_ID_PROMISE_20268R 0x6268 +#define PCI_DEVICE_ID_PROMISE_20268R 0x6268 +#define PCI_DEVICE_ID_PROMISE_20269 0x4d69 +#define PCI_DEVICE_ID_PROMISE_20275 0x1275 #define PCI_DEVICE_ID_PROMISE_5300 0x5300 #define PCI_VENDOR_ID_N9 0x105d @@ -710,6 +719,7 @@ #define PCI_DEVICE_ID_CMD_648 0x0648 #define PCI_DEVICE_ID_CMD_649 0x0649 #define PCI_DEVICE_ID_CMD_670 0x0670 +#define PCI_DEVICE_ID_CMD_680 0x0680 #define PCI_VENDOR_ID_VISION 0x1098 #define PCI_DEVICE_ID_VISION_QD8500 0x0001 @@ -1473,7 +1483,9 @@ #define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402 #define PCI_VENDOR_ID_BROADCOM 0x14e4 -#define PCI_DEVICE_ID_TIGON3 0x1644 +#define PCI_DEVICE_ID_TIGON3_5700 0x1644 +#define PCI_DEVICE_ID_TIGON3_5701 0x1645 +#define PCI_DEVICE_ID_TIGON3_5703 0x1647 #define PCI_VENDOR_ID_SYBA 0x1592 #define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782 @@ -1598,6 +1610,16 @@ #define PCI_DEVICE_ID_INTEL_82801BA_2 0x2443 #define PCI_DEVICE_ID_INTEL_82801BA_3 0x2444 #define PCI_DEVICE_ID_INTEL_82801BA_4 0x2445 +#define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480 +#define PCI_DEVICE_ID_INTEL_82801CA_2 0x2482 +#define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483 +#define PCI_DEVICE_ID_INTEL_82801CA_4 0x2484 +#define PCI_DEVICE_ID_INTEL_82801CA_5 0x2485 +#define PCI_DEVICE_ID_INTEL_82801CA_6 0x2486 +#define PCI_DEVICE_ID_INTEL_82801CA_7 0x2487 +#define PCI_DEVICE_ID_INTEL_82801CA_10 0x248a +#define PCI_DEVICE_ID_INTEL_82801CA_11 0x248b +#define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c #define PCI_DEVICE_ID_INTEL_82801BA_5 0x2446 #define PCI_DEVICE_ID_INTEL_82801BA_6 0x2448 #define PCI_DEVICE_ID_INTEL_82801BA_7 0x2449 diff -u --recursive --new-file v2.4.14/linux/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h --- v2.4.14/linux/include/linux/reiserfs_fs.h Mon Nov 5 15:55:35 2001 +++ linux/include/linux/reiserfs_fs.h Fri Nov 9 14:18:25 2001 @@ -19,6 +19,7 @@ #include <asm/unaligned.h> #include <linux/bitops.h> #include <asm/hardirq.h> +#include <linux/proc_fs.h> #endif /* @@ -1908,6 +1909,67 @@ struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent); int reiserfs_statfs (struct super_block * s, struct statfs * buf); +/* procfs.c */ + +#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO ) +#define REISERFS_PROC_INFO +#else +#undef REISERFS_PROC_INFO +#endif + +int reiserfs_proc_info_init( struct super_block *sb ); +int reiserfs_proc_info_done( struct super_block *sb ); +struct proc_dir_entry *reiserfs_proc_register( struct super_block *sb, + char *name, read_proc_t *func ); +void reiserfs_proc_unregister( struct super_block *sb, const char *name ); +struct proc_dir_entry *reiserfs_proc_register_global( char *name, + read_proc_t *func ); +void reiserfs_proc_unregister_global( const char *name ); +int reiserfs_proc_info_global_init( void ); +int reiserfs_proc_info_global_done( void ); +int reiserfs_proc_tail( int len, char *buffer, char **start, + off_t offset, int count, int *eof ); +int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ); +int reiserfs_version_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ); +int reiserfs_super_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ); +int reiserfs_per_level_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ); +int reiserfs_bitmap_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ); +int reiserfs_on_disk_super_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ); +int reiserfs_oidmap_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ); +int reiserfs_journal_in_proc( char *buffer, char **start, off_t offset, + int count, int *eof, void *data ); + +#if defined( REISERFS_PROC_INFO ) + +#define PROC_EXP( e ) e + +#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#define __PINFO( sb ) ( sb ) -> u.reiserfs_sb.s_proc_info_data +#define PROC_INFO_MAX( sb, field, value ) \ + __PINFO( sb ).field = \ + MAX( ( sb ) -> u.reiserfs_sb.s_proc_info_data.field, value ) +#define PROC_INFO_INC( sb, field ) ( ++ ( __PINFO( sb ).field ) ) +#define PROC_INFO_ADD( sb, field, val ) ( __PINFO( sb ).field += ( val ) ) +#define PROC_INFO_BH_STAT( sb, bh, level ) \ + PROC_INFO_INC( sb, sbk_read_at[ ( level ) ] ); \ + PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) ); \ + PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) ) +#else +#define PROC_EXP( e ) +#define VOID_V ( ( void ) 0 ) +#define PROC_INFO_MAX( sb, field, value ) VOID_V +#define PROC_INFO_INC( sb, field ) VOID_V +#define PROC_INFO_ADD( sb, field, val ) VOID_V +#define PROC_INFO_BH_STAT( p_s_sb, p_s_bh, n_node_level ) VOID_V +#endif + /* dir.c */ extern struct inode_operations reiserfs_dir_inode_operations; extern struct file_operations reiserfs_dir_operations; @@ -1929,8 +1991,8 @@ /* buffer2.c */ struct buffer_head * reiserfs_getblk (kdev_t n_dev, int n_block, int n_size); void wait_buffer_until_released (const struct buffer_head * bh); -struct buffer_head * reiserfs_bread (kdev_t n_dev, int n_block, int n_size); - +struct buffer_head * reiserfs_bread (struct super_block *super, int n_block, + int n_size); /* fix_nodes.c */ void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s); diff -u --recursive --new-file v2.4.14/linux/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h --- v2.4.14/linux/include/linux/reiserfs_fs_sb.h Tue Oct 23 22:48:53 2001 +++ linux/include/linux/reiserfs_fs_sb.h Fri Nov 9 14:55:24 2001 @@ -314,6 +314,74 @@ typedef __u32 (*hashf_t) (const signed char *, int); +struct proc_dir_entry; + +#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO ) +typedef unsigned long int stat_cnt_t; +typedef struct reiserfs_proc_info_data +{ + spinlock_t lock; + int exiting; + int max_hash_collisions; + + stat_cnt_t breads; + stat_cnt_t bread_miss; + stat_cnt_t search_by_key; + stat_cnt_t search_by_key_fs_changed; + stat_cnt_t search_by_key_restarted; + + stat_cnt_t leaked_oid; + stat_cnt_t leaves_removable; + + /* balances per level. Use explicit 5 as MAX_HEIGHT is not visible yet. */ + stat_cnt_t balance_at[ 5 ]; /* XXX */ + /* sbk == search_by_key */ + stat_cnt_t sbk_read_at[ 5 ]; /* XXX */ + stat_cnt_t sbk_fs_changed[ 5 ]; + stat_cnt_t sbk_restarted[ 5 ]; + stat_cnt_t items_at[ 5 ]; /* XXX */ + stat_cnt_t free_at[ 5 ]; /* XXX */ + stat_cnt_t can_node_be_removed[ 5 ]; /* XXX */ + long int lnum[ 5 ]; /* XXX */ + long int rnum[ 5 ]; /* XXX */ + long int lbytes[ 5 ]; /* XXX */ + long int rbytes[ 5 ]; /* XXX */ + stat_cnt_t get_neighbors[ 5 ]; + stat_cnt_t get_neighbors_restart[ 5 ]; + stat_cnt_t need_l_neighbor[ 5 ]; + stat_cnt_t need_r_neighbor[ 5 ]; + + stat_cnt_t free_block; + struct __find_forward_stats { + stat_cnt_t call; + stat_cnt_t wait; + stat_cnt_t bmap; + stat_cnt_t retry; + stat_cnt_t in_journal_hint; + stat_cnt_t in_journal_out; + } find_forward; + struct __journal_stats { + stat_cnt_t in_journal; + stat_cnt_t in_journal_bitmap; + stat_cnt_t in_journal_reusable; + stat_cnt_t lock_journal; + stat_cnt_t lock_journal_wait; + stat_cnt_t journal_being; + stat_cnt_t journal_relock_writers; + stat_cnt_t journal_relock_wcount; + stat_cnt_t mark_dirty; + stat_cnt_t mark_dirty_already; + stat_cnt_t mark_dirty_notjournal; + stat_cnt_t restore_prepared; + stat_cnt_t prepare; + stat_cnt_t prepare_retry; + } journal; +} reiserfs_proc_info_data_t; +#else +typedef struct reiserfs_proc_info_data +{} reiserfs_proc_info_data_t; +#endif + /* reiserfs union of in-core super block data */ struct reiserfs_sb_info { @@ -352,6 +420,8 @@ int s_bmaps_without_search; int s_direct2indirect; int s_indirect2direct; + reiserfs_proc_info_data_t s_proc_info_data; + struct proc_dir_entry *procdir; }; diff -u --recursive --new-file v2.4.14/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.4.14/linux/include/linux/sched.h Mon Nov 5 15:55:35 2001 +++ linux/include/linux/sched.h Fri Nov 9 14:55:40 2001 @@ -88,6 +88,7 @@ #define TASK_UNINTERRUPTIBLE 2 #define TASK_ZOMBIE 4 #define TASK_STOPPED 8 +#define TASK_DEAD 16 #define __set_task_state(tsk, state_value) \ do { (tsk)->state = (state_value); } while (0) @@ -399,6 +400,9 @@ u32 self_exec_id; /* Protection of (de-)allocation: mm, files, fs, tty */ spinlock_t alloc_lock; + +/* journalling filesystem info */ + void *journal_info; }; /* @@ -486,7 +490,8 @@ sig: &init_signals, \ pending: { NULL, &tsk.pending.head, {{0}}}, \ blocked: {{0}}, \ - alloc_lock: SPIN_LOCK_UNLOCKED \ + alloc_lock: SPIN_LOCK_UNLOCKED, \ + journal_info: NULL, \ } diff -u --recursive --new-file v2.4.14/linux/include/linux/serial.h linux/include/linux/serial.h --- v2.4.14/linux/include/linux/serial.h Thu Oct 18 13:47:37 2001 +++ linux/include/linux/serial.h Fri Nov 9 14:47:04 2001 @@ -182,5 +182,11 @@ /* Allow complicated architectures to specify rs_table[] at run time */ extern int early_serial_setup(struct serial_struct *req); +#ifdef CONFIG_ACPI +/* tty ports reserved for the ACPI serial console port and debug port */ +#define ACPI_SERIAL_CONSOLE_PORT 4 +#define ACPI_SERIAL_DEBUG_PORT 5 +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_SERIAL_H */ diff -u --recursive --new-file v2.4.14/linux/include/linux/sisfb.h linux/include/linux/sisfb.h --- v2.4.14/linux/include/linux/sisfb.h Wed Nov 8 17:15:13 2000 +++ linux/include/linux/sisfb.h Fri Nov 9 14:11:15 2001 @@ -1,12 +1,6 @@ #ifndef _LINUX_SISFB #define _LINUX_SISFB -/* CRT2 connection */ -#define MASK_DISPTYPE_CRT2 0x04 /* Connect CRT2 */ -#define MASK_DISPTYPE_LCD 0x02 /* Connect LCD */ -#define MASK_DISPTYPE_TV 0x01 /* Connect TV */ -#define MASK_DISPTYPE_DISP2 (MASK_DISPTYPE_LCD | MASK_DISPTYPE_TV | MASK_DISPTYPE_CRT2) - #define DISPTYPE_CRT1 0x00000008L #define DISPTYPE_CRT2 0x00000004L #define DISPTYPE_LCD 0x00000002L @@ -17,96 +11,102 @@ #define DISPMODE_MIRROR 0x00000010L #define DISPMODE_DUALVIEW 0x00000040L -#define HASVB_NONE 0 -#define HASVB_301 1 -#define HASVB_LVDS 2 -#define HASVB_TRUMPION 3 -#define HASVB_LVDS_CHRONTEL 4 -#define HASVB_LVDS_ALL (HASVB_LVDS | HASVB_TRUMPION | HASVB_LVDS_CHRONTEL) +#define HASVB_NONE 0x00 +#define HASVB_301 0x01 +#define HASVB_LVDS 0x02 +#define HASVB_TRUMPION 0x04 +#define HASVB_LVDS_CHRONTEL 0x10 +#define HASVB_302 0x20 +#define HASVB_303 0x40 +#define HASVB_CHRONTEL 0x80 + +typedef enum _SIS_CHIP_TYPE { + SIS_VGALegacy = 0, + SIS_300, + SIS_630, + SIS_540, + SIS_730, + SIS_315H, + SIS_315, + SIS_550, + SIS_315PRO, + SIS_640, + SIS_740, + SIS_330, + MAX_SIS_CHIP +} SIS_CHIP_TYPE; -enum _TVMODE -{ +typedef enum _TVTYPE { TVMODE_NTSC = 0, TVMODE_PAL, TVMODE_HIVISION, TVMODE_TOTAL -}; +} SIS_TV_TYPE; -enum _TVPLUGTYPE -{ - TVPLUG_UNKNOWN = 0, +typedef enum _TVPLUGTYPE { + TVPLUG_Legacy = 0, TVPLUG_COMPOSITE, TVPLUG_SVIDEO, TVPLUG_SCART, TVPLUG_TOTAL -}; - -enum CHIPTYPE -{ - SiS_UNKNOWN = 0, - SiS_300, - SiS_540, - SiS_630, - SiS_630S, - SiS_730 -}; +} SIS_TV_PLUG; -struct sis_memreq -{ - unsigned long offset; - unsigned long size; -}; - -/* Data for AP */ -struct mode_info -{ - int bpp; - int xres; - int yres; - int v_xres; - int v_yres; - int org_x; - int org_y; - unsigned int vrate; -}; - -struct ap_data -{ - struct mode_info minfo; - unsigned long iobase; - unsigned int mem_size; - unsigned long disp_state; - enum CHIPTYPE chip; -}; +struct sis_memreq { + unsigned long offset; + unsigned long size; +}; + +struct mode_info { + int bpp; + int xres; + int yres; + int v_xres; + int v_yres; + int org_x; + int org_y; + unsigned int vrate; +}; + +struct ap_data { + struct mode_info minfo; + unsigned long iobase; + unsigned int mem_size; + unsigned long disp_state; + SIS_CHIP_TYPE chip; + unsigned char hasVB; + SIS_TV_TYPE TV_type; + SIS_TV_PLUG TV_plug; + unsigned long version; + char reserved[256]; +}; + +struct video_info { + int chip_id; + unsigned int video_size; + unsigned long video_base; + char *video_vbase; + unsigned long mmio_base; + char *mmio_vbase; + unsigned long vga_base; + + int video_bpp; + int video_width; + int video_height; + int video_vwidth; + int video_vheight; + int org_x; + int org_y; + unsigned int refresh_rate; + + unsigned long disp_state; + unsigned char hasVB; + unsigned char TV_type; + unsigned char TV_plug; + SIS_CHIP_TYPE chip; + unsigned char revision_id; -/* Data for kernel */ -struct video_info -{ - /* card parameters */ - int chip_id; - unsigned int video_size; - unsigned long video_base; - char *video_vbase; - unsigned long mmio_base; - char *mmio_vbase; - unsigned long vga_base; - - /* mode */ - int video_bpp; - int video_width; - int video_height; - int video_vwidth; - int video_vheight; - int org_x; - int org_y; - unsigned int refresh_rate; - - /* VB functions */ - unsigned long disp_state; - unsigned char hasVB; - unsigned char TV_type; - unsigned char TV_plug; + char reserved[256]; }; #ifdef __KERNEL__ @@ -114,5 +114,6 @@ extern void sis_malloc(struct sis_memreq *req); extern void sis_free(unsigned long base); +extern void sis_dispinfo(struct ap_data *rec); #endif #endif diff -u --recursive --new-file v2.4.14/linux/include/linux/sockios.h linux/include/linux/sockios.h --- v2.4.14/linux/include/linux/sockios.h Mon Nov 5 15:55:35 2001 +++ linux/include/linux/sockios.h Wed Nov 7 14:39:36 2001 @@ -105,6 +105,15 @@ #define SIOCGIFVLAN 0x8982 /* 802.1Q VLAN support */ #define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */ +/* bonding calls */ + +#define SIOCBONDENSLAVE 0x8990 /* enslave a device to the bond */ +#define SIOCBONDRELEASE 0x8991 /* release a slave from the bond*/ +#define SIOCBONDSETHWADDR 0x8992 /* set the hw addr of the bond */ +#define SIOCBONDSLAVEINFOQUERY 0x8993 /* rtn info about slave state */ +#define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */ +#define SIOCBONDCHANGEACTIVE 0x8995 /* update to a new active slave */ + /* Device private ioctl calls */ /* diff -u --recursive --new-file v2.4.14/linux/include/linux/soundcard.h linux/include/linux/soundcard.h --- v2.4.14/linux/include/linux/soundcard.h Sun Sep 23 11:41:01 2001 +++ linux/include/linux/soundcard.h Fri Nov 9 14:11:15 2001 @@ -179,7 +179,7 @@ * Some big endian/little endian handling macros */ -#if defined(_AIX) || defined(AIX) || defined(sparc) || defined(__sparc__) || defined(HPPA) || defined(PPC) +#if defined(_AIX) || defined(AIX) || defined(sparc) || defined(__sparc__) || defined(HPPA) || defined(PPC) || defined(__mc68000__) /* Big endian machines */ # define _PATCHKEY(id) (0xfd00|id) # define AFMT_S16_NE AFMT_S16_BE diff -u --recursive --new-file v2.4.14/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.4.14/linux/include/linux/swap.h Mon Nov 5 15:55:35 2001 +++ linux/include/linux/swap.h Fri Nov 9 14:47:04 2001 @@ -166,9 +166,9 @@ */ #define DEBUG_LRU_PAGE(page) \ do { \ - if (PageActive(page)) \ + if (!PageLRU(page)) \ BUG(); \ - if (PageInactive(page)) \ + if (PageActive(page)) \ BUG(); \ if (page_count(page) == 0) \ BUG(); \ @@ -185,7 +185,6 @@ #define add_page_to_inactive_list(page) \ do { \ DEBUG_LRU_PAGE(page); \ - SetPageInactive(page); \ list_add(&(page)->lru, &inactive_list); \ nr_inactive_pages++; \ } while (0) @@ -200,7 +199,6 @@ #define del_page_from_inactive_list(page) \ do { \ list_del(&(page)->lru); \ - ClearPageInactive(page); \ nr_inactive_pages--; \ } while (0) diff -u --recursive --new-file v2.4.14/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h --- v2.4.14/linux/include/linux/sysv_fs.h Sun Sep 23 11:41:01 2001 +++ linux/include/linux/sysv_fs.h Fri Nov 9 13:45:35 2001 @@ -241,53 +241,6 @@ u32 i_ctime; /* time of creation */ }; -/* The admissible values for i_mode are listed in <linux/stat.h> : - * #define S_IFMT 00170000 mask for type - * #define S_IFREG 0100000 type = regular file - * #define S_IFBLK 0060000 type = block device - * #define S_IFDIR 0040000 type = directory - * #define S_IFCHR 0020000 type = character device - * #define S_IFIFO 0010000 type = named pipe - * #define S_ISUID 0004000 set user id - * #define S_ISGID 0002000 set group id - * #define S_ISVTX 0001000 save swapped text even after use - * Additionally for SystemV: - * #define S_IFLNK 0120000 type = symbolic link - * #define S_IFNAM 0050000 type = XENIX special named file ?? - * Additionally for Coherent: - * #define S_IFMPB 0070000 type = multiplexed block device ?? - * #define S_IFMPC 0030000 type = multiplexed character device ?? - * - * Since Coherent doesn't know about symbolic links, we use a kludgey - * implementation of symbolic links: i_mode = COH_KLUDGE_SYMLINK_MODE - * denotes a symbolic link. When a regular file should get this mode by - * accident, it is automatically converted to COH_KLUDGE_NOT_SYMLINK. - * We use S_IFREG because only regular files (and Coherent pipes...) can have - * data blocks with arbitrary contents associated with them, and S_ISVTX - * ("save swapped text after use") because it is unused on both Linux and - * Coherent: Linux does much more intelligent paging, and Coherent hasn't - * virtual memory at all. - * Same trick for Xenix. - */ -#define COH_KLUDGE_SYMLINK_MODE (S_IFREG | S_ISVTX) -#define COH_KLUDGE_NOT_SYMLINK (S_IFREG | S_ISVTX | S_IRUSR) /* force read access */ -static inline mode_t from_coh_imode(unsigned short mode) -{ - if (mode == COH_KLUDGE_SYMLINK_MODE) - return (S_IFLNK | 0777); - else - return mode; -} -static inline unsigned short to_coh_imode(mode_t mode) -{ - if (S_ISLNK(mode)) - return COH_KLUDGE_SYMLINK_MODE; - else if (mode == COH_KLUDGE_SYMLINK_MODE) - return COH_KLUDGE_NOT_SYMLINK; - else - return mode; -} - /* Admissible values for i_nlink: 0.._LINK_MAX */ enum { XENIX_LINK_MAX = 126, /* ?? */ @@ -360,7 +313,6 @@ extern void sysv_write_inode(struct inode *, int); extern int sysv_sync_inode(struct inode *); extern int sysv_sync_file(struct file *, struct dentry *, int); -extern int sysv_notify_change(struct dentry *, struct iattr *); extern void sysv_set_inode(struct inode *, dev_t); extern struct sysv_dir_entry *sysv_find_entry(struct dentry*, struct page**); diff -u --recursive --new-file v2.4.14/linux/include/linux/sysv_fs_i.h linux/include/linux/sysv_fs_i.h --- v2.4.14/linux/include/linux/sysv_fs_i.h Tue Jul 3 17:08:22 2001 +++ linux/include/linux/sysv_fs_i.h Fri Nov 9 13:45:35 2001 @@ -10,6 +10,7 @@ * then 1 double indirection block, * then 1 triple indirection block. */ + u32 i_dir_start_lookup; }; #endif diff -u --recursive --new-file v2.4.14/linux/include/linux/sysv_fs_sb.h linux/include/linux/sysv_fs_sb.h --- v2.4.14/linux/include/linux/sysv_fs_sb.h Tue Jul 3 17:08:22 2001 +++ linux/include/linux/sysv_fs_sb.h Fri Nov 9 13:45:35 2001 @@ -13,7 +13,6 @@ struct sysv_sb_info { int s_type; /* file system type: FSTYPE_{XENIX|SYSV|COH} */ char s_bytesex; /* bytesex (le/be/pdp) */ - char s_kludge_symlinks; /* flag whether symlinks have a kludgey mode */ char s_truncate; /* if 1: names > SYSV_NAMELEN chars are truncated */ /* if 0: they are disallowed (ENAMETOOLONG) */ nlink_t s_link_max; /* max number of hard links to a file */ @@ -56,7 +55,6 @@ /* sv_ == u.sysv_sb.s_ */ #define sv_type u.sysv_sb.s_type #define sv_bytesex u.sysv_sb.s_bytesex -#define sv_kludge_symlinks u.sysv_sb.s_kludge_symlinks #define sv_truncate u.sysv_sb.s_truncate #define sv_link_max u.sysv_sb.s_link_max #define sv_inodes_per_block u.sysv_sb.s_inodes_per_block diff -u --recursive --new-file v2.4.14/linux/include/linux/videodev.h linux/include/linux/videodev.h --- v2.4.14/linux/include/linux/videodev.h Tue Oct 23 22:48:53 2001 +++ linux/include/linux/videodev.h Fri Nov 9 14:11:15 2001 @@ -91,7 +91,7 @@ { int tuner; char name[32]; - ulong rangelow, rangehigh; /* Tuner range */ + unsigned long rangelow, rangehigh; /* Tuner range */ __u32 flags; #define VIDEO_TUNER_PAL 1 #define VIDEO_TUNER_NTSC 2 diff -u --recursive --new-file v2.4.14/linux/include/linux/watchdog.h linux/include/linux/watchdog.h --- v2.4.14/linux/include/linux/watchdog.h Sun Dec 31 10:26:18 2000 +++ linux/include/linux/watchdog.h Fri Nov 9 14:11:15 2001 @@ -25,6 +25,7 @@ #define WDIOC_GETTEMP _IOR(WATCHDOG_IOCTL_BASE, 3, int) #define WDIOC_SETOPTIONS _IOR(WATCHDOG_IOCTL_BASE, 4, int) #define WDIOC_KEEPALIVE _IOR(WATCHDOG_IOCTL_BASE, 5, int) +#define WDIOC_SETTIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 6, int) #define WDIOF_UNKNOWN -1 /* Unknown flag error */ #define WDIOS_UNKNOWN -1 /* Unknown status error */ diff -u --recursive --new-file v2.4.14/linux/include/net/dn.h linux/include/net/dn.h --- v2.4.14/linux/include/net/dn.h Thu Oct 18 13:47:42 2001 +++ linux/include/net/dn.h Fri Nov 9 14:47:57 2001 @@ -217,5 +217,6 @@ extern int decnet_dn_count; extern int decnet_di_count; extern int decnet_dr_count; +extern int decnet_no_fc_max_cwnd; #endif /* _NET_DN_H */ diff -u --recursive --new-file v2.4.14/linux/include/net/irda/irda-usb.h linux/include/net/irda/irda-usb.h --- v2.4.14/linux/include/net/irda/irda-usb.h Tue Oct 9 17:06:53 2001 +++ linux/include/net/irda/irda-usb.h Fri Nov 9 14:22:17 2001 @@ -120,6 +120,11 @@ __u8 bMaxUnicastList; } __attribute__ ((packed)); +/* class specific interface request to get the IrDA-USB class descriptor + * (6.2.5, USB-IrDA class spec 1.0) */ + +#define IU_REQ_GET_CLASS_DESC 0x06 + struct irda_usb_cb { struct irda_class_desc *irda_desc; struct usb_device *usbdev; /* init: probe_irda */ diff -u --recursive --new-file v2.4.14/linux/include/net/irda/irda.h linux/include/net/irda/irda.h --- v2.4.14/linux/include/net/irda/irda.h Thu Oct 18 13:48:05 2001 +++ linux/include/net/irda/irda.h Fri Nov 9 15:00:40 2001 @@ -10,6 +10,7 @@ * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -42,6 +43,11 @@ #ifndef FALSE #define FALSE 0 +#endif + +/* Hack to do small backoff when setting media busy in IrLAP */ +#ifndef SMALL +#define SMALL 5 #endif #ifndef IRDA_MIN /* Lets not mix this MIN with other header files */ diff -u --recursive --new-file v2.4.14/linux/include/net/irda/irlap_event.h linux/include/net/irda/irlap_event.h --- v2.4.14/linux/include/net/irda/irlap_event.h Fri May 25 17:07:17 2001 +++ linux/include/net/irda/irlap_event.h Fri Nov 9 14:22:17 2001 @@ -12,6 +12,7 @@ * * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -103,6 +104,7 @@ DISCOVERY_TIMER_EXPIRED, WD_TIMER_EXPIRED, BACKOFF_TIMER_EXPIRED, + MEDIA_BUSY_TIMER_EXPIRED, } IRLAP_EVENT; /* diff -u --recursive --new-file v2.4.14/linux/include/net/irda/irlmp.h linux/include/net/irda/irlmp.h --- v2.4.14/linux/include/net/irda/irlmp.h Tue Oct 9 17:06:53 2001 +++ linux/include/net/irda/irlmp.h Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -131,7 +132,6 @@ struct irlap_cb *irlap; /* Instance of IrLAP layer */ hashbin_t *lsaps; /* LSAP associated with this link */ - int refcount; __u8 caddr; /* Connection address */ __u32 saddr; /* Source device address */ diff -u --recursive --new-file v2.4.14/linux/include/net/irda/irlmp_event.h linux/include/net/irda/irlmp_event.h --- v2.4.14/linux/include/net/irda/irlmp_event.h Mon Aug 30 10:30:24 1999 +++ linux/include/net/irda/irlmp_event.h Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -102,10 +103,6 @@ void irlmp_watchdog_timer_expired(void *data); void irlmp_discovery_timer_expired(void *data); void irlmp_idle_timer_expired(void *data); - -void irlmp_next_station_state(IRLMP_STATE state); -void irlmp_next_lsap_state(struct lsap_cb *self, LSAP_STATE state); -void irlmp_next_lap_state(struct lap_cb *self, IRLMP_STATE state); void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, struct sk_buff *skb); diff -u --recursive --new-file v2.4.14/linux/include/net/irda/irmod.h linux/include/net/irda/irmod.h --- v2.4.14/linux/include/net/irda/irmod.h Mon Dec 11 12:59:37 2000 +++ linux/include/net/irda/irmod.h Fri Nov 9 14:22:17 2001 @@ -10,6 +10,7 @@ * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -25,108 +26,19 @@ #ifndef IRMOD_H #define IRMOD_H -#include <linux/skbuff.h> -#include <linux/miscdevice.h> +#include <net/irda/irda.h> /* Notify stuff */ -#include <net/irda/irqueue.h> +/* Nothing much here anymore - Maybe this header should be merged in + * another header like net/irda/irda.h... - Jean II */ -#define IRMGR_IOC_MAGIC 'm' -#define IRMGR_IOCTNPC _IO(IRMGR_IOC_MAGIC, 1) -#define IRMGR_IOC_MAXNR 1 - -/* - * Events that we pass to the user space manager - */ -typedef enum { - EVENT_DEVICE_DISCOVERED = 0, - EVENT_REQUEST_MODULE, - EVENT_IRLAN_START, - EVENT_IRLAN_STOP, - EVENT_IRLPT_START, /* Obsolete */ - EVENT_IRLPT_STOP, /* Obsolete */ - EVENT_IROBEX_START, /* Obsolete */ - EVENT_IROBEX_STOP, /* Obsolete */ - EVENT_IRDA_STOP, - EVENT_NEED_PROCESS_CONTEXT, -} IRMGR_EVENT; - -/* - * Event information passed to the IrManager daemon process - */ -struct irmanager_event { - IRMGR_EVENT event; - char devname[10]; - char info[32]; - int service; - __u32 saddr; - __u32 daddr; -}; - -typedef void (*TODO_CALLBACK)( void *self, __u32 param); - -/* - * Same as irmanager_event but this one can be queued and inclueds some - * addtional information - */ -struct irda_event { - irda_queue_t q; /* Must be first */ - - struct irmanager_event event; -}; - -/* - * Funtions with needs to be called with a process context - */ -struct irda_todo { - irda_queue_t q; /* Must be first */ - - void *self; - TODO_CALLBACK callback; - __u32 param; -}; - -/* - * Main structure for the IrDA device (not much here :-) - */ -struct irda_cb { - struct miscdevice dev; - wait_queue_head_t wait_queue; - - int in_use; - - irda_queue_t *event_queue; /* Events queued for the irmanager */ - irda_queue_t *todo_queue; /* Todo list */ -}; - -int irmod_init_module(void); -void irmod_cleanup_module(void); - -/* - * Function irda_lock (lock) - * - * Lock variable. Returns false if the lock is already set. - * - */ -static inline int irda_lock(int *lock) -{ - if (test_and_set_bit( 0, (void *) lock)) { - IRDA_DEBUG(3, __FUNCTION__ - "(), Trying to lock, already locked variable!\n"); - return FALSE; - } - return TRUE; -} - -inline int irda_unlock(int *lock); +/* Locking wrapper - Note the inverted logic on irda_lock(). + * Those function basically return false if the lock is already in the + * position you want to set it. - Jean II */ +#define irda_lock(lock) (! test_and_set_bit(0, (void *) (lock))) +#define irda_unlock(lock) (test_and_clear_bit(0, (void *) (lock))) +/* Zero the notify structure */ void irda_notify_init(notify_t *notify); - -void irda_execute_as_process(void *self, TODO_CALLBACK callback, __u32 param); -void irmanager_notify(struct irmanager_event *event); - -extern void irda_proc_modcount(struct inode *, int); -void irda_mod_inc_use_count(void); -void irda_mod_dec_use_count(void); #endif /* IRMOD_H */ diff -u --recursive --new-file v2.4.14/linux/include/net/irda/parameters.h linux/include/net/irda/parameters.h --- v2.4.14/linux/include/net/irda/parameters.h Tue Mar 21 11:17:28 2000 +++ linux/include/net/irda/parameters.h Fri Nov 9 14:22:17 2001 @@ -25,6 +25,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA + * + * Michel Dänzer <daenzer@debian.org>, 10/2001 + * - simplify irda_pv_t to avoid endianness issues * ********************************************************************/ @@ -55,11 +58,7 @@ typedef union { char *c; - __u8 b; - __u16 s; __u32 i; - __u8 *bp; - __u16 *sp; __u32 *ip; } irda_pv_t; diff -u --recursive --new-file v2.4.14/linux/include/net/irda/timer.h linux/include/net/irda/timer.h --- v2.4.14/linux/include/net/irda/timer.h Mon Dec 11 12:59:38 2000 +++ linux/include/net/irda/timer.h Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1997, 1998-1999 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -47,7 +48,9 @@ * duration of the P-timer. */ #define WD_TIMEOUT (POLL_TIMEOUT*2) + #define MEDIABUSY_TIMEOUT (500*HZ/1000) /* 500 msec */ +#define SMALLBUSY_TIMEOUT (100*HZ/1000) /* 100 msec - IrLAP 6.13.4 */ /* * Slot timer must never exceed 85 ms, and must always be at least 25 ms, @@ -75,7 +78,7 @@ inline void irlap_start_wd_timer(struct irlap_cb *self, int timeout); inline void irlap_start_backoff_timer(struct irlap_cb *self, int timeout); -void irlap_start_mbusy_timer(struct irlap_cb *); +void irlap_start_mbusy_timer(struct irlap_cb *self, int timeout); void irlap_stop_mbusy_timer(struct irlap_cb *); struct lsap_cb; diff -u --recursive --new-file v2.4.14/linux/init/main.c linux/init/main.c --- v2.4.14/linux/init/main.c Tue Oct 23 22:48:53 2001 +++ linux/init/main.c Fri Nov 9 14:15:00 2001 @@ -119,7 +119,7 @@ int rows, cols; #ifdef CONFIG_BLK_DEV_INITRD -kdev_t real_root_dev; +unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ #endif int root_mountflags = MS_RDONLY; diff -u --recursive --new-file v2.4.14/linux/init/version.c linux/init/version.c --- v2.4.14/linux/init/version.c Mon Oct 2 11:57:01 2000 +++ linux/init/version.c Fri Nov 9 14:11:15 2001 @@ -1,5 +1,5 @@ /* - * linux/version.c + * linux/init/version.c * * Copyright (C) 1992 Theodore Ts'o * diff -u --recursive --new-file v2.4.14/linux/kernel/exit.c linux/kernel/exit.c --- v2.4.14/linux/kernel/exit.c Tue Oct 23 22:48:53 2001 +++ linux/kernel/exit.c Fri Nov 9 14:39:24 2001 @@ -39,6 +39,7 @@ break; task_unlock(p); do { + cpu_relax(); barrier(); } while (p->has_cpu); } @@ -534,6 +535,9 @@ } goto end_wait4; case TASK_ZOMBIE: + /* Make sure no other waiter picks this task up */ + p->state = TASK_DEAD; + current->times.tms_cutime += p->times.tms_utime + p->times.tms_cutime; current->times.tms_cstime += p->times.tms_stime + p->times.tms_cstime; read_unlock(&tasklist_lock); diff -u --recursive --new-file v2.4.14/linux/lib/brlock.c linux/lib/brlock.c --- v2.4.14/linux/lib/brlock.c Tue Jul 3 17:08:22 2001 +++ linux/lib/brlock.c Fri Nov 9 14:11:15 2001 @@ -54,6 +54,7 @@ if (__brlock_array[cpu_logical_map(i)][idx] != 0) { spin_unlock(&__br_write_locks[idx].lock); barrier(); + cpu_relax(); goto again; } } diff -u --recursive --new-file v2.4.14/linux/mm/filemap.c linux/mm/filemap.c --- v2.4.14/linux/mm/filemap.c Mon Nov 5 15:55:35 2001 +++ linux/mm/filemap.c Fri Nov 9 14:25:04 2001 @@ -209,19 +209,26 @@ spin_unlock(&pagemap_lru_lock); } +static int do_flushpage(struct page *page, unsigned long offset) +{ + int (*flushpage) (struct page *, unsigned long); + flushpage = page->mapping->a_ops->flushpage; + if (flushpage) + return (*flushpage)(page, offset); + return block_flushpage(page, offset); +} + static inline void truncate_partial_page(struct page *page, unsigned partial) { memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial); - if (page->buffers) - block_flushpage(page, partial); - + do_flushpage(page, partial); } static void truncate_complete_page(struct page *page) { /* Leave it on the LRU if it gets converted into anonymous buffers */ - if (!page->buffers || block_flushpage(page, 0)) + if (!page->buffers || do_flushpage(page, 0)) lru_cache_del(page); /* diff -u --recursive --new-file v2.4.14/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.4.14/linux/mm/page_alloc.c Mon Nov 5 15:55:35 2001 +++ linux/mm/page_alloc.c Tue Nov 6 21:12:54 2001 @@ -80,9 +80,9 @@ BUG(); if (PageLocked(page)) BUG(); - if (PageActive(page)) + if (PageLRU(page)) BUG(); - if (PageInactive(page)) + if (PageActive(page)) BUG(); page->flags &= ~((1<<PG_referenced) | (1<<PG_dirty)); @@ -203,7 +203,10 @@ set_page_count(page, 1); if (BAD_RANGE(zone,page)) BUG(); - DEBUG_LRU_PAGE(page); + if (PageLRU(page)) + BUG(); + if (PageActive(page)) + BUG(); return page; } curr_order++; @@ -268,9 +271,9 @@ BUG(); if (PageLocked(page)) BUG(); - if (PageActive(page)) + if (PageLRU(page)) BUG(); - if (PageInactive(page)) + if (PageActive(page)) BUG(); if (PageDirty(page)) BUG(); @@ -425,7 +428,7 @@ void page_cache_release(struct page *page) { if (!PageReserved(page) && put_page_testzero(page)) { - if (PageActive(page) || PageInactive(page)) + if (PageLRU(page)) lru_cache_del(page); __free_pages_ok(page, 0); } diff -u --recursive --new-file v2.4.14/linux/mm/swap.c linux/mm/swap.c --- v2.4.14/linux/mm/swap.c Mon Nov 5 15:55:35 2001 +++ linux/mm/swap.c Tue Nov 6 22:44:20 2001 @@ -38,7 +38,7 @@ */ static inline void activate_page_nolock(struct page * page) { - if (PageInactive(page)) { + if (PageLRU(page) && !PageActive(page)) { del_page_from_inactive_list(page); add_page_to_active_list(page); } @@ -57,7 +57,7 @@ */ void lru_cache_add(struct page * page) { - if (!PageActive(page) && !PageInactive(page)) { + if (!TestSetPageLRU(page)) { spin_lock(&pagemap_lru_lock); add_page_to_inactive_list(page); spin_unlock(&pagemap_lru_lock); @@ -73,12 +73,12 @@ */ void __lru_cache_del(struct page * page) { - if (PageActive(page)) { - del_page_from_active_list(page); - } else if (PageInactive(page)) { - del_page_from_inactive_list(page); - } else { -// printk("VM: __lru_cache_del, found unknown page ?!\n"); + if (TestClearPageLRU(page)) { + if (PageActive(page)) { + del_page_from_active_list(page); + } else { + del_page_from_inactive_list(page); + } } } diff -u --recursive --new-file v2.4.14/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.4.14/linux/mm/vmscan.c Mon Nov 5 15:55:35 2001 +++ linux/mm/vmscan.c Fri Nov 9 14:25:04 2001 @@ -7,7 +7,6 @@ * kswapd added: 7.1.96 sct * Removed kswapd_ctl limits, and swap out as many pages as needed * to bring the system back to freepages.high: 2.4.97, Rik van Riel. - * Version: $Id: vmscan.c,v 1.5 1998/02/23 22:14:28 sct Exp $ * Zone aware kswapd started 02/00, Kanoj Sarcar (kanoj@sgi.com). * Multiqueue VM started 5.8.00, Rik van Riel. */ @@ -117,6 +116,13 @@ goto drop_pte; /* + * Anonymous buffercache pages can be left behind by + * concurrent truncate and pagefault. + */ + if (page->buffers) + goto preserve; + + /* * This is a dirty, swappable page. First of all, * get a suitable swap entry for it, and make sure * we have the swap cache set up to associate the @@ -140,6 +146,7 @@ } /* No swap space left */ +preserve: set_pte(page_table, pte); UnlockPage(page); return 0; @@ -347,7 +354,9 @@ page = list_entry(entry, struct page, lru); - if (unlikely(!PageInactive(page))) + if (unlikely(!PageLRU(page))) + BUG(); + if (unlikely(PageActive(page))) BUG(); list_del(entry); @@ -419,7 +428,7 @@ /* avoid to free a locked page */ page_cache_get(page); - if (try_to_free_buffers(page, gfp_mask)) { + if (try_to_release_page(page, gfp_mask)) { if (!page->mapping) { /* * We must not allow an anon page @@ -440,7 +449,7 @@ } else { /* * The page is still in pagecache so undo the stuff - * before the try_to_free_buffers since we've not + * before the try_to_release_page since we've not * finished and we can now try the next step. */ page_cache_release(page); diff -u --recursive --new-file v2.4.14/linux/net/802/cl2llc.pre linux/net/802/cl2llc.pre --- v2.4.14/linux/net/802/cl2llc.pre Fri Apr 6 10:51:19 2001 +++ linux/net/802/cl2llc.pre Fri Nov 9 14:11:15 2001 @@ -28,7 +28,7 @@ #include <linux/types.h> #include <linux/kernel.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/netdevice.h> #include <linux/skbuff.h> #include <net/p8022.h> diff -u --recursive --new-file v2.4.14/linux/net/atm/Makefile linux/net/atm/Makefile --- v2.4.14/linux/net/atm/Makefile Mon Mar 26 15:36:30 2001 +++ linux/net/atm/Makefile Fri Nov 9 14:11:15 2001 @@ -33,6 +33,7 @@ obj-$(CONFIG_ATM_LANE) += lec.o obj-$(CONFIG_ATM_MPOA) += mpoa.o +obj-$(CONFIG_PPPOATM) += pppoatm.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.14/linux/net/atm/common.c linux/net/atm/common.c --- v2.4.14/linux/net/atm/common.c Tue Oct 9 17:06:53 2001 +++ linux/net/atm/common.c Fri Nov 9 14:11:15 2001 @@ -58,6 +58,11 @@ #endif #endif +#if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE) +int (*pppoatm_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long); +EXPORT_SYMBOL(pppoatm_ioctl_hook); +#endif + #include "resources.h" /* atm_find_dev */ #include "common.h" /* prototypes */ #include "protocols.h" /* atm_init_<transport> */ @@ -773,6 +778,13 @@ default: break; } +#if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE) + if (pppoatm_ioctl_hook) { + ret_val = pppoatm_ioctl_hook(vcc, cmd, arg); + if (ret_val != -ENOIOCTLCMD) + goto done; + } +#endif if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) { ret_val = -EFAULT; goto done; diff -u --recursive --new-file v2.4.14/linux/net/atm/pppoatm.c linux/net/atm/pppoatm.c --- v2.4.14/linux/net/atm/pppoatm.c Wed Dec 31 16:00:00 1969 +++ linux/net/atm/pppoatm.c Fri Nov 9 14:11:15 2001 @@ -0,0 +1,365 @@ +/* net/atm/pppoatm.c - RFC2364 PPP over ATM/AAL5 */ + +/* Copyright 1999-2000 by Mitchell Blank Jr */ +/* Based on clip.c; 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* And on ppp_async.c; Copyright 1999 Paul Mackerras */ +/* And help from Jens Axboe */ + +/* + * 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 driver provides the encapsulation and framing for sending + * and receiving PPP frames in ATM AAL5 PDUs. + */ + +/* + * One shortcoming of this driver is that it does not comply with + * section 8 of RFC2364 - we are supposed to detect a change + * in encapsulation and immediately abort the connection (in order + * to avoid a black-hole being created if our peer loses state + * and changes encapsulation unilaterally. However, since the + * ppp_generic layer actually does the decapsulation, we need + * a way of notifying it when we _think_ there might be a problem) + * There's two cases: + * 1. LLC-encapsulation was missing when it was enabled. In + * this case, we should tell the upper layer "tear down + * this session if this skb looks ok to you" + * 2. LLC-encapsulation was present when it was disabled. Then + * we need to tell the upper layer "this packet may be + * ok, but if its in error tear down the session" + * These hooks are not yet available in ppp_generic + */ + +#include <linux/module.h> +#include <linux/config.h> +#include <linux/init.h> +#include <linux/skbuff.h> +#include <linux/atm.h> +#include <linux/atmdev.h> +#include <linux/ppp_defs.h> +#include <linux/if_ppp.h> +#include <linux/ppp_channel.h> +#include <linux/atmppp.h> + +#if 0 +#define DPRINTK(format, args...) \ + printk(KERN_DEBUG "pppoatm: " format, ##args) +#else +#define DPRINTK(format, args...) +#endif + +enum pppoatm_encaps { + e_autodetect = PPPOATM_ENCAPS_AUTODETECT, + e_vc = PPPOATM_ENCAPS_VC, + e_llc = PPPOATM_ENCAPS_LLC, +}; + +struct pppoatm_vcc { + struct atm_vcc *atmvcc; /* VCC descriptor */ + void (*old_push)(struct atm_vcc *, struct sk_buff *); + void (*old_pop)(struct atm_vcc *, struct sk_buff *); + /* keep old push/pop for detaching */ + enum pppoatm_encaps encaps; + int flags; /* SC_COMP_PROT - compress protocol */ + struct ppp_channel chan; /* interface to generic ppp layer */ + struct tasklet_struct wakeup_tasklet; +}; + +/* + * Header used for LLC Encapsulated PPP (4 bytes) followed by the LCP protocol + * ID (0xC021) used in autodetection + */ +static const unsigned char pppllc[6] = { 0xFE, 0xFE, 0x03, 0xCF, 0xC0, 0x21 }; +#define LLC_LEN (4) + +static inline struct pppoatm_vcc *atmvcc_to_pvcc(const struct atm_vcc *atmvcc) +{ + return (struct pppoatm_vcc *) (atmvcc->user_back); +} + +static inline struct pppoatm_vcc *chan_to_pvcc(const struct ppp_channel *chan) +{ + return (struct pppoatm_vcc *) (chan->private); +} + +/* + * We can't do this directly from our _pop handler, since the ppp code + * doesn't want to be called in interrupt context, so we do it from + * a tasklet + */ +static void pppoatm_wakeup_sender(unsigned long arg) +{ + ppp_output_wakeup((struct ppp_channel *) arg); +} + +/* + * This gets called every time the ATM card has finished sending our + * skb. The ->old_pop will take care up normal atm flow control, + * but we also need to wake up the device if we blocked it + */ +static void pppoatm_pop(struct atm_vcc *atmvcc, struct sk_buff *skb) +{ + struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); + pvcc->old_pop(atmvcc, skb); + /* + * We don't really always want to do this since it's + * really inefficient - it would be much better if we could + * test if we had actually throttled the generic layer. + * Unfortunately then there would be a nasty SMP race where + * we could clear that flag just as we refuse another packet. + * For now we do the safe thing. + */ + tasklet_schedule(&pvcc->wakeup_tasklet); +} + +/* + * Unbind from PPP - currently we only do this when closing the socket, + * but we could put this into an ioctl if need be + */ +static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc) +{ + struct pppoatm_vcc *pvcc; + pvcc = atmvcc_to_pvcc(atmvcc); + atmvcc->push = pvcc->old_push; + atmvcc->pop = pvcc->old_pop; + tasklet_disable(&pvcc->wakeup_tasklet); + ppp_unregister_channel(&pvcc->chan); + atmvcc->user_back = NULL; + kfree(pvcc); + /* Gee, I hope we have the big kernel lock here... */ + MOD_DEC_USE_COUNT; +} + +/* Called when an AAL5 PDU comes in */ +static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb) +{ + struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); + DPRINTK("pppoatm push\n"); + if (skb == NULL) { /* VCC was closed */ + DPRINTK("removing ATMPPP VCC %p\n", pvcc); + pppoatm_unassign_vcc(atmvcc); + atmvcc->push(atmvcc, NULL); /* Pass along bad news */ + return; + } + atm_return(atmvcc, skb->truesize); + switch (pvcc->encaps) { + case e_llc: + if (skb->len < LLC_LEN || + memcmp(skb->data, pppllc, LLC_LEN)) + goto error; + skb_pull(skb, LLC_LEN); + break; + case e_autodetect: + if (pvcc->chan.ppp == NULL) { /* Not bound yet! */ + kfree_skb(skb); + return; + } + if (skb->len >= sizeof(pppllc) && + !memcmp(skb->data, pppllc, sizeof(pppllc))) { + pvcc->encaps = e_llc; + skb_pull(skb, LLC_LEN); + break; + } + if (skb->len >= (sizeof(pppllc) - LLC_LEN) && + !memcmp(skb->data, &pppllc[LLC_LEN], + sizeof(pppllc) - LLC_LEN)) { + pvcc->encaps = e_vc; + pvcc->chan.mtu += LLC_LEN; + break; + } + DPRINTK("(unit %d): Couldn't autodetect yet " + "(skb: %02X %02X %02X %02X %02X %02X)\n", + pvcc->chan.unit, + skb->data[0], skb->data[1], skb->data[2], + skb->data[3], skb->data[4], skb->data[5]); + goto error; + case e_vc: + break; + } + ppp_input(&pvcc->chan, skb); + return; + error: + kfree_skb(skb); + ppp_input_error(&pvcc->chan, 0); +} + +/* + * Called by the ppp_generic.c to send a packet - returns true if packet + * was accepted. If we return false, then it's our job to call + * ppp_output_wakeup(chan) when we're feeling more up to it. + * Note that in the ENOMEM case (as opposed to the !atm_may_send case) + * we should really drop the packet, but the generic layer doesn't + * support this yet. We just return 'DROP_PACKET' which we actually define + * as success, just to be clear what we're really doing. + */ +#define DROP_PACKET 1 +static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) +{ + struct pppoatm_vcc *pvcc = chan_to_pvcc(chan); + ATM_SKB(skb)->vcc = pvcc->atmvcc; + DPRINTK("(unit %d): pppoatm_send (skb=0x%p, vcc=0x%p)\n", + pvcc->chan.unit, skb, pvcc->atmvcc); + if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) + (void) skb_pull(skb, 1); + switch (pvcc->encaps) { /* LLC encapsulation needed */ + case e_llc: + if (skb_headroom(skb) < LLC_LEN) { + struct sk_buff *n; + n = skb_realloc_headroom(skb, LLC_LEN); + if (n != NULL && + !atm_may_send(pvcc->atmvcc, n->truesize)) { + kfree_skb(n); + goto nospace; + } + kfree_skb(skb); + if ((skb = n) == NULL) + return DROP_PACKET; + } else if (!atm_may_send(pvcc->atmvcc, skb->truesize)) + goto nospace; + memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN); + break; + case e_vc: + if (!atm_may_send(pvcc->atmvcc, skb->truesize)) + goto nospace; + break; + case e_autodetect: + DPRINTK("(unit %d): Trying to send without setting encaps!\n", + pvcc->chan.unit); + kfree_skb(skb); + return 1; + } + atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->tx_inuse); + ATM_SKB(skb)->iovcnt = 0; + ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; + DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n", + pvcc->chan.unit, skb, ATM_SKB(skb)->vcc, + ATM_SKB(skb)->vcc->dev); + return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) + ? DROP_PACKET : 1; + nospace: + /* + * We don't have space to send this SKB now, but we might have + * already applied SC_COMP_PROT compression, so may need to undo + */ + if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 && + skb->data[-1] == '\0') + (void) skb_push(skb, 1); + return 0; +} + +/* This handles ioctls sent to the /dev/ppp interface */ +static int pppoatm_devppp_ioctl(struct ppp_channel *chan, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case PPPIOCGFLAGS: + return put_user(chan_to_pvcc(chan)->flags, (int *) arg) + ? -EFAULT : 0; + case PPPIOCSFLAGS: + return get_user(chan_to_pvcc(chan)->flags, (int *) arg) + ? -EFAULT : 0; + } + return -ENOTTY; +} + +static /*const*/ struct ppp_channel_ops pppoatm_ops = { + start_xmit: pppoatm_send, + ioctl: pppoatm_devppp_ioctl, +}; + +static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, unsigned long arg) +{ + struct atm_backend_ppp be; + struct pppoatm_vcc *pvcc; + int err; + /* + * Each PPPoATM instance has its own tasklet - this is just a + * prototypical one used to initialize them + */ + static const DECLARE_TASKLET(tasklet_proto, pppoatm_wakeup_sender, 0); + if (copy_from_user(&be, (void *) arg, sizeof be)) + return -EFAULT; + if (be.encaps != PPPOATM_ENCAPS_AUTODETECT && + be.encaps != PPPOATM_ENCAPS_VC && be.encaps != PPPOATM_ENCAPS_LLC) + return -EINVAL; + MOD_INC_USE_COUNT; + pvcc = kmalloc(sizeof(*pvcc), GFP_KERNEL); + if (pvcc == NULL) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + memset(pvcc, 0, sizeof(*pvcc)); + pvcc->atmvcc = atmvcc; + pvcc->old_push = atmvcc->push; + pvcc->old_pop = atmvcc->pop; + pvcc->encaps = (enum pppoatm_encaps) be.encaps; + pvcc->chan.private = pvcc; + pvcc->chan.ops = &pppoatm_ops; + pvcc->chan.mtu = atmvcc->qos.txtp.max_sdu - PPP_HDRLEN - + (be.encaps == e_vc ? 0 : LLC_LEN); + pvcc->wakeup_tasklet = tasklet_proto; + pvcc->wakeup_tasklet.data = (unsigned long) &pvcc->chan; + if ((err = ppp_register_channel(&pvcc->chan)) != 0) { + kfree(pvcc); + return err; + } + atmvcc->user_back = pvcc; + atmvcc->push = pppoatm_push; + atmvcc->pop = pppoatm_pop; + return 0; +} + +/* + * This handles ioctls actually performed on our vcc - we must return + * -ENOIOCTLCMD for any unrecognized ioctl + */ +static int pppoatm_ioctl(struct atm_vcc *atmvcc, unsigned int cmd, + unsigned long arg) +{ + if (cmd != ATM_SETBACKEND && atmvcc->push != pppoatm_push) + return -ENOIOCTLCMD; + switch (cmd) { + case ATM_SETBACKEND: { + atm_backend_t b; + if (get_user(b, (atm_backend_t *) arg)) + return -EFAULT; + if (b != ATM_BACKEND_PPP) + return -ENOIOCTLCMD; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + return pppoatm_assign_vcc(atmvcc, arg); + } + case PPPIOCGCHAN: + return put_user(ppp_channel_index(&atmvcc_to_pvcc(atmvcc)-> + chan), (int *) arg) ? -EFAULT : 0; + case PPPIOCGUNIT: + return put_user(ppp_unit_number(&atmvcc_to_pvcc(atmvcc)-> + chan), (int *) arg) ? -EFAULT : 0; + } + return -ENOIOCTLCMD; +} + +/* the following avoids some spurious warnings from the compiler */ +#define UNUSED __attribute__((unused)) + +extern int (*pppoatm_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long); + +static int __init UNUSED pppoatm_init(void) +{ + pppoatm_ioctl_hook = pppoatm_ioctl; + return 0; +} + +static void __exit UNUSED pppoatm_exit(void) +{ + pppoatm_ioctl_hook = NULL; +} + +module_init(pppoatm_init); +module_exit(pppoatm_exit); + +MODULE_AUTHOR("Mitchell Blank Jr <mitch@sfgoth.com>"); +MODULE_DESCRIPTION("RFC2364 PPP over ATM/AAL5"); diff -u --recursive --new-file v2.4.14/linux/net/atm/resources.c linux/net/atm/resources.c --- v2.4.14/linux/net/atm/resources.c Fri Dec 29 14:35:47 2000 +++ linux/net/atm/resources.c Fri Nov 9 14:11:15 2001 @@ -36,13 +36,18 @@ if (!dev) return NULL; memset(dev,0,sizeof(*dev)); dev->type = type; - dev->prev = last_dev; dev->signal = ATM_PHY_SIG_UNKNOWN; dev->link_rate = ATM_OC3_PCR; dev->next = NULL; + + spin_lock(&atm_dev_lock); + + dev->prev = last_dev; + if (atm_devs) last_dev->next = dev; else atm_devs = dev; last_dev = dev; + spin_unlock(&atm_dev_lock); return dev; } diff -u --recursive --new-file v2.4.14/linux/net/bluetooth/hci_core.c linux/net/bluetooth/hci_core.c --- v2.4.14/linux/net/bluetooth/hci_core.c Tue Oct 9 17:06:53 2001 +++ linux/net/bluetooth/hci_core.c Fri Nov 9 14:21:21 2001 @@ -891,7 +891,7 @@ /* Limit inquiry time, also avoid overflows */ - if(ir.length > 2048) + if(ir.length > 2048 || ir.num_rsp > 2048) { err = -EINVAL; goto done; diff -u --recursive --new-file v2.4.14/linux/net/core/dev.c linux/net/core/dev.c --- v2.4.14/linux/net/core/dev.c Mon Nov 5 15:55:36 2001 +++ linux/net/core/dev.c Wed Nov 7 14:39:36 2001 @@ -565,11 +565,11 @@ /* * Verify the string as this thing may have come from - * the user. There must be one "%d" and no other "%" - * characters. + * the user. There must be either one "%d" and no other "%" + * characters, or no "%" characters at all. */ p = strchr(name, '%'); - if (!p || p[1] != 'd' || strchr(p+2, '%')) + if (p && (p[1] != 'd' || strchr(p+2, '%'))) return -EINVAL; /* @@ -2221,6 +2221,12 @@ default: if ((cmd >= SIOCDEVPRIVATE && cmd <= SIOCDEVPRIVATE + 15) || + cmd == SIOCBONDENSLAVE || + cmd == SIOCBONDRELEASE || + cmd == SIOCBONDSETHWADDR || + cmd == SIOCBONDSLAVEINFOQUERY || + cmd == SIOCBONDINFOQUERY || + cmd == SIOCBONDCHANGEACTIVE || cmd == SIOCETHTOOL || cmd == SIOCGMIIPHY || cmd == SIOCGMIIREG || @@ -2372,6 +2378,12 @@ case SIOCSIFTXQLEN: case SIOCSIFNAME: case SIOCSMIIREG: + case SIOCBONDENSLAVE: + case SIOCBONDRELEASE: + case SIOCBONDSETHWADDR: + case SIOCBONDSLAVEINFOQUERY: + case SIOCBONDINFOQUERY: + case SIOCBONDCHANGEACTIVE: if (!capable(CAP_NET_ADMIN)) return -EPERM; dev_load(ifr.ifr_name); diff -u --recursive --new-file v2.4.14/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c --- v2.4.14/linux/net/decnet/af_decnet.c Tue Jul 3 17:08:22 2001 +++ linux/net/decnet/af_decnet.c Fri Nov 9 14:12:54 2001 @@ -1003,6 +1003,9 @@ if (DN_SK(newsk)->segsize_rem < 230) DN_SK(newsk)->segsize_rem = 230; + if ((DN_SK(newsk)->services_rem & NSP_FC_MASK) == NSP_FC_NONE) + DN_SK(newsk)->max_window = decnet_no_fc_max_cwnd; + newsk->state = TCP_LISTEN; newsk->zapped = 0; @@ -1072,7 +1075,9 @@ lock_sock(sk); if (peer) { - if (sock->state != SS_CONNECTED && scp->accept_mode == ACC_IMMED) + if ((sock->state != SS_CONNECTED && + sock->state != SS_CONNECTING) && + scp->accept_mode == ACC_IMMED) return -ENOTCONN; memcpy(sa, &scp->peer, sizeof(struct sockaddr_dn)); @@ -2145,6 +2150,7 @@ EXPORT_NO_SYMBOLS; MODULE_DESCRIPTION("The Linux DECnet Network Protocol"); MODULE_AUTHOR("Linux DECnet Project Team"); +MODULE_LICENSE("GPL"); static int addr[2] = {0, 0}; @@ -2152,7 +2158,7 @@ MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node"); #endif -static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.0-test12s (C) 1995-2000 Linux DECnet Project Team\n"; +static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.9s (C) 1995-2001 Linux DECnet Project Team\n"; static int __init decnet_init(void) { diff -u --recursive --new-file v2.4.14/linux/net/decnet/dn_nsp_in.c linux/net/decnet/dn_nsp_in.c --- v2.4.14/linux/net/decnet/dn_nsp_in.c Mon Jan 22 13:32:10 2001 +++ linux/net/decnet/dn_nsp_in.c Fri Nov 9 14:12:54 2001 @@ -355,6 +355,9 @@ scp->info_rem = cb->info; scp->segsize_rem = cb->segsize; + if ((scp->services_rem & NSP_FC_MASK) == NSP_FC_NONE) + scp->max_window = decnet_no_fc_max_cwnd; + if (skb->len > 0) { unsigned char dlen = *skb->data; if ((dlen <= 16) && (dlen <= skb->len)) { diff -u --recursive --new-file v2.4.14/linux/net/decnet/dn_route.c linux/net/decnet/dn_route.c --- v2.4.14/linux/net/decnet/dn_route.c Mon Jan 22 13:32:10 2001 +++ linux/net/decnet/dn_route.c Fri Nov 9 14:12:54 2001 @@ -638,8 +638,8 @@ { struct dn_skb_cb *cb = DN_SKB_CB(skb); struct dst_entry *dst = skb->dst; - struct net_device *dev = skb->dev; struct neighbour *neigh; + struct net_device *dev = skb->dev; int err = -EINVAL; if ((neigh = dst->neighbour) == NULL) diff -u --recursive --new-file v2.4.14/linux/net/decnet/sysctl_net_decnet.c linux/net/decnet/sysctl_net_decnet.c --- v2.4.14/linux/net/decnet/sysctl_net_decnet.c Wed Jul 25 17:10:26 2001 +++ linux/net/decnet/sysctl_net_decnet.c Fri Nov 9 14:12:54 2001 @@ -33,6 +33,7 @@ int decnet_di_count = 3; int decnet_dr_count = 3; int decnet_log_martians = 1; +int decnet_no_fc_max_cwnd = NSP_MIN_WINDOW; #ifdef CONFIG_SYSCTL extern int decnet_dst_gc_interval; @@ -42,6 +43,8 @@ static int max_state_count[] = { NSP_MAXRXTSHIFT }; static int min_decnet_dst_gc_interval[] = { 1 }; static int max_decnet_dst_gc_interval[] = { 60 }; +static int min_decnet_no_fc_max_cwnd[] = { NSP_MIN_WINDOW }; +static int max_decnet_no_fc_max_cwnd[] = { NSP_MAX_WINDOW }; static char node_name[7] = "???"; static struct ctl_table_header *dn_table_header = NULL; @@ -344,6 +347,10 @@ sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_decnet_dst_gc_interval, &max_decnet_dst_gc_interval}, + {NET_DECNET_NO_FC_MAX_CWND, "no_fc_max_cwnd", &decnet_no_fc_max_cwnd, + sizeof(int), 0644, + NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, + &min_decnet_no_fc_max_cwnd, &max_decnet_no_fc_max_cwnd}, {NET_DECNET_DEBUG_LEVEL, "debug", &decnet_debug_level, sizeof(int), 0644, NULL, &proc_dointvec, &sysctl_intvec, NULL, diff -u --recursive --new-file v2.4.14/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.4.14/linux/net/ipv4/icmp.c Sun Sep 23 11:41:01 2001 +++ linux/net/ipv4/icmp.c Wed Nov 7 14:39:36 2001 @@ -3,7 +3,7 @@ * * Alan Cox, <alan@redhat.com> * - * Version: $Id: icmp.c,v 1.81 2001/09/01 00:31:50 davem Exp $ + * Version: $Id: icmp.c,v 1.82 2001/11/01 23:44:31 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -139,7 +139,7 @@ { EHOSTUNREACH, 1 } /* ICMP_PREC_CUTOFF */ }; -/* Control parameters for ECHO relies. */ +/* Control parameters for ECHO replies. */ int sysctl_icmp_echo_ignore_all; int sysctl_icmp_echo_ignore_broadcasts; diff -u --recursive --new-file v2.4.14/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c --- v2.4.14/linux/net/ipv4/ip_input.c Thu Apr 12 12:11:39 2001 +++ linux/net/ipv4/ip_input.c Wed Nov 7 14:39:36 2001 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) module. * - * Version: $Id: ip_input.c,v 1.53 2000/12/18 19:01:50 davem Exp $ + * Version: $Id: ip_input.c,v 1.54 2001/11/06 22:33:52 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> @@ -383,7 +383,7 @@ */ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) { - struct iphdr *iph = skb->nh.iph; + struct iphdr *iph; /* When the interface is in promisc. mode, drop all the crap * that it receives, do not try to analyse it. @@ -417,6 +417,8 @@ if (!pskb_may_pull(skb, iph->ihl*4)) goto inhdr_error; + + iph = skb->nh.iph; if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) goto inhdr_error; diff -u --recursive --new-file v2.4.14/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c --- v2.4.14/linux/net/ipv4/ipconfig.c Mon Nov 5 15:55:36 2001 +++ linux/net/ipv4/ipconfig.c Fri Nov 9 14:19:41 2001 @@ -53,6 +53,7 @@ #include <asm/uaccess.h> #include <asm/checksum.h> +#include <asm/processor.h> /* Define this to allow debugging output */ #undef IPCONFIG_DEBUG @@ -194,8 +195,10 @@ printk(KERN_ERR "IP-Config: Failed to open %s\n", dev->name); continue; } - if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) + if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) { + rtnl_shunlock(); return -1; + } d->dev = dev; *last = d; last = &d->next; @@ -605,6 +608,12 @@ *e++ = 17; /* Boot path */ *e++ = 40; e += 40; + + *e++ = 57; /* set extension buffer size for reply */ + *e++ = 2; + *e++ = 1; /* 128+236+8+20+14, see dhcpd sources */ + *e++ = 150; + *e++ = 255; /* End of the list */ } @@ -1000,8 +1009,10 @@ #endif jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout); - while (jiffies < jiff && !ic_got_reply) + while (jiffies < jiff && !ic_got_reply) { barrier(); + cpu_relax(); + } #ifdef IPCONFIG_DHCP /* DHCP isn't done until we get a DHCPACK. */ if ((ic_got_reply & IC_BOOTP) diff -u --recursive --new-file v2.4.14/linux/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c --- v2.4.14/linux/net/ipv4/netfilter/ip_fw_compat.c Fri Apr 27 14:15:01 2001 +++ linux/net/ipv4/netfilter/ip_fw_compat.c Wed Nov 7 14:39:36 2001 @@ -78,11 +78,19 @@ { int ret = FW_BLOCK; u_int16_t redirpt; + struct sk_buff *nskb; /* Assume worse case: any hook could change packet */ (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED; if ((*pskb)->ip_summed == CHECKSUM_HW) (*pskb)->ip_summed = CHECKSUM_NONE; + + /* Firewall rules can alter TOS: raw socket may have clone of + skb: don't disturb it --RR */ + nskb = skb_unshare(*pskb, GFP_ATOMIC); + if (!nskb) + return NF_DROP; + *pskb = nskb; switch (hooknum) { case NF_IP_PRE_ROUTING: diff -u --recursive --new-file v2.4.14/linux/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c --- v2.4.14/linux/net/ipv4/netfilter/ip_nat_core.c Wed May 16 10:31:27 2001 +++ linux/net/ipv4/netfilter/ip_nat_core.c Wed Nov 7 14:39:36 2001 @@ -734,6 +734,15 @@ synchronize_bh()) can vanish. */ READ_LOCK(&ip_nat_lock); for (i = 0; i < info->num_manips; i++) { + struct sk_buff *nskb; + /* raw socket may have clone of skb: don't disturb it --RR */ + nskb = skb_unshare(*pskb, GFP_ATOMIC); + if (!nskb) { + READ_UNLOCK(&ip_nat_lock); + return NF_DROP; + } + *pskb = nskb; + if (info->manips[i].direction == dir && info->manips[i].hooknum == hooknum) { DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n", diff -u --recursive --new-file v2.4.14/linux/net/ipv4/netfilter/ipt_TCPMSS.c linux/net/ipv4/netfilter/ipt_TCPMSS.c --- v2.4.14/linux/net/ipv4/netfilter/ipt_TCPMSS.c Tue Oct 9 17:06:53 2001 +++ linux/net/ipv4/netfilter/ipt_TCPMSS.c Wed Nov 7 14:39:36 2001 @@ -48,6 +48,13 @@ u_int16_t tcplen, newtotlen, oldval, newmss; unsigned int i; u_int8_t *opt; + struct sk_buff *nskb; + + /* raw socket may have clone of skb: don't disturb it --RR */ + nskb = skb_unshare(*pskb, GFP_ATOMIC); + if (!nskb) + return NF_DROP; + *pskb = nskb; tcplen = (*pskb)->len - iph->ihl*4; diff -u --recursive --new-file v2.4.14/linux/net/ipv4/netfilter/ipt_TOS.c linux/net/ipv4/netfilter/ipt_TOS.c --- v2.4.14/linux/net/ipv4/netfilter/ipt_TOS.c Tue Oct 9 17:06:53 2001 +++ linux/net/ipv4/netfilter/ipt_TOS.c Wed Nov 7 14:39:36 2001 @@ -19,7 +19,14 @@ const struct ipt_tos_target_info *tosinfo = targinfo; if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { + struct sk_buff *nskb; u_int16_t diffs[2]; + + /* raw socket may have clone of skb: don't disturb it --RR */ + nskb = skb_unshare(*pskb, GFP_ATOMIC); + if (!nskb) + return NF_DROP; + *pskb = nskb; diffs[0] = htons(iph->tos) ^ 0xFFFF; iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; diff -u --recursive --new-file v2.4.14/linux/net/irda/af_irda.c linux/net/irda/af_irda.c --- v2.4.14/linux/net/irda/af_irda.c Tue Oct 9 17:06:53 2001 +++ linux/net/irda/af_irda.c Fri Nov 9 14:22:17 2001 @@ -11,7 +11,7 @@ * Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc. * * Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no> - * Copyright (c) 1999 Jean Tourrilhes <jt@hpl.hp.com> + * Copyright (c) 1999-2001 Jean Tourrilhes <jt@hpl.hp.com> * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -134,33 +134,41 @@ IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self); + /* Don't care about it, but let's not leak it */ + if(skb) + dev_kfree_skb(skb); + sk = self->sk; if (sk == NULL) return; - sk->state = TCP_CLOSE; - sk->err = ECONNRESET; - sk->shutdown |= SEND_SHUTDOWN; - if (!sk->dead) { + /* Prevent race conditions with irda_release() and irda_shutdown() */ + if ((!sk->dead) && (sk->state != TCP_CLOSE)) { + sk->state = TCP_CLOSE; + sk->err = ECONNRESET; + sk->shutdown |= SEND_SHUTDOWN; + sk->state_change(sk); - sk->dead = 1; - } + sk->dead = 1; /* Uh-oh... Should use sock_orphan ? */ - /* Close our TSAP. - * If we leave it open, IrLMP put it back into the list of - * unconnected LSAPs. The problem is that any incoming request - * can then be matched to this socket (and it will be, because - * it is at the head of the list). This would prevent any - * listening socket waiting on the same TSAP to get those requests. - * Some apps forget to close sockets, or hang to it a bit too long, - * so we may stay in this dead state long enough to be noticed... - * Note : all socket function do check sk->state, so we are safe... - * Jean II - */ - if (self->tsap) { - irttp_close_tsap(self->tsap); - self->tsap = NULL; - } + /* Close our TSAP. + * If we leave it open, IrLMP put it back into the list of + * unconnected LSAPs. The problem is that any incoming request + * can then be matched to this socket (and it will be, because + * it is at the head of the list). This would prevent any + * listening socket waiting on the same TSAP to get those + * requests. Some apps forget to close sockets, or hang to it + * a bit too long, so we may stay in this dead state long + * enough to be noticed... + * Note : all socket function do check sk->state, so we are + * safe... + * Jean II + */ + if (self->tsap) { + irttp_close_tsap(self->tsap); + self->tsap = NULL; + } + } /* Note : once we are there, there is not much you want to do * with the socket anymore, apart from closing it. @@ -222,7 +230,8 @@ self->max_data_size); memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); - kfree_skb(skb); + dev_kfree_skb(skb); + // Should be ??? skb_queue_tail(&sk->receive_queue, skb); /* We are now connected! */ sk->state = TCP_ESTABLISHED; @@ -1205,7 +1214,7 @@ sk->protinfo.irda = NULL; sock_orphan(sk); - sock->sk = NULL; + sock->sk = NULL; /* Purge queues (see sock_init_data()) */ skb_queue_purge(&sk->receive_queue); diff -u --recursive --new-file v2.4.14/linux/net/irda/ircomm/ircomm_param.c linux/net/irda/ircomm/ircomm_param.c --- v2.4.14/linux/net/irda/ircomm/ircomm_param.c Tue Mar 21 11:17:28 2000 +++ linux/net/irda/ircomm/ircomm_param.c Fri Nov 9 14:22:17 2001 @@ -182,13 +182,13 @@ int get) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - __u8 service_type = param->pv.b; /* We know it's a one byte integer */ + __u8 service_type = (__u8) param->pv.i; ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); if (get) { - param->pv.b = self->settings.service_type; + param->pv.i = self->settings.service_type; return 0; } @@ -246,9 +246,9 @@ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); if (get) - param->pv.b = IRCOMM_SERIAL; + param->pv.i = IRCOMM_SERIAL; else { - self->settings.port_type = param->pv.b; + self->settings.port_type = (__u8) param->pv.i; IRDA_DEBUG(0, __FUNCTION__ "(), port type=%d\n", self->settings.port_type); @@ -317,9 +317,9 @@ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); if (get) - param->pv.b = self->settings.data_format; + param->pv.i = self->settings.data_format; else - self->settings.data_format = param->pv.b; + self->settings.data_format = (__u8) param->pv.i; return 0; } @@ -339,11 +339,11 @@ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); if (get) - param->pv.b = self->settings.flow_control; + param->pv.i = self->settings.flow_control; else - self->settings.flow_control = param->pv.b; + self->settings.flow_control = (__u8) param->pv.i; - IRDA_DEBUG(1, __FUNCTION__ "(), flow control = 0x%02x\n", param->pv.b); + IRDA_DEBUG(1, __FUNCTION__ "(), flow control = 0x%02x\n", (__u8) param->pv.i); return 0; } @@ -362,15 +362,15 @@ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); if (get) { - param->pv.s = self->settings.xonxoff[0]; - param->pv.s |= self->settings.xonxoff[1] << 8; + param->pv.i = self->settings.xonxoff[0]; + param->pv.i |= self->settings.xonxoff[1] << 8; } else { - self->settings.xonxoff[0] = param->pv.s & 0xff; - self->settings.xonxoff[1] = param->pv.s >> 8; + self->settings.xonxoff[0] = (__u16) param->pv.i & 0xff; + self->settings.xonxoff[1] = (__u16) param->pv.i >> 8; } IRDA_DEBUG(0, __FUNCTION__ "(), XON/XOFF = 0x%02x,0x%02x\n", - param->pv.s & 0xff, param->pv.s >> 8); + param->pv.i & 0xff, param->pv.i >> 8); return 0; } @@ -389,15 +389,15 @@ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); if (get) { - param->pv.s = self->settings.enqack[0]; - param->pv.s |= self->settings.enqack[1] << 8; + param->pv.i = self->settings.enqack[0]; + param->pv.i |= self->settings.enqack[1] << 8; } else { - self->settings.enqack[0] = param->pv.s & 0xff; - self->settings.enqack[1] = param->pv.s >> 8; + self->settings.enqack[0] = (__u16) param->pv.i & 0xff; + self->settings.enqack[1] = (__u16) param->pv.i >> 8; } IRDA_DEBUG(0, __FUNCTION__ "(), ENQ/ACK = 0x%02x,0x%02x\n", - param->pv.s & 0xff, param->pv.s >> 8); + param->pv.i & 0xff, param->pv.i >> 8); return 0; } @@ -431,9 +431,9 @@ ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); if (get) - param->pv.b = self->settings.dte; + param->pv.i = self->settings.dte; else { - dte = param->pv.b; + dte = (__u8) param->pv.i; if (dte & IRCOMM_DELTA_DTR) self->settings.dce |= (IRCOMM_DELTA_DSR| @@ -470,9 +470,9 @@ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; __u8 dce; - IRDA_DEBUG(1, __FUNCTION__ "(), dce = 0x%02x\n", param->pv.b); + IRDA_DEBUG(1, __FUNCTION__ "(), dce = 0x%02x\n", (__u8) param->pv.i); - dce = param->pv.b; + dce = (__u8) param->pv.i; ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); diff -u --recursive --new-file v2.4.14/linux/net/irda/irda_device.c linux/net/irda/irda_device.c --- v2.4.14/linux/net/irda/irda_device.c Sun Sep 23 11:41:02 2001 +++ linux/net/irda/irda_device.c Fri Nov 9 14:22:17 2001 @@ -10,6 +10,7 @@ * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -65,6 +66,8 @@ extern int tekram_init(void); extern int actisys_init(void); extern int girbil_init(void); +extern int sa1100_irda_init(void); +extern int ep7211_ir_init(void); static void __irda_task_delete(struct irda_task *task); @@ -124,6 +127,9 @@ #ifdef CONFIG_WINBOND_FIR w83977af_init(); #endif +#ifdef CONFIG_SA1100_FIR + sa1100_irda_init(); +#endif #ifdef CONFIG_NSC_FIR nsc_ircc_init(); #endif @@ -151,6 +157,9 @@ #ifdef CONFIG_OLD_BELKIN old_belkin_init(); #endif +#ifdef CONFIG_EP7211_IR + ep7211_ir_init(); +#endif return 0; } @@ -181,7 +190,10 @@ if (status) { self->media_busy = TRUE; - irlap_start_mbusy_timer(self); + if (status == SMALL) + irlap_start_mbusy_timer(self, SMALLBUSY_TIMEOUT); + else + irlap_start_mbusy_timer(self, MEDIABUSY_TIMEOUT); IRDA_DEBUG( 4, "Media busy!\n"); } else { self->media_busy = FALSE; diff -u --recursive --new-file v2.4.14/linux/net/irda/iriap.c linux/net/irda/iriap.c --- v2.4.14/linux/net/irda/iriap.c Sun Sep 23 11:41:02 2001 +++ linux/net/irda/iriap.c Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -773,7 +774,7 @@ { struct iriap_cb *self, *new; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); self = (struct iriap_cb *) instance; diff -u --recursive --new-file v2.4.14/linux/net/irda/irlap.c linux/net/irda/irlap.c --- v2.4.14/linux/net/irda/irlap.c Sun Sep 23 11:41:02 2001 +++ linux/net/irda/irlap.c Fri Nov 9 14:22:17 2001 @@ -10,6 +10,7 @@ * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -502,10 +503,17 @@ IRDA_DEBUG(4, __FUNCTION__ "(), discovery only possible in NDM mode\n"); irlap_discovery_confirm(self, NULL); + /* Note : in theory, if we are not in NDM, we could postpone + * the discovery like we do for connection request. + * In practice, it's not worth it. If the media was busy, + * it's likely next time around it won't be busy. If we are + * in REPLY state, we will get passive discovery info & event. + * Jean II */ return; } - /* Check if last discovery request finished in time */ + /* Check if last discovery request finished in time, or if + * it was aborted due to the media busy flag. */ if (self->discovery_log != NULL) { hashbin_delete(self->discovery_log, (FREE_FUNC) kfree); self->discovery_log = NULL; @@ -555,10 +563,16 @@ /* * Check for successful discovery, since we are then allowed to clear - * the media busy condition (irlap p.94). This should allow us to make - * connection attempts much easier. + * the media busy condition (IrLAP 6.13.4 - p.94). This should allow + * us to make connection attempts much faster and easier (i.e. no + * collisions). + * Setting media busy to false will also generate an event allowing + * to process pending events in NDM state machine. + * Note : the spec doesn't define what's a successful discovery is. + * If we want Ultra to work, it's successful even if there is + * nobody discovered - Jean II */ - if (discovery_log && HASHBIN_GET_SIZE(discovery_log) > 0) + if (discovery_log) irda_device_set_media_busy(self->netdev, FALSE); /* Inform IrLMP */ @@ -580,7 +594,18 @@ ASSERT(discovery != NULL, return;); ASSERT(self->notify.instance != NULL, return;); - + + /* A device is very likely to connect immediately after it performs + * a successful discovery. This means that in our case, we are much + * more likely to receive a connection request over the medium. + * So, we backoff to avoid collisions. + * IrLAP spec 6.13.4 suggest 100ms... + * Note : this little trick actually make a *BIG* difference. If I set + * my Linux box with discovery enabled and one Ultra frame sent every + * second, my Palm has no trouble connecting to it every time ! + * Jean II */ + irda_device_set_media_busy(self->netdev, SMALL); + irlmp_link_discovery_indication(self->notify.instance, discovery); } diff -u --recursive --new-file v2.4.14/linux/net/irda/irlap_event.c linux/net/irda/irlap_event.c --- v2.4.14/linux/net/irda/irlap_event.c Tue Oct 9 17:06:53 2001 +++ linux/net/irda/irlap_event.c Fri Nov 9 14:22:17 2001 @@ -12,6 +12,7 @@ * Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>, * Copyright (c) 1998 Thomas Davis <ratbert@radiks.net> * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -114,6 +115,7 @@ "DISCOVERY_TIMER_EXPIRED", "WD_TIMER_EXPIRED", "BACKOFF_TIMER_EXPIRED", + "MEDIA_BUSY_TIMER_EXPIRED", }; const char *irlap_state[] = { @@ -263,15 +265,7 @@ NULL, NULL); } break; - case LAP_NDM: - /* Check if we should try to connect */ - if ((self->connect_pending) && !self->media_busy) { - self->connect_pending = FALSE; - - ret = (*state[self->state])(self, CONNECT_REQUEST, - NULL, NULL); - } - break; +/* case LAP_NDM: */ /* case LAP_CONN: */ /* case LAP_RESET_WAIT: */ /* case LAP_RESET_CHECK: */ @@ -305,17 +299,6 @@ if ((state != LAP_XMIT_P) && (state != LAP_XMIT_S)) self->bytes_left = self->line_capacity; #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ -#ifdef CONFIG_IRDA_ULTRA - /* Send any pending Ultra frames if any */ - /* The higher layers may have sent a few Ultra frames while we - * were doing discovery (either query or reply). Those frames - * have been queued, but were never sent. It is now time to - * send them... - * Jean II */ - if ((state == LAP_NDM) && (!skb_queue_empty(&self->txq_ultra))) - /* Force us to listen 500 ms before sending Ultra */ - irda_device_set_media_busy(self->netdev, TRUE); -#endif /* CONFIG_IRDA_ULTRA */ } /* @@ -339,6 +322,9 @@ ASSERT(self->netdev != NULL, return -1;); if (self->media_busy) { + /* Note : this will never happen, because we test + * media busy in irlap_connect_request() and + * postpone the event... - Jean II */ IRDA_DEBUG(0, __FUNCTION__ "(), CONNECT_REQUEST: media busy!\n"); @@ -379,6 +365,9 @@ /* This will make IrLMP try again */ irlap_discovery_confirm(self, NULL); + /* Note : the discovery log is not cleaned up here, + * it will be done in irlap_discovery_request() + * Jean II */ return 0; } @@ -417,8 +406,7 @@ */ irlap_start_query_timer(self, QUERY_TIMEOUT*info->S); irlap_next_state(self, LAP_REPLY); - } - else { + } else { /* This is the final slot. How is it possible ? * This would happen is both discoveries are just slightly * offset (if they are in sync, all packets are lost). @@ -440,6 +428,54 @@ irlap_discovery_indication(self, info->discovery); } break; + case MEDIA_BUSY_TIMER_EXPIRED: + /* A bunch of events may be postponed because the media is + * busy (usually immediately after we close a connection), + * or while we are doing discovery (state query/reply). + * In all those cases, the media busy flag will be cleared + * when it's OK for us to process those postponed events. + * This event is not mentioned in the state machines in the + * IrLAP spec. It's because they didn't consider Ultra and + * postponing connection request is optional. + * Jean II */ +#ifdef CONFIG_IRDA_ULTRA + /* Send any pending Ultra frames if any */ + if (!skb_queue_empty(&self->txq_ultra)) { + /* We don't send the frame, just post an event. + * Also, previously this code was in timer.c... + * Jean II */ + ret = (*state[self->state])(self, SEND_UI_FRAME, + NULL, NULL); + } +#endif /* CONFIG_IRDA_ULTRA */ + /* Check if we should try to connect. + * This code was previously in irlap_do_event() */ + if (self->connect_pending) { + self->connect_pending = FALSE; + + /* This one *should* not pend in this state, except + * if a socket try to connect and immediately + * disconnect. - clear - Jean II */ + if (self->disconnect_pending) + irlap_disconnect_indication(self, LAP_DISC_INDICATION); + else + ret = (*state[self->state])(self, + CONNECT_REQUEST, + NULL, NULL); + self->disconnect_pending = FALSE; + } + /* Note : one way to test if this code works well (including + * media busy and small busy) is to create a user space + * application generating an Ultra packet every 3.05 sec (or + * 2.95 sec) and to see how it interact with discovery. + * It's fairly easy to check that no packet is lost, that the + * packets are postponed during discovery and that after + * discovery indication you have a 100ms "gap". + * As connection request and Ultra are now processed the same + * way, this avoid the tedious job of trying IrLAP connection + * in all those cases... + * Jean II */ + break; #ifdef CONFIG_IRDA_ULTRA case SEND_UI_FRAME: /* Only allowed to repeat an operation twice */ @@ -735,8 +771,10 @@ break; case DISCONNECT_REQUEST: + IRDA_DEBUG(0, __FUNCTION__ "(), Disconnect request!\n"); irlap_send_dm_frame(self); - irlap_next_state( self, LAP_CONN); + irlap_next_state( self, LAP_NDM); + irlap_disconnect_indication(self, LAP_DISC_INDICATION); break; default: IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event, @@ -1417,13 +1455,12 @@ irlap_start_final_timer(self, self->final_timeout); break; case RECV_RD_RSP: - IRDA_DEBUG(0, __FUNCTION__ "(), RECV_RD_RSP\n"); + IRDA_DEBUG(1, __FUNCTION__ "(), RECV_RD_RSP\n"); - irlap_next_state(self, LAP_PCLOSE); - irlap_send_disc_frame(self); irlap_flush_all_queues(self); - irlap_start_final_timer(self, self->final_timeout); - self->retry_count = 0; + irlap_next_state(self, LAP_XMIT_P); + /* Call back the LAP state machine to do a proper disconnect */ + irlap_disconnect_request(self); break; default: IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n", diff -u --recursive --new-file v2.4.14/linux/net/irda/irlap_frame.c linux/net/irda/irlap_frame.c --- v2.4.14/linux/net/irda/irlap_frame.c Wed Jul 25 17:10:27 2001 +++ linux/net/irda/irlap_frame.c Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -696,7 +697,7 @@ static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info, int command) { - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(2, __FUNCTION__ "()\n"); /* Check if this is a command or a response frame */ if (command) diff -u --recursive --new-file v2.4.14/linux/net/irda/irlmp.c linux/net/irda/irlmp.c --- v2.4.14/linux/net/irda/irlmp.c Tue Oct 9 17:06:53 2001 +++ linux/net/irda/irlmp.c Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -75,7 +76,7 @@ */ int __init irlmp_init(void) { - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); /* Initialize the irlmp structure. */ irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL); if (irlmp == NULL) @@ -170,14 +171,14 @@ #endif /* CONFIG_IRDA_ULTRA */ } else self->dlsap_sel = LSAP_ANY; - self->connected = FALSE; + /* self->connected = FALSE; -> already NULL via memset() */ init_timer(&self->watchdog_timer); ASSERT(notify->instance != NULL, return NULL;); self->notify = *notify; - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); + self->lsap_state = LSAP_DISCONNECTED; /* Insert into queue of unconnected LSAPs */ hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self, @@ -237,6 +238,7 @@ ASSERT(lap->magic == LMP_LAP_MAGIC, return;); lsap = hashbin_remove(lap->lsaps, (int) self, NULL); } + self->lap = NULL; /* Check if we found the LSAP! If not then try the unconnected lsaps */ if (!lsap) { lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self, @@ -281,7 +283,7 @@ lap->daddr = DEV_ADDR_ANY; lap->lsaps = hashbin_new(HB_GLOBAL); - irlmp_next_lap_state(lap, LAP_STANDBY); + lap->lap_state = LAP_STANDBY; init_timer(&lap->idle_timer); @@ -346,7 +348,7 @@ "(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", self->slsap_sel, dlsap_sel, saddr, daddr); - if (self->connected) + if (test_bit(0, &self->connected)) return -EISCONN; /* Client must supply destination device address */ @@ -435,7 +437,7 @@ hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (int) self, NULL); - self->connected = TRUE; + set_bit(0, &self->connected); /* TRUE */ /* * User supplied qos specifications? @@ -481,6 +483,8 @@ self->notify.connect_indication(self->notify.instance, self, &self->qos, max_seg_size, max_header_size, skb); + else + dev_kfree_skb(skb); } /* @@ -495,7 +499,7 @@ ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); ASSERT(userdata != NULL, return -1;); - self->connected = TRUE; + set_bit(0, &self->connected); /* TRUE */ IRDA_DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", self->slsap_sel, self->dlsap_sel); @@ -543,7 +547,8 @@ self->notify.connect_confirm(self->notify.instance, self, &self->qos, max_seg_size, max_header_size, skb); - } + } else + dev_kfree_skb(skb); } /* @@ -598,16 +603,18 @@ ASSERT(self != NULL, return -1;); ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); + ASSERT(userdata != NULL, return -1;); - /* Already disconnected? */ - if (!self->connected) { - WARNING(__FUNCTION__ "(), already disconnected!\n"); + /* Already disconnected ? + * There is a race condition between irlmp_disconnect_indication() + * and us that might mess up the hashbins below. This fixes it. + * Jean II */ + if (! test_and_clear_bit(0, &self->connected)) { + IRDA_DEBUG(0, __FUNCTION__ "(), already disconnected!\n"); + dev_kfree_skb(userdata); return -1; } - ASSERT(userdata != NULL, return -1;); - ASSERT(self->connected == TRUE, return -1;); - skb_push(userdata, LMP_CONTROL_HEADER); /* @@ -634,7 +641,6 @@ NULL); /* Reset some values */ - self->connected = FALSE; self->dlsap_sel = LSAP_ANY; self->lap = NULL; @@ -651,16 +657,23 @@ { struct lsap_cb *lsap; - IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]); + IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lmp_reasons[reason]); ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - ASSERT(self->connected == TRUE, return;); IRDA_DEBUG(3, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", self->slsap_sel, self->dlsap_sel); - self->connected = FALSE; - self->dlsap_sel = LSAP_ANY; + /* Already disconnected ? + * There is a race condition between irlmp_disconnect_request() + * and us that might mess up the hashbins below. This fixes it. + * Jean II */ + if (! test_and_clear_bit(0, &self->connected)) { + IRDA_DEBUG(0, __FUNCTION__ "(), already disconnected!\n"); + if (userdata) + dev_kfree_skb(userdata); + return; + } #ifdef CONFIG_IRDA_CACHE_LAST_LSAP irlmp->cache.valid = FALSE; @@ -679,6 +692,7 @@ hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, (int) lsap, NULL); + self->dlsap_sel = LSAP_ANY; self->lap = NULL; /* @@ -689,7 +703,8 @@ self, reason, userdata); else { IRDA_DEBUG(0, __FUNCTION__ "(), no handler\n"); - dev_kfree_skb(userdata); + if (userdata) + dev_kfree_skb(userdata); } } @@ -1401,7 +1416,7 @@ irlmp_client_t *client; __u32 handle; - IRDA_DEBUG(0, __FUNCTION__ "()\n"); + IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(irlmp != NULL, return 0;); /* Get a unique handle for this client */ @@ -1673,14 +1688,15 @@ len += sprintf(buf+len, "saddr: %#08x, daddr: %#08x, ", lap->saddr, lap->daddr); - len += sprintf(buf+len, "refcount: %d", lap->refcount); + len += sprintf(buf+len, "num lsaps: %d", + HASHBIN_GET_SIZE(lap->lsaps)); len += sprintf(buf+len, "\n"); - len += sprintf(buf+len, "\nConnected LSAPs:\n"); + len += sprintf(buf+len, "\n Connected LSAPs:\n"); self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); while (self != NULL) { ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;); - len += sprintf(buf+len, "lsap state: %s, ", + len += sprintf(buf+len, " lsap state: %s, ", irlsap_state[ self->lsap_state]); len += sprintf(buf+len, "slsap_sel: %#02x, dlsap_sel: %#02x, ", diff -u --recursive --new-file v2.4.14/linux/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c --- v2.4.14/linux/net/irda/irlmp_event.c Sun Sep 23 11:41:02 2001 +++ linux/net/irda/irlmp_event.c Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -114,6 +115,25 @@ irlmp_state_setup_pend }; +static inline void irlmp_next_lap_state(struct lap_cb *self, + IRLMP_STATE state) +{ + /* + IRDA_DEBUG(4, __FUNCTION__ "(), LMP LAP = %s\n", irlmp_state[state]); + */ + self->lap_state = state; +} + +static inline void irlmp_next_lsap_state(struct lsap_cb *self, + LSAP_STATE state) +{ + /* + ASSERT(self != NULL, return;); + IRDA_DEBUG(4, __FUNCTION__ "(), LMP LSAP = %s\n", irlsap_state[state]); + */ + self->lsap_state = state; +} + /* Do connection control events */ int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, struct sk_buff *skb) @@ -223,7 +243,6 @@ IRDA_DEBUG(4, __FUNCTION__ "() LS_CONNECT_REQUEST\n"); irlmp_next_lap_state(self, LAP_U_CONNECT); - self->refcount++; /* FIXME: need to set users requested QoS */ irlap_connect_request(self->irlap, self->daddr, NULL, 0); @@ -278,12 +297,12 @@ * the lsaps may already have gone. This avoid getting stuck * forever in LAP_ACTIVE state - Jean II */ if (HASHBIN_GET_SIZE(self->lsaps) == 0) { + IRDA_DEBUG(0, __FUNCTION__ "() NO LSAPs !\n"); irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); } break; case LM_LAP_CONNECT_REQUEST: /* Already trying to connect */ - self->refcount++; break; case LM_LAP_CONNECT_CONFIRM: /* For all lsap_ce E Associated do LS_Connect_confirm */ @@ -298,12 +317,13 @@ * the lsaps may already have gone. This avoid getting stuck * forever in LAP_ACTIVE state - Jean II */ if (HASHBIN_GET_SIZE(self->lsaps) == 0) { + IRDA_DEBUG(0, __FUNCTION__ "() NO LSAPs !\n"); irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); } break; case LM_LAP_DISCONNECT_INDICATION: + IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_INDICATION\n"); irlmp_next_lap_state(self, LAP_STANDBY); - self->refcount = 0; /* Send disconnect event to all LSAPs using this link */ lsap = (struct lsap_cb *) hashbin_get_first( self->lsaps); @@ -322,9 +342,11 @@ case LM_LAP_DISCONNECT_REQUEST: IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n"); - self->refcount--; - if (self->refcount == 0) - irlmp_next_lap_state(self, LAP_STANDBY); + /* One of the LSAP did timeout or was closed, if it was + * the last one, try to get out of here - Jean II */ + if (HASHBIN_GET_SIZE(self->lsaps) <= 1) { + irlap_disconnect_request(self->irlap); + } break; default: IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", @@ -352,7 +374,6 @@ switch (event) { case LM_LAP_CONNECT_REQUEST: IRDA_DEBUG(4, __FUNCTION__ "(), LS_CONNECT_REQUEST\n"); - self->refcount++; /* * LAP connection allready active, just bounce back! Since we @@ -379,8 +400,6 @@ /* Keep state */ break; case LM_LAP_DISCONNECT_REQUEST: - self->refcount--; - /* * Need to find out if we should close IrLAP or not. If there * is only one LSAP connection left on this link, that LSAP @@ -419,7 +438,6 @@ break; case LM_LAP_DISCONNECT_INDICATION: irlmp_next_lap_state(self, LAP_STANDBY); - self->refcount = 0; /* In some case, at this point our side has already closed * all lsaps, and we are waiting for the idle_timer to @@ -517,6 +535,8 @@ * If we receive this event while our LAP is closing down, * the LM_LAP_CONNECT_REQUEST get lost and we get stuck in * CONNECT_PEND state forever. + * The other cause of getting stuck down there is if the + * higher layer never reply to the CONNECT_INDICATION. * Anyway, it make sense to make sure that we always have * a backup plan. 1 second is plenty (should be immediate). * Jean II */ @@ -577,9 +597,8 @@ * Jean II */ IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n"); - /* Here, we should probably disconnect proper */ + /* Disconnect, get out... - Jean II */ self->dlsap_sel = LSAP_ANY; - self->conn_skb = NULL; irlmp_next_lsap_state(self, LSAP_DISCONNECTED); break; default: @@ -612,15 +631,6 @@ case LM_CONNECT_REQUEST: /* Keep state */ break; - case LM_CONNECT_INDICATION: - /* Will happen in some rare cases when the socket get stuck, - * the other side retries the connect request. - * We just unstuck the socket - Jean II */ - IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_INDICATION, " - "LSAP stuck in CONNECT_PEND state...\n"); - /* Keep state */ - irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); - break; case LM_CONNECT_RESPONSE: IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, " "no indication issued yet\n"); @@ -648,6 +658,8 @@ /* Go back to disconnected mode, keep the socket waiting */ self->dlsap_sel = LSAP_ANY; + if(self->conn_skb) + dev_kfree_skb(self->conn_skb); self->conn_skb = NULL; irlmp_next_lsap_state(self, LSAP_DISCONNECTED); break; @@ -856,7 +868,7 @@ irlmp_next_lsap_state(self, LSAP_SETUP); break; case LM_WATCHDOG_TIMEOUT: - IRDA_DEBUG(0, __FUNCTION__ "() WATCHDOG_TIMEOUT!\n"); + IRDA_DEBUG(0, __FUNCTION__ "() : WATCHDOG_TIMEOUT !\n"); ASSERT(self->lap != NULL, return -1;); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); @@ -881,18 +893,4 @@ break; } return ret; -} - -void irlmp_next_lap_state(struct lap_cb *self, IRLMP_STATE state) -{ - IRDA_DEBUG(4, __FUNCTION__ "(), LMP LAP = %s\n", irlmp_state[state]); - self->lap_state = state; -} - -void irlmp_next_lsap_state(struct lsap_cb *self, LSAP_STATE state) -{ - ASSERT(self != NULL, return;); - - IRDA_DEBUG(4, __FUNCTION__ "(), LMP LSAP = %s\n", irlsap_state[state]); - self->lsap_state = state; } diff -u --recursive --new-file v2.4.14/linux/net/irda/irlmp_frame.c linux/net/irda/irlmp_frame.c --- v2.4.14/linux/net/irda/irlmp_frame.c Sun Sep 23 11:41:02 2001 +++ linux/net/irda/irlmp_frame.c Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no> * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -34,9 +35,6 @@ #include <net/irda/irlmp_frame.h> #include <net/irda/discovery.h> -#define DISCO_SMALL_DELAY 250 /* Delay for some discoveries in ms */ -struct timer_list disco_delay; /* The timer associated */ - static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap, __u8 slsap, int status, hashbin_t *); @@ -343,28 +341,6 @@ } /* - * Function irlmp_discovery_timeout (priv) - * - * Create a discovery event to the state machine (called after a delay) - * - * Note : irlmp_do_lap_event will handle the very rare case where the LAP - * is destroyed while we were sleeping. - */ -static void irlmp_discovery_timeout(u_long priv) -{ - struct lap_cb *self; - - IRDA_DEBUG(2, __FUNCTION__ "()\n"); - - self = (struct lap_cb *) priv; - ASSERT(self != NULL, return;); - - /* Just handle it the same way as a discovery confirm, - * bypass the LM_LAP state machine (see below) */ - irlmp_discovery_confirm(irlmp->cachelog); -} - -/* * Function irlmp_link_discovery_indication (self, log) * * Device is discovering us @@ -379,25 +355,16 @@ * o Make faster discovery, statistically divide time of discovery * events by 2 (important for the latency aspect and user feel) * o Even is we do active discovery, the other node might not - * answer our discoveries (ex: Palm). + * answer our discoveries (ex: Palm). The Palm will just perform + * one active discovery and connect directly to us. * * However, when both devices discover each other, they might attempt to * connect to each other following the discovery event, and it would create * collisions on the medium (SNRM battle). - * The trick here is to defer the event by a little delay to avoid both - * devices to jump in exactly at the same time... - * - * The delay is currently set to 0.25s, which leave enough time to perform - * a connection and don't interfer with next discovery (the lowest discovery - * period/timeout that may be set is 1s). The message triggering this - * event was the last of the discovery, so the medium is now free... - * Maybe more testing is needed to get the value right... - - * One more problem : the other node might do only a single discovery - * and connect immediately to us, and we would receive only a single - * discovery indication event, and because of the delay, it will arrive - * while the LAP is connected. That's another good reason to - * bypass the LM_LAP state machine ;-) + * The "fix" for that is to disable all connection requests in IrLAP + * for 100ms after a discovery indication by setting the media_busy flag. + * Previously, we used to postpone the event which was quite ugly. Now + * that IrLAP takes care of this problem, just pass the event up... * * Jean II */ @@ -409,14 +376,9 @@ irlmp_add_discovery(irlmp->cachelog, discovery); - /* If delay was activated, kill it! */ - if(timer_pending(&disco_delay)) - del_timer(&disco_delay); - /* Set delay timer to expire in 0.25s. */ - disco_delay.expires = jiffies + (DISCO_SMALL_DELAY * HZ/1000); - disco_delay.function = irlmp_discovery_timeout; - disco_delay.data = (unsigned long) self; - add_timer(&disco_delay); + /* Just handle it the same way as a discovery confirm, + * bypass the LM_LAP state machine (see below) */ + irlmp_discovery_confirm(irlmp->cachelog); } /* @@ -435,10 +397,6 @@ ASSERT(self->magic == LMP_LAP_MAGIC, return;); irlmp_add_discovery_log(irlmp->cachelog, log); - - /* If discovery delay was activated, kill it! */ - if(timer_pending(&disco_delay)) - del_timer(&disco_delay); /* Propagate event to various LSAPs registered for it. * We bypass the LM_LAP state machine because diff -u --recursive --new-file v2.4.14/linux/net/irda/irnet/irnet.h linux/net/irda/irnet/irnet.h --- v2.4.14/linux/net/irda/irnet/irnet.h Sun Sep 23 11:41:02 2001 +++ linux/net/irda/irnet/irnet.h Fri Nov 9 14:22:17 2001 @@ -126,17 +126,17 @@ * History : * ------- * - * v1 - 15/5/00 - Jean II + * v1 - 15.5.00 - Jean II * o Basic IrNET (hook to ppp_generic & IrTTP - incl. multipoint) * o control channel on /dev/irnet (set name/address) * o event channel on /dev/irnet (for user space daemon) * - * v2 - 5/6/00 - Jean II + * v2 - 5.6.00 - Jean II * o Enable DROP_NOT_READY to avoid PPP timeouts & other weirdness... * o Add DISCONNECT_TO event and rename DISCONNECT_FROM. * o Set official device number alloaction on /dev/irnet * - * v3 - 30/8/00 - Jean II + * v3 - 30.8.00 - Jean II * o Update to latest Linux-IrDA changes : * - queue_t => irda_queue_t * o Update to ppp-2.4.0 : @@ -148,17 +148,17 @@ * another multilink bug (darn !) * o Remove LINKNAME_IOCTL cruft * - * v3b - 31/8/00 - Jean II + * v3b - 31.8.00 - Jean II * o Dump discovery log at event channel startup * - * v4 - 28/9/00 - Jean II + * v4 - 28.9.00 - Jean II * o Fix interaction between poll/select and dump discovery log * o Add IRNET_BLOCKED_LINK event (depend on new IrDA-Linux patch) * o Add IRNET_NOANSWER_FROM event (mostly to help support) * o Release flow control in disconnect_indication * o Block packets while connecting (speed up connections) * - * v5 - 11/01/01 - Jean II + * v5 - 11.01.01 - Jean II * o Init self->max_header_size, just in case... * o Set up ap->chan.hdrlen, to get zero copy on tx side working. * o avoid tx->ttp->flow->ppp->tx->... loop, by checking flow state @@ -169,7 +169,7 @@ * o Declare hashbin HB_NOLOCK instead of HB_LOCAL to avoid * disabling and enabling irq twice * - * v6 - 31/05/01 - Jean II + * v6 - 31.05.01 - Jean II * o Print source address in Found, Discovery, Expiry & Request events * o Print requested source address in /proc/net/irnet * o Change control channel input. Allow multiple commands in one line. @@ -186,12 +186,19 @@ * o Add ttp_connect flag to prevent rentry on the connect procedure * o Test and fixups to eliminate side effects of retries * - * v7 - 22/08/01 - Jean II + * v7 - 22.08.01 - Jean II * o Cleanup : Change "saddr = 0x0" to "saddr = DEV_ADDR_ANY" * o Fix bug in BLOCK_WHEN_CONNECT introduced in v6 : due to the * asynchronous IAS query, self->tsap is NULL when PPP send the * first packet. This was preventing "connect-delay 0" to work. * Change the test in ppp_irnet_send() to self->ttp_connect. + * + * v8 - 1.11.01 - Jean II + * o Tighten the use of self->ttp_connect and self->ttp_open to + * prevent various race conditions. + * o Avoid leaking discovery log and skb + * o Replace "self" with "server" in irnet_connect_indication() to + * better detect cut'n'paste error ;-) */ /***************************** INCLUDES *****************************/ @@ -204,6 +211,7 @@ #include <linux/proc_fs.h> #include <linux/devfs_fs_kernel.h> #include <linux/netdevice.h> +#include <linux/miscdevice.h> #include <linux/poll.h> #include <linux/config.h> #include <linux/ctype.h> /* isspace() */ diff -u --recursive --new-file v2.4.14/linux/net/irda/irnet/irnet_irda.c linux/net/irda/irnet/irnet_irda.c --- v2.4.14/linux/net/irda/irnet/irnet_irda.c Tue Oct 9 17:06:53 2001 +++ linux/net/irda/irnet/irnet_irda.c Fri Nov 9 14:22:17 2001 @@ -272,7 +272,7 @@ err = irnet_open_tsap(self); if(err != 0) { - self->ttp_connect = 0; + clear_bit(0, &self->ttp_connect); DERROR(IRDA_SR_ERROR, "connect aborted!\n"); return(err); } @@ -283,7 +283,7 @@ self->max_sdu_size_rx, NULL); if(err != 0) { - self->ttp_connect = 0; + clear_bit(0, &self->ttp_connect); DERROR(IRDA_SR_ERROR, "connect aborted!\n"); return(err); } @@ -377,7 +377,7 @@ if(self->discoveries == NULL) { self->disco_number = -1; - self->ttp_connect = 0; + clear_bit(0, &self->ttp_connect); DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n"); } DEBUG(IRDA_SR_INFO, "Got the log (0x%X), size is %d\n", @@ -399,7 +399,7 @@ kfree(self->discoveries); self->discoveries = NULL; - self->ttp_connect = 0; + clear_bit(0, &self->ttp_connect); DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n"); } @@ -518,12 +518,12 @@ DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self); - /* Check if we have opened a local TSAP : - * If we have already opened a TSAP, it means that either we are already - * connected or in the process of doing so... */ - if(self->ttp_connect) + /* Check if we are already trying to connect. + * Because irda_irnet_connect() can be called directly by pppd plus + * packet retries in ppp_generic and connect may take time, plus we may + * race with irnet_connect_indication(), we need to be careful there... */ + if(test_and_set_bit(0, &self->ttp_connect)) DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n"); - self->ttp_connect = 1; if((self->iriap != NULL) || (self->tsap != NULL)) DERROR(IRDA_SOCK_ERROR, "Socket not cleaned up...\n"); @@ -579,6 +579,7 @@ * * Destroy irnet instance * + * Note : this need to be called from a process context. */ void irda_irnet_destroy(irnet_socket * self) @@ -601,6 +602,23 @@ DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n"); } + /* If we were connected, post a message */ + if(test_bit(0, &self->ttp_open)) + { + /* Note : as the disconnect comes from ppp_generic, the unit number + * doesn't exist anymore when we post the event, so we need to pass + * NULL as the first arg... */ + irnet_post_event(NULL, IRNET_DISCONNECT_TO, + self->saddr, self->daddr, self->rname); + } + + /* Prevent various IrDA callbacks from messing up things + * Need to be first */ + clear_bit(0, &self->ttp_connect); + + /* Prevent higher layer from accessing IrTTP */ + clear_bit(0, &self->ttp_open); + /* Unregister with IrLMP */ irlmp_unregister_client(self->ckey); @@ -611,19 +629,14 @@ self->iriap = NULL; } - /* If we were connected, post a message */ - if(self->ttp_open) + /* Cleanup eventual discoveries from connection attempt */ + if(self->discoveries != NULL) { - /* Note : as the disconnect comes from ppp_generic, the unit number - * doesn't exist anymore when we post the event, so we need to pass - * NULL as the first arg... */ - irnet_post_event(NULL, IRNET_DISCONNECT_TO, - self->saddr, self->daddr, self->rname); + /* Cleanup our copy of the discovery log */ + kfree(self->discoveries); + self->discoveries = NULL; } - /* Prevent higher layer from accessing IrTTP */ - self->ttp_open = 0; - /* Close our IrTTP connection */ if(self->tsap) { @@ -761,7 +774,7 @@ while(new !=(irnet_socket *) NULL) { /* Is it available ? */ - if(!(new->ttp_open) && (new->rdaddr == DEV_ADDR_ANY) && + if(!(test_bit(0, &new->ttp_open)) && (new->rdaddr == DEV_ADDR_ANY) && (new->rname[0] == '\0') && (new->ppp_open)) { /* Yes !!! Get it.. */ @@ -788,17 +801,17 @@ * */ static inline int -irnet_connect_socket(irnet_socket * self, +irnet_connect_socket(irnet_socket * server, irnet_socket * new, struct qos_info * qos, __u32 max_sdu_size, __u8 max_header_size) { - DENTER(IRDA_SERV_TRACE, "(self=0x%X, new=0x%X)\n", - (unsigned int) self, (unsigned int) new); + DENTER(IRDA_SERV_TRACE, "(server=0x%X, new=0x%X)\n", + (unsigned int) server, (unsigned int) new); /* Now attach up the new socket */ - new->tsap = irttp_dup(self->tsap, new); + new->tsap = irttp_dup(server->tsap, new); DABORT(new->tsap == NULL, -1, IRDA_SERV_ERROR, "dup failed!\n"); /* Set up all the relevant parameters on the new socket */ @@ -817,17 +830,32 @@ #endif /* STREAM_COMPAT */ /* Clean up the original one to keep it in listen state */ - self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY; - self->tsap->lsap->lsap_state = LSAP_DISCONNECTED; + server->tsap->dtsap_sel = server->tsap->lsap->dlsap_sel = LSAP_ANY; + server->tsap->lsap->lsap_state = LSAP_DISCONNECTED; /* Send a connection response on the new socket */ irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL); /* Allow PPP to send its junk over the new socket... */ - new->ttp_open = 1; - new->ttp_connect = 0; + set_bit(0, &new->ttp_open); + + /* Not connecting anymore, and clean up last possible remains + * of connection attempts on the socket */ + clear_bit(0, &new->ttp_connect); + if(new->iriap) + { + iriap_close(new->iriap); + new->iriap = NULL; + } + if(new->discoveries != NULL) + { + kfree(new->discoveries); + new->discoveries = NULL; + } + #ifdef CONNECT_INDIC_KICK - /* As currently we don't packets in ppp_irnet_send(), this is not needed... + /* As currently we don't block packets in ppp_irnet_send() while passive, + * this is not really needed... * Also, not doing it give IrDA a chance to finish the setup properly * before beeing swamped with packets... */ ppp_output_wakeup(&new->chan); @@ -835,7 +863,7 @@ /* Notify the control channel */ irnet_post_event(new, IRNET_CONNECT_FROM, - new->saddr, new->daddr, self->rname); + new->saddr, new->daddr, server->rname); DEXIT(IRDA_SERV_TRACE, "\n"); return 0; @@ -1053,12 +1081,33 @@ struct sk_buff *skb) { irnet_socket * self = (irnet_socket *) instance; + int test = 0; DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); + /* Don't care about it, but let's not leak it */ + if(skb) + dev_kfree_skb(skb); + + /* Prevent higher layer from accessing IrTTP */ + test = test_and_clear_bit(0, &self->ttp_open); + /* Not connecting anymore... + * (note : TSAP is open, so IAP callbacks are no longer pending...) */ + test |= test_and_clear_bit(0, &self->ttp_connect); + + /* If both self->ttp_open and self->ttp_connect are NULL, it mean that we + * have a race condition with irda_irnet_destroy() or + * irnet_connect_indication(), so don't mess up tsap... + */ + if(!test) + { + DERROR(IRDA_CB_ERROR, "Race condition detected...\n"); + return; + } + /* If we were active, notify the control channel */ - if(self->ttp_open) + if(test_bit(0, &self->ttp_open)) irnet_post_event(self, IRNET_DISCONNECT_FROM, self->saddr, self->daddr, self->rname); else @@ -1067,15 +1116,10 @@ irnet_post_event(self, IRNET_NOANSWER_FROM, self->saddr, self->daddr, self->rname); - /* Prevent higher layer from accessing IrTTP */ - self->ttp_open = 0; - self->ttp_connect = 0; - - /* Close our IrTTP connection */ + /* Close our IrTTP connection, cleanup tsap */ if((self->tsap) && (self != &irnet_server.s)) { DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n"); - irttp_disconnect_request(self->tsap, NULL, P_NORMAL); irttp_close_tsap(self->tsap); self->tsap = NULL; @@ -1114,6 +1158,13 @@ DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + /* Check if socket is closing down (via irda_irnet_destroy()) */ + if(! test_bit(0, &self->ttp_connect)) + { + DERROR(IRDA_CB_ERROR, "Socket no longer connecting. Ouch !\n"); + return; + } + /* How much header space do we need to reserve */ self->max_header_size = max_header_size; @@ -1129,8 +1180,8 @@ self->saddr = irttp_get_saddr(self->tsap); /* Allow higher layer to access IrTTP */ - self->ttp_connect = 0; - self->ttp_open = 1; + set_bit(0, &self->ttp_open); + clear_bit(0, &self->ttp_connect); /* Not racy, IrDA traffic is serial */ /* Give a kick in the ass of ppp_generic so that he sends us some data */ ppp_output_wakeup(&self->chan); @@ -1251,56 +1302,76 @@ __u8 max_header_size, struct sk_buff *skb) { - irnet_socket * self = &irnet_server.s; + irnet_socket * server = &irnet_server.s; irnet_socket * new = (irnet_socket *) NULL; - DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_TCB_TRACE, "(server=0x%X)\n", (unsigned int) server); DASSERT(instance == &irnet_server, , IRDA_CB_ERROR, "Invalid instance (0x%X) !!!\n", (unsigned int) instance); DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n"); /* Try to find the most appropriate IrNET socket */ - new = irnet_find_socket(self); + new = irnet_find_socket(server); /* After all this hard work, do we have an socket ? */ if(new == (irnet_socket *) NULL) { DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n"); - irnet_disconnect_server(self, skb); + irnet_disconnect_server(server, skb); return; } /* Is the socket already busy ? */ - if(new->ttp_open) + if(test_bit(0, &new->ttp_open)) { DEXIT(IRDA_CB_INFO, ": Socket already connected.\n"); - irnet_disconnect_server(self, skb); + irnet_disconnect_server(server, skb); return; } - /* Socket connecting */ - if(new->tsap != NULL) - { - /* The socket has sent a IrTTP connection request and is waiting for - * a connection response (that may never come). - * Now, the pain is that the socket has open a tsap and is waiting on it, - * while the other end is trying to connect to it on another tsap. - * Argh ! We will deal with that later... + /* Socket connecting ? + * Clear up flag : prevent irnet_disconnect_indication() to mess up tsap */ + if(test_and_clear_bit(0, &new->ttp_connect)) + { + /* The socket is trying to connect to the other end and may have sent + * a IrTTP connection request and is waiting for a connection response + * (that may never come). + * Now, the pain is that the socket may have opened a tsap and is + * waiting on it, while the other end is trying to connect to it on + * another tsap. */ DERROR(IRDA_CB_ERROR, "Socket already connecting. Ouch !\n"); #ifdef ALLOW_SIMULT_CONNECT - /* Close the connection the new socket was attempting. - * WARNING : This need more testing ! */ - irttp_close_tsap(new->tsap); + /* Cleanup the TSAP if necessary - IrIAP will be cleaned up later */ + if(new->tsap != NULL) + { + /* Close the connection the new socket was attempting. + * This seems to be safe... */ + irttp_close_tsap(new->tsap); + new->tsap = NULL; + } /* Note : no return, fall through... */ #else /* ALLOW_SIMULT_CONNECT */ - irnet_disconnect_server(self, skb); + irnet_disconnect_server(server, skb); return; #endif /* ALLOW_SIMULT_CONNECT */ } + else + /* If socket is not connecting or connected, tsap should be NULL */ + if(new->tsap != NULL) + { + /* If we are here, we are also in irnet_disconnect_indication(), + * and it's a nice race condition... On the other hand, we can't be + * in irda_irnet_destroy() otherwise we would not have found the + * socket in the hashbin. */ + /* Better get out of here, otherwise we will mess up tsaps ! */ + DERROR(IRDA_CB_ERROR, "Race condition detected, abort connect...\n"); + irnet_disconnect_server(server, skb); + return; + } /* So : at this point, we have a socket, and it is idle. Good ! */ - irnet_connect_socket(self, new, qos, max_sdu_size, max_header_size); + irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size); /* Check size of received packet */ if(skb->len > 0) @@ -1349,24 +1420,25 @@ DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); - /* We probably don't need to make any more queries */ - iriap_close(self->iriap); - self->iriap = NULL; - - /* Check if already connected (via irnet_connect_socket()) */ - if(self->ttp_open) + /* Check if already connected (via irnet_connect_socket()) + * or socket is closing down (via irda_irnet_destroy()) */ + if(! test_bit(0, &self->ttp_connect)) { - DERROR(IRDA_OCB_ERROR, "Socket already connected. Ouch !\n"); + DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); return; } + /* We probably don't need to make any more queries */ + iriap_close(self->iriap); + self->iriap = NULL; + /* Post process the IAS reply */ self->dtsap_sel = irnet_ias_to_tsap(self, result, value); /* If error, just go out */ if(self->errno) { - self->ttp_connect = 0; + clear_bit(0, &self->ttp_connect); DERROR(IRDA_OCB_ERROR, "IAS connect failed ! (0x%X)\n", self->errno); return; } @@ -1412,6 +1484,14 @@ DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); + /* Check if already connected (via irnet_connect_socket()) + * or socket is closing down (via irda_irnet_destroy()) */ + if(! test_bit(0, &self->ttp_connect)) + { + DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); + return; + } + /* Post process the IAS reply */ dtsap_sel = irnet_ias_to_tsap(self, result, value); @@ -1468,15 +1548,8 @@ if(self->daddr == DEV_ADDR_ANY) { self->daddr = DEV_ADDR_ANY; - self->ttp_connect = 0; + clear_bit(0, &self->ttp_connect); DEXIT(IRDA_OCB_TRACE, ": cannot discover IrNET in any device !!!\n"); - return; - } - - /* Check if already connected (via irnet_connect_socket()) */ - if(self->ttp_open) - { - DERROR(IRDA_OCB_ERROR, "Socket already connected. Ouch !\n"); return; } diff -u --recursive --new-file v2.4.14/linux/net/irda/irnet/irnet_ppp.c linux/net/irda/irnet/irnet_ppp.c --- v2.4.14/linux/net/irda/irnet/irnet_ppp.c Tue Oct 9 17:06:53 2001 +++ linux/net/irda/irnet/irnet_ppp.c Fri Nov 9 14:22:17 2001 @@ -850,7 +850,7 @@ DASSERT(self != NULL, 0, PPP_ERROR, "Self is NULL !!!\n"); /* Check if we are connected */ - if(self->ttp_open == 0) + if(!(test_bit(0, &self->ttp_open))) { #ifdef CONNECT_IN_SEND /* Let's try to connect one more time... */ @@ -884,7 +884,7 @@ */ #ifdef BLOCK_WHEN_CONNECT /* If we are attempting to connect */ - if(self->ttp_connect) + if(test_bit(0, &self->ttp_connect)) { /* Blocking packet, ppp_generic will retry later */ return 0; diff -u --recursive --new-file v2.4.14/linux/net/irda/irsyms.c linux/net/irda/irsyms.c --- v2.4.14/linux/net/irda/irsyms.c Wed Jul 25 17:10:27 2001 +++ linux/net/irda/irsyms.c Fri Nov 9 14:22:17 2001 @@ -10,6 +10,7 @@ * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1997, 1999-2000 Dag Brattli, All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -79,7 +80,6 @@ EXPORT_SYMBOL(irda_debug); #endif EXPORT_SYMBOL(irda_notify_init); -EXPORT_SYMBOL(irda_lock); #ifdef CONFIG_PROC_FS EXPORT_SYMBOL(proc_irda); #endif @@ -217,21 +217,6 @@ /* Remove middle layer */ irlmp_cleanup(); -} - -/* - * Function irda_unlock (lock) - * - * Unlock variable. Returns false if lock is already unlocked - * - */ -inline int irda_unlock(int *lock) -{ - if (!test_and_clear_bit(0, (void *) lock)) { - printk("Trying to unlock already unlocked variable!\n"); - return FALSE; - } - return TRUE; } /* diff -u --recursive --new-file v2.4.14/linux/net/irda/irttp.c linux/net/irda/irttp.c --- v2.4.14/linux/net/irda/irttp.c Wed Jul 25 17:10:27 2001 +++ linux/net/irda/irttp.c Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -223,6 +224,11 @@ del_timer(&self->todo_timer); + /* This one won't be cleaned up if we are diconnect_pend + close_pend + * and we receive a disconnect_indication */ + if (self->disconnect_skb) + dev_kfree_skb(self->disconnect_skb); + self->connected = FALSE; self->magic = ~TTP_TSAP_MAGIC; @@ -235,6 +241,9 @@ * Remove TSAP from list of all TSAPs and then deallocate all resources * associated with this TSAP * + * Note : because we *free* the tsap structure, it is the responsability + * of the caller to make sure we are called only once and to deal with + * possible race conditions. - Jean II */ int irttp_close_tsap(struct tsap_cb *self) { @@ -248,8 +257,8 @@ /* Make sure tsap has been disconnected */ if (self->connected) { /* Check if disconnect is not pending */ - if (!self->disconnect_pend) { - IRDA_DEBUG(0, __FUNCTION__ "(), TSAP still connected!\n"); + if (!test_bit(0, &self->disconnect_pend)) { + WARNING(__FUNCTION__ "(), TSAP still connected!\n"); irttp_disconnect_request(self, NULL, P_NORMAL); } self->close_pend = TRUE; @@ -407,6 +416,7 @@ unsigned long flags; int n; + /* Get exclusive access to the tx queue, otherwise don't touch it */ if (irda_lock(&self->tx_queue_lock) == FALSE) return; @@ -473,27 +483,17 @@ * close the socket, we are dead ! * Jean II */ if (skb->sk != NULL) { - struct sk_buff *tx_skb; - /* IrSOCK application, IrOBEX, ... */ IRDA_DEBUG(4, __FUNCTION__ "() : Detaching SKB from socket.\n"); - /* Note : still looking for a more efficient way - * to do that - Jean II */ - /* Get another skb on the same buffer, but without - * a reference to the socket (skb->sk = NULL) */ - tx_skb = skb_clone(skb, GFP_ATOMIC); - if (tx_skb != NULL) { - /* Release the skb associated with the - * socket, and use the new skb insted */ - kfree_skb(skb); - skb = tx_skb; - } + /* That's the right way to do it - Jean II */ + skb_orphan(skb); } else { /* IrCOMM over IrTTP, IrLAN, ... */ IRDA_DEBUG(4, __FUNCTION__ "() : Got SKB not attached to a socket.\n"); } + /* Pass the skb to IrLMP - done */ irlmp_data_request(self->lsap, skb); self->stats.tx_packets++; @@ -1105,18 +1105,23 @@ /* Already disconnected? */ if (!self->connected) { IRDA_DEBUG(4, __FUNCTION__ "(), already disconnected!\n"); + if (userdata) + dev_kfree_skb(userdata); return -1; } - /* Disconnect already pending? */ - if (self->disconnect_pend) { - IRDA_DEBUG(1, __FUNCTION__ "(), disconnect already pending\n"); - if (userdata) { + /* Disconnect already pending ? + * We need to use an atomic operation to prevent reentry. This + * function may be called from various context, like user, timer + * for following a disconnect_indication() (i.e. net_bh). + * Jean II */ + if(test_and_set_bit(0, &self->disconnect_pend)) { + IRDA_DEBUG(0, __FUNCTION__ "(), disconnect already pending\n"); + if (userdata) dev_kfree_skb(userdata); - } /* Try to make some progress */ - irttp_run_rx_queue(self); + irttp_run_tx_queue(self); return -1; } @@ -1125,25 +1130,20 @@ */ if (skb_queue_len(&self->tx_queue) > 0) { if (priority == P_HIGH) { - IRDA_DEBUG(1, __FUNCTION__ "High priority!!()\n" ); - /* * No need to send the queued data, if we are * disconnecting right now since the data will * not have any usable connection to be sent on */ + IRDA_DEBUG(1, __FUNCTION__ "High priority!!()\n" ); irttp_flush_queues(self); } else if (priority == P_NORMAL) { /* - * Must delay disconnect til after all data segments - * have been sent an the tx_queue is empty + * Must delay disconnect until after all data segments + * have been sent and the tx_queue is empty */ - if (userdata) - self->disconnect_skb = userdata; - else - self->disconnect_skb = NULL; - - self->disconnect_pend = TRUE; + /* We'll reuse this one later for the disconnect */ + self->disconnect_skb = userdata; /* May be NULL */ irttp_run_tx_queue(self); @@ -1152,9 +1152,8 @@ } } IRDA_DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n"); - self->connected = FALSE; - + if (!userdata) { skb = dev_alloc_skb(64); if (!skb) @@ -1169,6 +1168,9 @@ } ret = irlmp_disconnect_request(self->lsap, userdata); + /* The disconnect is no longer pending */ + clear_bit(0, &self->disconnect_pend); /* FALSE */ + return ret; } @@ -1190,19 +1192,27 @@ ASSERT(self != NULL, return;); ASSERT(self->magic == TTP_TSAP_MAGIC, return;); + /* Prevent higher layer to send more data */ self->connected = FALSE; /* Check if client has already tried to close the TSAP */ if (self->close_pend) { + /* In this case, the higher layer is probably gone. Don't + * bother it and clean up the remains - Jean II */ + if (skb) + dev_kfree_skb(skb); irttp_close_tsap(self); return; } + /* If we are here, we assume that is the higher layer is still + * waiting for the disconnect notification and able to process it, + * even if he tried to disconnect. Otherwise, it would have already + * attempted to close the tsap and self->close_pend would be TRUE. + * Jean II */ + /* No need to notify the client if has already tried to disconnect */ - if (self->disconnect_pend) - return; - - if (self->notify.disconnect_indication) + if(self->notify.disconnect_indication) self->notify.disconnect_indication(self->notify.instance, self, reason, skb); else @@ -1222,7 +1232,7 @@ int err; /* Check if client has already tried to close the TSAP */ - if (self->close_pend || self->disconnect_pend) { + if (self->close_pend) { dev_kfree_skb(skb); return; } @@ -1263,6 +1273,7 @@ IRDA_DEBUG(2, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", self->send_credit, self->avail_credit, self->remote_credit); + /* Get exclusive access to the rx queue, otherwise don't touch it */ if (irda_lock(&self->rx_queue_lock) == FALSE) return; @@ -1500,7 +1511,7 @@ else self->tx_max_sdu_size = param->pv.i; - IRDA_DEBUG(0, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i); + IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i); return 0; } @@ -1530,18 +1541,16 @@ } /* Check if time for disconnect */ - if (self->disconnect_pend) { + if (test_bit(0, &self->disconnect_pend)) { /* Check if it's possible to disconnect yet */ if (skb_queue_empty(&self->tx_queue)) { - /* Make sure disconnect is not pending anymore */ - self->disconnect_pend = FALSE; - if (self->disconnect_skb) { - irttp_disconnect_request( - self, self->disconnect_skb, P_NORMAL); - self->disconnect_skb = NULL; - } else - irttp_disconnect_request(self, NULL, P_NORMAL); + clear_bit(0, &self->disconnect_pend); /* FALSE */ + + /* Note : self->disconnect_skb may be NULL */ + irttp_disconnect_request(self, self->disconnect_skb, + P_NORMAL); + self->disconnect_skb = NULL; } else { /* Try again later */ irttp_start_todo_timer(self, 1*HZ); diff -u --recursive --new-file v2.4.14/linux/net/irda/parameters.c linux/net/irda/parameters.c --- v2.4.14/linux/net/irda/parameters.c Sat Nov 11 18:11:22 2000 +++ linux/net/irda/parameters.c Fri Nov 9 14:22:17 2001 @@ -167,14 +167,14 @@ IRDA_DEBUG(2, __FUNCTION__ "(), pi=%#x, pl=%d, pi=%d\n", p.pi, p.pl, p.pv.i); switch (p.pl) { case 1: - n += irda_param_pack(buf, "bbb", p.pi, p.pl, p.pv.b); + n += irda_param_pack(buf, "bbb", p.pi, p.pl, (__u8) p.pv.i); break; case 2: if (type & PV_BIG_ENDIAN) - cpu_to_be16s(&p.pv.s); + p.pv.i = cpu_to_be16((__u16) p.pv.i); else - cpu_to_le16s(&p.pv.s); - n += irda_param_pack(buf, "bbs", p.pi, p.pl, p.pv.s); + p.pv.i = cpu_to_le16((__u16) p.pv.i); + n += irda_param_pack(buf, "bbs", p.pi, p.pl, (__u16) p.pv.i); break; case 4: if (type & PV_BIG_ENDIAN) @@ -230,16 +230,17 @@ return p.pl+2; } + switch (p.pl) { case 1: - n += irda_param_unpack(buf+2, "b", &p.pv.b); + n += irda_param_unpack(buf+2, "b", &p.pv.i); break; case 2: - n += irda_param_unpack(buf+2, "s", &p.pv.s); + n += irda_param_unpack(buf+2, "s", &p.pv.i); if (type & PV_BIG_ENDIAN) - be16_to_cpus(&p.pv.s); + p.pv.i = be16_to_cpu((__u16) p.pv.i); else - le16_to_cpus(&p.pv.s); + p.pv.i = le16_to_cpu((__u16) p.pv.i); break; case 4: n += irda_param_unpack(buf+2, "i", &p.pv.i); @@ -255,6 +256,7 @@ return p.pl+2; } + IRDA_DEBUG(2, __FUNCTION__ "(), pi=%#x, pl=%d, pi=%d\n", p.pi, p.pl, p.pv.i); /* Call handler for this parameter */ err = (*func)(self, &p, PV_PUT); if (err < 0) @@ -359,8 +361,8 @@ buf[n++] = (__u8)va_arg(args, int); break; case 's': /* 16 bits unsigned short */ - arg.s = (__u16)va_arg(args, int); - put_unaligned(arg.s, (__u16 *)(buf+n)); n+=2; + arg.i = (__u16)va_arg(args, int); + put_unaligned((__u16)arg.i, (__u16 *)(buf+n)); n+=2; break; case 'i': /* 32 bits unsigned integer */ arg.i = va_arg(args, __u32); @@ -402,12 +404,12 @@ for (p = fmt; *p != '\0'; p++) { switch (*p) { case 'b': /* 8 bits byte */ - arg.bp = va_arg(args, __u8 *); - *arg.bp = buf[n++]; + arg.ip = va_arg(args, __u32 *); + *arg.ip = buf[n++]; break; case 's': /* 16 bits short */ - arg.sp = va_arg(args, __u16 *); - *arg.sp = get_unaligned((__u16 *)(buf+n)); n+=2; + arg.ip = va_arg(args, __u32 *); + *arg.ip = get_unaligned((__u16 *)(buf+n)); n+=2; break; case 'i': /* 32 bits unsigned integer */ arg.ip = va_arg(args, __u32 *); diff -u --recursive --new-file v2.4.14/linux/net/irda/qos.c linux/net/irda/qos.c --- v2.4.14/linux/net/irda/qos.c Wed Jul 25 17:10:27 2001 +++ linux/net/irda/qos.c Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -455,8 +456,8 @@ * Stations must agree on baud rate, so calculate * intersection */ - IRDA_DEBUG(2, "Requested BAUD_RATE: 0x%04x\n", param->pv.s); - final = param->pv.s & self->qos_rx.baud_rate.bits; + IRDA_DEBUG(2, "Requested BAUD_RATE: 0x%04x\n", (__u16) param->pv.i); + final = (__u16) param->pv.i & self->qos_rx.baud_rate.bits; IRDA_DEBUG(2, "Final BAUD_RATE: 0x%04x\n", final); self->qos_tx.baud_rate.bits = final; @@ -483,14 +484,14 @@ ASSERT(self->magic == LAP_MAGIC, return -1;); if (get) - param->pv.b = self->qos_rx.link_disc_time.bits; + param->pv.i = self->qos_rx.link_disc_time.bits; else { /* * Stations must agree on link disconnect/threshold * time. */ - IRDA_DEBUG(2, "LINK_DISC: %02x\n", param->pv.b); - final = param->pv.b & self->qos_rx.link_disc_time.bits; + IRDA_DEBUG(2, "LINK_DISC: %02x\n", (__u8) param->pv.i); + final = (__u8) param->pv.i & self->qos_rx.link_disc_time.bits; IRDA_DEBUG(2, "Final LINK_DISC: %02x\n", final); self->qos_tx.link_disc_time.bits = final; @@ -515,9 +516,9 @@ ASSERT(self->magic == LAP_MAGIC, return -1;); if (get) - param->pv.b = self->qos_rx.max_turn_time.bits; + param->pv.i = self->qos_rx.max_turn_time.bits; else - self->qos_tx.max_turn_time.bits = param->pv.b; + self->qos_tx.max_turn_time.bits = (__u8) param->pv.i; return 0; } @@ -537,9 +538,9 @@ ASSERT(self->magic == LAP_MAGIC, return -1;); if (get) - param->pv.b = self->qos_rx.data_size.bits; + param->pv.i = self->qos_rx.data_size.bits; else - self->qos_tx.data_size.bits = param->pv.b; + self->qos_tx.data_size.bits = (__u8) param->pv.i; return 0; } @@ -560,9 +561,9 @@ ASSERT(self->magic == LAP_MAGIC, return -1;); if (get) - param->pv.b = self->qos_rx.window_size.bits; + param->pv.i = self->qos_rx.window_size.bits; else - self->qos_tx.window_size.bits = param->pv.b; + self->qos_tx.window_size.bits = (__u8) param->pv.i; return 0; } @@ -581,9 +582,9 @@ ASSERT(self->magic == LAP_MAGIC, return -1;); if (get) - param->pv.b = self->qos_rx.additional_bofs.bits; + param->pv.i = self->qos_rx.additional_bofs.bits; else - self->qos_tx.additional_bofs.bits = param->pv.b; + self->qos_tx.additional_bofs.bits = (__u8) param->pv.i; return 0; } @@ -603,9 +604,9 @@ ASSERT(self->magic == LAP_MAGIC, return -1;); if (get) - param->pv.b = self->qos_rx.min_turn_time.bits; + param->pv.i = self->qos_rx.min_turn_time.bits; else - self->qos_tx.min_turn_time.bits = param->pv.b; + self->qos_tx.min_turn_time.bits = (__u8) param->pv.i; return 0; } diff -u --recursive --new-file v2.4.14/linux/net/irda/timer.c linux/net/irda/timer.c --- v2.4.14/linux/net/irda/timer.c Sun Nov 12 20:40:43 2000 +++ linux/net/irda/timer.c Fri Nov 9 14:22:17 2001 @@ -11,6 +11,7 @@ * * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -94,29 +95,24 @@ irlap_backoff_timer_expired); } -void irlap_start_mbusy_timer(struct irlap_cb *self) +void irlap_start_mbusy_timer(struct irlap_cb *self, int timeout) { - irda_start_timer(&self->media_busy_timer, MEDIABUSY_TIMEOUT, + irda_start_timer(&self->media_busy_timer, timeout, (void *) self, irlap_media_busy_expired); } void irlap_stop_mbusy_timer(struct irlap_cb *self) { /* If timer is activated, kill it! */ - if(timer_pending(&self->media_busy_timer)) - del_timer(&self->media_busy_timer); + del_timer(&self->media_busy_timer); -#ifdef CONFIG_IRDA_ULTRA - /* Send any pending Ultra frames if any */ - if (!skb_queue_empty(&self->txq_ultra)) - /* Note : we don't send the frame, just post an event. - * Frames will be sent only if we are in NDM mode (see - * irlap_event.c). - * Also, moved this code from irlap_media_busy_expired() - * to here to catch properly all cases... - * Jean II */ - irlap_do_event(self, SEND_UI_FRAME, NULL, NULL); -#endif /* CONFIG_IRDA_ULTRA */ + /* If we are in NDM, there is a bunch of events in LAP that + * that be pending due to the media_busy condition, such as + * CONNECT_REQUEST and SEND_UI_FRAME. If we don't generate + * an event, they will wait forever... + * Jean II */ + if (self->state == LAP_NDM) + irlap_do_event(self, MEDIA_BUSY_TIMER_EXPIRED, NULL, NULL); } void irlmp_start_watchdog_timer(struct lsap_cb *self, int timeout) @@ -237,5 +233,7 @@ ASSERT(self != NULL, return;); irda_device_set_media_busy(self->netdev, FALSE); - /* Note : will deal with Ultra frames */ + /* Note : the LAP event will be send in irlap_stop_mbusy_timer(), + * to catch other cases where the flag is cleared (for example + * after a discovery) - Jean II */ } diff -u --recursive --new-file v2.4.14/linux/net/netlink/netlink_dev.c linux/net/netlink/netlink_dev.c --- v2.4.14/linux/net/netlink/netlink_dev.c Fri Feb 9 11:29:44 2001 +++ linux/net/netlink/netlink_dev.c Fri Nov 9 14:12:55 2001 @@ -28,10 +28,11 @@ #include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> +#include <asm/bitops.h> #include <asm/system.h> #include <asm/uaccess.h> -static unsigned open_map; +static long open_map; static struct socket *netlink_user[MAX_LINKS]; /* @@ -111,11 +112,9 @@ if (minor>=MAX_LINKS) return -ENODEV; - if (open_map&(1<<minor)) + if (test_and_set_bit(minor, &open_map)) return -EBUSY; - open_map |= (1<<minor); - err = sock_create(PF_NETLINK, SOCK_RAW, minor, &sock); if (err < 0) goto out; @@ -132,7 +131,7 @@ return 0; out: - open_map &= ~(1<<minor); + clear_bit(minor, &open_map); return err; } @@ -141,11 +140,9 @@ unsigned int minor = MINOR(inode->i_rdev); struct socket *sock; - lock_kernel(); sock = netlink_user[minor]; netlink_user[minor] = NULL; - open_map &= ~(1<<minor); - unlock_kernel(); + clear_bit(minor, &open_map); sock_release(sock); return 0; } diff -u --recursive --new-file v2.4.14/linux/net/sched/sch_api.c linux/net/sched/sch_api.c --- v2.4.14/linux/net/sched/sch_api.c Mon Jan 1 09:57:08 2001 +++ linux/net/sched/sch_api.c Fri Nov 9 14:12:54 2001 @@ -1145,8 +1145,10 @@ stop = jiffies + HZ/10; PSCHED_GET_TIME(stamp); do_gettimeofday(&tv); - while (time_before(jiffies, stop)) + while (time_before(jiffies, stop)) { barrier(); + cpu_relax(); + } PSCHED_GET_TIME(stamp1); do_gettimeofday(&tv1); diff -u --recursive --new-file v2.4.14/linux/scripts/Lindent linux/scripts/Lindent --- v2.4.14/linux/scripts/Lindent Thu Feb 8 16:32:44 2001 +++ linux/scripts/Lindent Fri Nov 9 14:12:54 2001 @@ -1,2 +1,2 @@ #!/bin/bash -indent -kr -i8 -ts8 -br -ce -bap -sob -l80 -pcs -cs -ss -bs -di1 -nbc -lp -psl $@ +indent -kr -i8 -ts8 -sob -l80 -ss -bs -psl $@ diff -u --recursive --new-file v2.4.14/linux/scripts/patch-kernel linux/scripts/patch-kernel --- v2.4.14/linux/scripts/patch-kernel Sun Dec 12 22:55:54 1999 +++ linux/scripts/patch-kernel Fri Nov 9 14:12:54 2001 @@ -1,8 +1,22 @@ #! /bin/sh # Script to apply kernel patches. -# usage: patch-kernel [ sourcedir [ patchdir [ stopversion ] ] ] +# usage: patch-kernel [ sourcedir [ patchdir [ stopversion ] [ -acxx ] ] ] # The source directory defaults to /usr/src/linux, and the patch # directory defaults to the current directory. +# e.g. +# scripts/patch-kernel . .. +# Update the kernel tree in the current directory using patches in the +# directory above to the latest Linus kernel +# scripts/patch-kernel . .. -ac +# Get the latest Linux kernel and patch it with the latest ac patch +# scripts/patch-kernel . .. 2.4.9 +# Gets standard kernel 2.4.9 +# scripts/patch-kernel . .. 2.4.9 -ac +# Gets 2.4.9 with latest ac patches +# scripts/patch-kernel . .. 2.4.9 -ac11 +# Gets 2.4.9 with ac patch ac11 +# Note: It uses the patches relative to the Linus kernels, not the +# ac to ac relative patches # # It determines the current kernel version from the top-level Makefile. # It then looks for patches for the next sublevel in the patch directory. @@ -21,74 +35,159 @@ # Put the full version number (i.e. 2.3.31) as the last parameter # Dave Gilbert <linux@treblig.org>, 11th December 1999. +# Fixed previous patch so that if we are already at the correct version +# not to patch up. +# +# Added -ac option, use -ac or -ac9 (say) to stop at a particular version +# Dave Gilbert <linux@treblig.org>, 29th September 2001. + # Set directories from arguments, or use defaults. sourcedir=${1-/usr/src/linux} patchdir=${2-.} stopvers=${3-imnotaversion} -# set current VERSION, PATCHLEVEL, SUBLEVEL -eval `sed -n 's/^\([A-Z]*\) = \([0-9]*\)$/\1=\2/p' $sourcedir/Makefile` +# See if we have any -ac options +for PARM in $* +do + case $PARM in + -ac*) + gotac=$PARM; + + esac; +done + +# --------------------------------------------------------------------------- +# Find a file, first parameter is basename of file +# it tries many compression mechanisms and sets variables to say how to get it +function findFile { + filebase=$1; + + if [ -r ${filebase}.gz ]; then + ext=".gz" + name="gzip" + uncomp="gunzip -dc" + elif [ -r ${filebase}.bz ]; then + ext=".bz" + name="bzip" + uncomp="bunzip -dc" + elif [ -r ${filebase}.bz2 ]; then + ext=".bz2" + name="bzip2" + uncomp="bunzip2 -dc" + elif [ -r ${filebase}.zip ]; then + ext=".zip" + name="zip" + uncomp="unzip -d" + elif [ -r ${filebase}.Z ]; then + ext=".Z" + name="uncompress" + uncomp="uncompress -c" + elif [ -r ${filebase} ]; then + ext="" + name="plaintext" + uncomp="cat" + else + return 1; + fi + + return 0; +} + +# --------------------------------------------------------------------------- +# Apply a patch and check it goes in cleanly +# First param is patch name (e.g. patch-2.4.9-ac5) - without path or extension + +function applyPatch { + echo -n "Applying $1 (${name})... " + if $uncomp ${patchdir}/$1${ext} | patch -p1 -s -N -E -d $sourcedir + then + echo "done." + else + echo "failed. Clean up yourself." + return 1; + fi + if [ "`find $sourcedir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ] + then + echo "Aborting. Reject files found." + return 1; + fi + # Remove backup files + find $sourcedir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \; + + return 0; +} + +# set current VERSION, PATCHLEVEL, SUBLEVEL, EXTERVERSION +eval `sed -n -e 's/^\([A-Z]*\) = \([0-9]*\)$/\1=\2/p' -e 's/^\([A-Z]*\) = \(-[-a-z0-9]*\)$/\1=\2/p' $sourcedir/Makefile` if [ -z "$VERSION" -o -z "$PATCHLEVEL" -o -z "$SUBLEVEL" ] then echo "unable to determine current kernel version" >&2 exit 1 fi -echo "Current kernel version is $VERSION.$PATCHLEVEL.$SUBLEVEL" +echo "Current kernel version is $VERSION.$PATCHLEVEL.$SUBLEVEL${EXTRAVERSION}" + +if [ x$EXTRAVERSION != "x" ] +then + echo "I'm sorry but patch-kernel can't work with a kernel source tree that is not a base version" + exit 1; +fi while : do + CURRENTFULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL" + if [ $stopvers = $CURRENTFULLVERSION ] + then + echo "Stoping at $CURRENTFULLVERSION base as requested." + break + fi + SUBLEVEL=`expr $SUBLEVEL + 1` FULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL" patch=patch-$FULLVERSION - if [ -r $patchdir/${patch}.gz ]; then - ext=".gz" - name="gzip" - uncomp="gunzip -dc" - elif [ -r $patchdir/${patch}.bz ]; then - ext=".bz" - name="bzip" - uncomp="bunzip -dc" - elif [ -r $patchdir/${patch}.bz2 ]; then - ext=".bz2" - name="bzip2" - uncomp="bunzip2 -dc" - elif [ -r $patchdir/${patch}.zip ]; then - ext=".zip" - name="zip" - uncomp="unzip -d" - elif [ -r $patchdir/${patch}.Z ]; then - ext=".Z" - name="uncompress" - uncomp="uncompress -c" - elif [ -r $patchdir/${patch} ]; then - ext="" - name="plaintext" - uncomp="cat" - else - break - fi - echo -n "Applying ${patch} (${name})... " - if $uncomp ${patchdir}/${patch}${ext} | patch -p1 -s -N -E -d $sourcedir - then - echo "done." - else - echo "failed. Clean up yourself." - break - fi - if [ "`find $sourcedir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ] - then - echo "Aborting. Reject files found." - break - fi - # Remove backup files - find $sourcedir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \; + # See if the file exists and find extension + findFile $patchdir/${patch} || break - if [ $stopvers = $FULLVERSION ] - then - echo "Stoping at $FULLVERSION as requested. Enjoy." - break - fi + # Apply the patch and check all is OK + applyPatch $patch || break done + +if [ x$gotac != x ]; then + # Out great user wants the -ac patches + # They could have done -ac (get latest) or -acxx where xx=version they want + if [ $gotac == "-ac" ] + then + # They want the latest version + HIGHESTPATCH=0 + for PATCHNAMES in $patchdir/patch-${CURRENTFULLVERSION}-ac*\.* + do + ACVALUE=`echo $PATCHNAMES | sed -e 's/^.*patch-[0-9.]*-ac\([0-9]*\).*/\1/'` + # Check it is actually a recognised patch type + findFile $patchdir/patch-${CURRENTFULLVERSION}-ac${ACVALUE} || break + + if [ $ACVALUE -gt $HIGHESTPATCH ] + then + HIGHESTPATCH=$ACVALUE + fi + done + + if [ $HIGHESTPATCH -ne 0 ] + then + findFile $patchdir/patch-${CURRENTFULLVERSION}-ac${HIGHESTPATCH} || break + applyPatch patch-${CURRENTFULLVERSION}-ac${HIGHESTPATCH} + else + echo "No ac patches found" + fi + else + # They want an exact version + findFile $patchdir/patch-${CURRENTFULLVERSION}${gotac} || { + echo "Sorry, I couldn't find the $gotac patch for $CURRENTFULLVERSION. Hohum." + exit 1 + } + applyPatch patch-${CURRENTFULLVERSION}${gotac} + fi +fi + +