]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.10pre1 2.3.10pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:25:57 +0000 (15:25 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:25:57 +0000 (15:25 -0500)
119 files changed:
Documentation/Changes
Documentation/Configure.help
Documentation/SMP.txt
Documentation/fb/tgafb.txt [new file with mode: 0644]
Documentation/java.txt
Documentation/oops-tracing.txt
Documentation/parport.txt
Makefile
README
arch/alpha/config.in
arch/alpha/kernel/smp.c
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/irq.h
arch/i386/kernel/process.c
arch/i386/kernel/ptrace.c
arch/i386/kernel/smp.c
arch/i386/mm/fault.c
arch/mips/sgi/kernel/indy_sc.c
arch/ppc/config.in
arch/ppc/kernel/process.c
arch/ppc/kernel/smp.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc64/config.in
arch/sparc64/kernel/binfmt_aout32.c
arch/sparc64/kernel/smp.c
drivers/block/Config.in
drivers/block/Makefile
drivers/block/alim15x3.c
drivers/block/cmd646.c
drivers/block/hpt343.c [deleted file]
drivers/block/hpt34x.c [new file with mode: 0644]
drivers/block/icside.c
drivers/block/ide-dma.c
drivers/block/ide-pci.c
drivers/block/ide.c
drivers/block/pdc202xx.c
drivers/block/piix.c
drivers/char/Config.in
drivers/char/c-qcam.c
drivers/char/cyclades.c
drivers/char/esp.c
drivers/char/i2c-parport.c
drivers/char/joystick/joy-db9.c
drivers/char/lp.c
drivers/char/rocket.c
drivers/char/serial.c
drivers/macintosh/macserial.c
drivers/misc/Config.in [new file with mode: 0644]
drivers/misc/Makefile
drivers/misc/parport_arc.c
drivers/misc/parport_atari.c
drivers/misc/parport_ax.c
drivers/misc/parport_daisy.c [new file with mode: 0644]
drivers/misc/parport_ieee1284.c
drivers/misc/parport_ieee1284_ops.c [new file with mode: 0644]
drivers/misc/parport_init.c
drivers/misc/parport_pc.c
drivers/misc/parport_probe.c [new file with mode: 0644]
drivers/misc/parport_procfs.c
drivers/misc/parport_share.c
drivers/pnp/Config.in
drivers/pnp/Makefile
drivers/pnp/parport_probe.c [deleted file]
drivers/sbus/char/sab82532.c
drivers/sbus/char/su.c
drivers/scsi/ppa.c
drivers/sgi/char/graphics.c
drivers/sgi/char/shmiq.c
drivers/usb/CREDITS
drivers/video/Makefile
drivers/video/fbmem.c
drivers/video/tgafb.c
drivers/video/tgafb.h [new file with mode: 0644]
fs/binfmt_aout.c
fs/buffer.c
fs/ext2/ioctl.c
fs/fat/mmap.c
fs/locks.c
fs/ncpfs/mmap.c
fs/proc/array.c
fs/proc/mem.c
fs/ufs/super.c
include/asm-sparc/page.h
include/linux/fs.h
include/linux/ide.h
include/linux/isdn.h
include/linux/lp.h
include/linux/mm.h
include/linux/parport.h
include/linux/parport_pc.h
include/linux/sched.h
include/linux/swap.h
ipc/shm.c
kernel/exit.c
kernel/fork.c
kernel/sched.c
kernel/sys.c
mm/filemap.c
mm/memory.c
mm/mmap.c
mm/page_alloc.c
mm/vmscan.c
net/appletalk/ddp.c
net/socket.c
net/sunrpc/xprt.c
scripts/ksymoops/Makefile [deleted file]
scripts/ksymoops/README
scripts/ksymoops/io.c [deleted file]
scripts/ksymoops/ksymoops.c [deleted file]
scripts/ksymoops/ksymoops.h [deleted file]
scripts/ksymoops/ksyms.c [deleted file]
scripts/ksymoops/map.c [deleted file]
scripts/ksymoops/misc.c [deleted file]
scripts/ksymoops/object.c [deleted file]
scripts/ksymoops/oops.c [deleted file]
scripts/ksymoops/re.c [deleted file]
scripts/ksymoops/symbol.c [deleted file]

index 633479eb991e9e58e0164964c12714fc4af7e210..ce50723e9be2a24e86824684c9a4daf165806007 100644 (file)
@@ -191,12 +191,6 @@ Either use binutils-2.8.1.0.23 or binutils-2.9.1.0.7 or later.  Glibc2
 users should especially try to use the 2.9.1.0.x releases, as they
 resolve known issues with glibc2 and binutils-2.8.x releases.
 
-   libbfd, libiberty, and /usr/include/bfd.h, which are part of recent
-binutils packages, are also required to compile ksymoops.  Depending
-upon your distribution, this may require you to install both binutils
-and binutils-development packages (Debian puts bfd.h in binutils-dev,
-for example).
-
 Gnu C
 =====
 
index da39d21ef4f55973d1fa68c381382117dd57cbef..ace1522fec35e61ef5dd0eb2f5a5d09c6cc5dc09 100644 (file)
@@ -530,7 +530,7 @@ CONFIG_BLK_DEV_IDEPCI
   People with SCSI-only systems should say N here; if unsure say Y.
 
 Generic PCI bus-master DMA support
-CONFIG_BLK_DEV_IDEDMA
+CONFIG_BLK_DEV_IDEDMA_PCI
   If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
   is capable of bus-master DMA operation (most Pentium PCI systems),
   you will want to say Y here to reduce CPU overhead. You can then use
@@ -546,6 +546,26 @@ CONFIG_BLK_DEV_IDEDMA
 
   It is safe to say Y to this question.
 
+Good-Bad DMA Model-Firmware (EXPERIMENTAL)
+IDEDMA_NEW_DRIVE_LISTINGS
+  This test compares both the model and firmware revision for buggy drives
+  that claim to (U)DMA capable.  This is a blanket on/off test with no speed
+  limit options.  Straight GNU GCC 2.7.3/2.8.X compilers are known to be safe;
+  whereas, many versions of EGCS have a problem and miscompile.
+
+  If in doubt, say N.
+
+Generic ATA-66 support (DANGEROUS)
+CONFIG_IDEDMA_ULTRA_66
+  This allows for your Generic IDE control to attempt support for
+  using ATA-66 or UDMA-66 transfer modes 3/4.  If you are not sure what you
+  are attempting, "DO NOT" even think about this option, unless your
+  mainboard's chipset is verified.  Do not complain to anyone if you
+  do not know what you are doing and are just playing around.
+  This option has no known success cases to date.
+
+  Say N, or beware.........
+
 Winbond SL82c105 support
 CONFIG_BLK_DEV_SL82C105
   If you have a Winbond SL82c105 IDE controller, say Y here to enable
@@ -562,13 +582,16 @@ CONFIG_BLK_DEV_OFFBOARD
   improve the usability of some boot managers such as LILO when
   booting from a drive on an off-board controller.
 
+  Requires that all onboard ide controllers be disabled or calling
+  "pci=reverse" to invert the device scan order.
+
   Note that, if you say Y here, the order of the hd* devices will be
   rearranged which may require modification of fstab and other files.
 
   If in doubt, say N.
 
 Use DMA by default when available
-CONFIG_IDEDMA_AUTO
+CONFIG_IDEDMA_PCI_AUTO
   Prior to kernel version 2.1.112, Linux used to automatically use
   DMA for IDE drives and chipsets which support it. Due to concerns
   about a couple of cases where buggy hardware may have caused damage,
@@ -664,7 +687,7 @@ CONFIG_BLK_DEV_CY82C693
   This driver adds detection and support for the CY82C693 chipset
   used on Digital's PC-Alpha 164SX boards.
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
   Please read the comments at the top of drivers/block/cy82c693.c
 
@@ -679,7 +702,7 @@ CONFIG_BLK_DEV_VIA82C586
   (while running a "cat") provided you enabled "proc" support and
   set DISPLAY_APOLLO_TIMINGS in via82c586.c
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
   If unsure, say N.
 
@@ -693,14 +716,15 @@ CONFIG_BLK_DEV_ALI15X3
   onboard chipsets.  It also tests for Simplex mode and enables
   normal dual channel support.
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
   Please read the comments at the top of drivers/block/alim15x3.c
 
   If unsure, say N.
 
-PROMISE PDC20246 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PDC20246
+PROMISE PDC20246/PDC20262 support
+CONFIG_BLK_DEV_PDC202XX
+  Promise Ultra33 or PDC20246.
   This driver adds up to 4 more eide devices sharing a single interrupt.
   This add-on card is a bootable PCI UDMA controller.
   Since multiple cards can be installed and there are BIOS ROM problems
@@ -708,38 +732,49 @@ CONFIG_BLK_DEV_PDC20246
   do not match.  Should you be unable to make new BIOS chips with a burner,
   the driver attempts to dynamic tuning of the chipset at boot-time
   for max-speed.  Ultra33 BIOS 1.25 or new required for more than one card.
+  This card may require "PDC202XX Special UDMA Feature (EXPERIMENTAL)".
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
-
-  Please read the comments at the top of drivers/block/pdc202xx.c
-
-  If unsure, say N.
-
-PROMISE PDC20262 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PDC20262
+  Promise Ultra66 or PDC20262.
   This driver adds up to 4 more eide devices sharing a single interrupt.
   This add-on card is a bootable PCI UDMA ATA-66 controller.
   The driver attempts to dynamic tuning of the chipset at boot-time
   for max-speed.  Note tested limits are UDMA-2.
   Ultra66 BIOS 1.11 or newer required.
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
+
+  Please read the comments at the top of drivers/block/pdc202xx.c
+
+  If unsure, say N.
+
+Special UDMA Feature (EXPERIMENTAL)
+PDC202XX_FORCE_BURST_BIT
+  For PDC20246 and PDC20262 Ultra DMA chipsets.
+  Designed originally for PDC20246/Ultra33 that has BIOS setup failures
+  when using 3 or more cards.
 
   Please read the comments at the top of drivers/block/pdc202xx.c
 
   If unsure, say N.
 
+Special Mode Feature (DANGEROUS)
+PDC202XX_FORCE_MASTER_MODE
+  For PDC20246 and PDC20262 Ultra DMA chipsets.
+  This is reserved for possible Hardware RAID 0,1 for the FastTrak Series.
+
+  Say N. 
+
 AEC6210 chipset support
 CONFIG_BLK_DEV_AEC6210
   This driver adds up to 4 more eide devices sharing a single interrupt.
   This add-on card is a bootable PCI UDMA controller.  In order to get this
   card to initialize correctly in some cases, you should include this driver.
 
-  This prefers CONFIG_IDEDMA_AUTO to be enabled, regardless.
+  This prefers CONFIG_IDEDMA_PCI_AUTO to be enabled, regardless.
 
   Please read the comments at the top of drivers/block/aec6210.c
 
-Intel PIIXn chipsets support (EXPERIMENTAL)
+Intel PIIXn chipsets support
 CONFIG_BLK_DEV_PIIX
   This driver adds PIO mode setting and tuning for all PIIX IDE
   controllers by Intel.  Since the BIOS can sometimes improperly tune
@@ -750,15 +785,31 @@ CONFIG_BLK_DEV_PIIX
 
   If unsure, say N.
 
-HPT343 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_HPT343
+PIIXn Tuning support (EXPERIMENTAL)
+CONFIG_BLK_DEV_PIIX_TUNING
+  This driver extension adds DMA mode setting and tuning for all PIIX IDE
+  controllers by Intel.  Since the BIOS can sometimes improperly setup
+  the device/adapter combination and speed limits, It has become a necessity
+  to back/forward speed devices as needed.
+
+  Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode 2
+  if the BIOS can to perform this task at INIT.
+
+  If unsure, say N.
+
+HPT34X chipset support
+CONFIG_BLK_DEV_HPT34X
   This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. The HPT343 chipset in its current form is a non-bootable
-  PCI UDMA controller. This driver requires dynamic tuning of the
-  chipset during the ide-probe at boot. It is reported to support DVD
-  II drives, by the manufacturer.
+  interrupt. The HPT343 chipset in its current form is a non-bootable or
+  HPT345/HPT363 chipset is bootable (needs BIOS FIX) PCI UDMA controllers.
+  This driver requires dynamic tuning of the chipset during the ide-probe
+  at boot. It is reported to support DVD II drives, by the manufacturer.
 
-  This requires CONFIG_IDEDMA_AUTO to be enabled.
+  Please read the comments at the top of drivers/block/hpt343.c
+
+HPT34X DMA support (DANGEROUS)
+CONFIG_BLK_DEV_HPT34X_DMA
+  This requires CONFIG_IDEDMA_PCI_AUTO to be enabled.
 
   Please read the comments at the top of drivers/block/hpt343.c
 
@@ -821,17 +872,17 @@ CONFIG_BLK_DEV_IDEDOUBLER
   Say Y if you have an IDE doubler.  The driver is enabled at kernel
   runtime using the "ide=doubler" kernel boot parameter.
 
- Support for PowerMac IDE devices (must also enable IDE)
- CONFIG_BLK_DEV_IDE_PMAC
-   No help for CONFIG_BLK_DEV_IDE_PMAC
+Support for PowerMac IDE devices (must also enable IDE)
+CONFIG_BLK_DEV_IDE_PMAC
+  No help for CONFIG_BLK_DEV_IDE_PMAC
 
- PowerMac IDE DMA support
- CONFIG_BLK_DEV_IDEDMA_PMAC
-   No help for CONFIG_BLK_DEV_IDEDMA_PMAC
+PowerMac IDE DMA support
+CONFIG_BLK_DEV_IDEDMA_PMAC
+  No help for CONFIG_BLK_DEV_IDEDMA_PMAC
 
- Use DMA by default
- CONFIG_PMAC_IDEDMA_AUTO
-   No help for CONFIG_PMAC_IDEDMA_AUTO
+Use DMA by default
+CONFIG_IDEDMA_PMAC_AUTO
+  No help for CONFIG_IDEDMA_PMAC_AUTO
 
 Macintosh Quadra/Powerbook IDE interface support
 CONFIG_BLK_DEV_MAC_IDE
@@ -843,9 +894,21 @@ CONFIG_BLK_DEV_MAC_IDE
   (hard disks, CD-ROM drives, etc.) that are connected to the builtin
   IDE interface.
 
- RapIDE interface support
- CONFIG_BLK_DEV_IDE_RAPIDE
-   No help for CONFIG_BLK_DEV_IDE_RAPIDE
+ICS IDE interface support
+CONFIG_BLK_DEV_IDE_ICSIDE
+  No help for CONFIG_BLK_DEV_IDE_ICSIDE
+
+ICS DMA support
+CONFIG_BLK_DEV_IDEDMA_ICS
+  No help for CONFIG_BLK_DEV_IDEDMA_ICS
+
+Use ICS DMA by default
+CONFIG_IDEDMA_ICS_AUTO
+  No help for CONFIG_IDEDMA_ICS_AUTO
+
+RapIDE interface support
+CONFIG_BLK_DEV_IDE_RAPIDE
+  No help for CONFIG_BLK_DEV_IDE_RAPIDE
 
 XT hard disk support
 CONFIG_BLK_DEV_XD
@@ -2218,12 +2281,12 @@ CONFIG_PARPORT
   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, read
-  Documentation/networking/net-modules.txt.
+  this driver at module load time, take a look at
+  Documentation/networking/parport.txt.
 
   If unsure, say Y.
 
-PC-style hardware 
+PC-style hardware
 CONFIG_PARPORT_PC
   You should say Y here if you have a PC-style parallel port. All IBM
   PC compatible computers and some Alphas have PC-style parallel
@@ -2236,28 +2299,36 @@ CONFIG_PARPORT_PC
   
   If unsure, say Y.
 
+Use FIFO/DMA if available
+CONFIG_PARPORT_PC_FIFO
+  Many parallel port chipsets provide hardware that can speed up
+  printing. Say Y here if you want to take advantage of that.
+
+  As well as actually having a FIFO, or DMA capability, the kernel
+  will need to know which IRQ the parallel port has. By default,
+  parallel port interrupts will not be used, and so neither will the
+  FIFO. See Documentation/parport.txt to find out how to specify
+  which IRQ/DMA to use.
+
 Support foreign hardware
 CONFIG_PARPORT_OTHER
   Say Y here if you want to be able to load driver modules to support
   other non-standard types of parallel ports. This causes a
   performance loss, so most people say N.
 
-Sun Ultra/AX-style hardware 
+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.
 
-Plug and Play support
-CONFIG_PNP
-  Plug and Play support allows the kernel to automatically configure
-  some peripheral devices. Say Y to enable PnP.
-
-Auto-probe for parallel devices
-CONFIG_PNP_PARPORT
-  Some IEEE-1284 conforming parallel-port devices can identify
-  themselves when requested. Say Y to enable this feature, or M to
-  compile it as a module (parport_probe.o). If in doubt, say N.
+IEEE1284 transfer modes
+CONFIG_PARPORT_1284
+  If you have a printer that supports status readback or device ID, or
+  want to use a device that uses enhanced parallel port transfer modes
+  such as EPP and ECP, say Y here to enable advanced IEEE 1284
+  transfer modes. Also say Y if you want device ID information to
+  appear in /proc/parport/*/autoprobe*. It is safe to say N.
 
 Enable loadable module support
 CONFIG_MODULES
@@ -8440,7 +8511,8 @@ CONFIG_PRINTER
   corresponding drivers into the kernel. If you want to compile this
   driver as a module however ( = code which can be inserted in and
   removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt. The module will be called lp.o. 
+  read Documentation/modules.txt and Documentation/parport.txt. The
+  module will be called lp.o. 
 
   If you have several parallel ports, you can specify which ports to
   use with the "lp" kernel command line option. (Try "man bootparam"
@@ -8454,11 +8526,18 @@ CONFIG_PRINTER
   If you have more than 3 printers, you need to increase the LP_NO
   variable in lp.c.
 
-Support IEEE1284 status readback
-CONFIG_PRINTER_READBACK
-  If your printer conforms to IEEE 1284, it may be able to provide a
-  status indication when you read from it (for example, with `cat
-  /dev/lp1'). To use this feature, say Y here.
+Support for console on line printer
+CONFIG_LP_CONSOLE
+  If you want kernel messages to be printed out as they occur, you
+  can have a console on the printer. This option adds support for
+  doing that; to actually get it to happen you need to pass the
+  option "console=lp" to the kernel at boot time.
+
+  Note that kernel messages can get lost if the printer is out of
+  paper (or off, or unplugged, or too busy..), but this behaviour
+  can be changed. See drivers/char/lp.c (do this at your own risk).
+
+  If unsure, say N.
 
 Mouse Support (not serial mice)
 CONFIG_MOUSE
index deac933c8afb2cf9429c1fd509baf563e65eed2a..99832ca96df28ee8ddd8b72efc210f9753edfe7b 100644 (file)
@@ -1,7 +1,7 @@
 SMP on x86/Linux is now an official feature and is not experimental.
 Experimental SMP support for other architectures is underway.
 
-Please view linux/Documentation/smp for more information about enabling SMP.
+Please view linux/Documentation/smp.txt for more information about enabling SMP.
 
 SMP support for Linux with up to 16 processors using the Intel MP
 specification. 
diff --git a/Documentation/fb/tgafb.txt b/Documentation/fb/tgafb.txt
new file mode 100644 (file)
index 0000000..36fe078
--- /dev/null
@@ -0,0 +1,51 @@
+[Also cloned from vesafb.txt, thanks to Gerd]
+
+What is tgafb?
+===============
+
+This is a driver for DECChip 21030 based graphics framebuffers, a.k.a. TGA
+cards, specifically the following models
+
+ZLxP-E1 (8bpp, 4 MB VRAM)
+ZLxP-E2 (32bpp, 8 MB VRAM)
+ZLxP-E3 (32bpp, 16 MB VRAM, Zbuffer)
+
+This version, tgafb-1.12, is almost a complete rewrite of the code written
+by Geert Uytterhoeven, which was based on the original TGA console code
+written by Jay Estabrook.
+
+Major new features:
+
+ * Support for multiple resolutions, including setting the resolution at
+   boot time, allowing the use of a fixed-frequency monitor.
+ * Complete code rewrite to follow Geert's skeletonfb spec which will allow
+   future implementation of hardware acceleration and other features.
+
+
+Configuration
+=============
+
+You can pass kernel command line options to tgafb with
+`video=tga:option1,option2:value2,option3' (multiple options should be
+separated by comma, values are separated from options by `:').
+Accepted options:
+
+font:X    - default font to use. All fonts are supported, including the
+            SUN12x22 font which is very nice at high resolutions.
+mode:X    - default video mode. See drivers/video/tgafb.c for a list.
+            
+X11
+===
+
+XF68_FBDev should work just fine, but I haven't tested it.  Running
+the XF86_TGA server (reasonably recent versions of which support all TGA
+cards) works fine for me.
+
+One minor problem with XF86_TGA is when running tgafb in resolutions higher
+than 640x480, on switching VCs from tgafb to X, the entire screen is not
+re-drawn and must be manually refreshed. This is an X server problem, not a
+tgafb problem.
+
+Enjoy!
+
+Martin Lucina <mato@kotelna.sk>
index 1b30c1183e3ee4e7fc54e2da80f62a9aabcee355..be7203d3b0a1ef479d5d9ac493e6fbe98d9fcc74 100644 (file)
@@ -21,7 +21,7 @@ other program after you have done the following:
 2) You have to compile BINFMT_MISC either as a module or into
    the kernel (CONFIG_BINFMT_MISC) and set it up properly.
    If you choose to compile it as a module, you will have
-   to insert it manually with modprobe/insmod, as kerneld
+   to insert it manually with modprobe/insmod, as kmod
    can not easy be supported with binfmt_misc. 
    Read the file 'binfmt_misc.txt' in this directory to know
    more about the configuration process.
@@ -29,14 +29,15 @@ other program after you have done the following:
 3) Add the following configuration items to binfmt_misc
    (you should really have read binfmt_misc.txt now):
    support for Java applications:
-     ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:'
+     ':Java:M::\xca\xfe\xba\xbe::/usr/local/bin/javawrapper:'
    support for Java Applets:
-     ':Applet:E::html::/usr/local/java/bin/appletviewer:'
+     ':Applet:E::html::/usr/bin/appletviewer:'
    or the following, if you want to be more selective:
-     ':Applet:M::<!--applet::/usr/local/java/bin/appletviewer:'
+     ':Applet:M::<!--applet::/usr/bin/appletviewer:'
 
-   Of cause you have to fix the path names, if you installed the JDK
-   at another place than /usr/local/java.
+   Of cause you have to fix the path names. Given path/file names in this
+   document match the Debian 2.1 system. (i.e. jdk installed in /usr,
+   custom wrappers from this document in /usr/local)
 
    Note, that for the more selective applet support you have to modify
    existing html-files to contain <!--applet--> in the first line
@@ -45,42 +46,300 @@ other program after you have done the following:
    For the compiled Java programs you need a wrapper script like the
    following (this is because Java is broken in case of the filename
    handling), again fix the path names, both in the script and in the
-   above given configuration string:
+   above given configuration string.
+
+   You, too, need the little program after the script. Compile like
+   gcc -O2 -o javaclassname javaclassname.c
+   and stick it to /usr/local/bin.
+
+   Both the javawrapper shellscript and the javaclassname program
+   were supplied by Colin J. Watson <cjw44@cam.ac.uk>.
 
 ====================== Cut here ===================
 #!/bin/bash
-# /usr/local/java/bin/javawrapper - the wrapper for binfmt_misc/java
+# /usr/local/bin/javawrapper - the wrapper for binfmt_misc/java
+
+if [ -z "$1" ]; then
+       exec 1>&2
+       echo Usage: $0 class-file
+       exit 1
+fi
+
 CLASS=$1
+FQCLASS=`/usr/local/bin/javaclassname $1`
+FQCLASSN=`echo $FQCLASS | sed -e 's/^.*\.\([^.]*\)$/\1/'`
+FQCLASSP=`echo $FQCLASS | sed -e 's-\.-/-g' -e 's-^[^/]*$--' -e 's-/[^/]*$--'`
 
-# if classname is a link, we follow it (this could be done easier - how?)
-if [ -L "$1" ] ; then
-        CLASS=`ls --color=no -l $1 | tr -s '\t ' '  ' | cut -d ' ' -f 11`
+# for example:
+# CLASS=Test.class
+# FQCLASS=foo.bar.Test
+# FQCLASSN=Test
+# FQCLASSP=foo/bar
+
+unset CLASSBASE
+
+declare -i LINKLEVEL=0
+
+while :; do
+       if [ "`basename $CLASS .class`" == "$FQCLASSN" ]; then
+               # See if this directory works straight off
+               cd -L `dirname $CLASS`
+               CLASSDIR=$PWD
+               cd $OLDPWD
+               if echo $CLASSDIR | grep -q "$FQCLASSP$"; then
+                       CLASSBASE=`echo $CLASSDIR | sed -e "s.$FQCLASSP$.."`
+                       break;
+               fi
+               # Try dereferencing the directory name
+               cd -P `dirname $CLASS`
+               CLASSDIR=$PWD
+               cd $OLDPWD
+               if echo $CLASSDIR | grep -q "$FQCLASSP$"; then
+                       CLASSBASE=`echo $CLASSDIR | sed -e "s.$FQCLASSP$.."`
+                       break;
+               fi
+               # If no other possible filename exists
+               if [ ! -L $CLASS ]; then
+                       exec 1>&2
+                       echo $0:
+                       echo "  $CLASS should be in a" \
+                            "directory tree called $FQCLASSP"
+                       exit 1
+               fi
+       fi
+       if [ ! -L $CLASS ]; then break; fi
+       # Go down one more level of symbolic links
+       let LINKLEVEL+=1
+       if [ $LINKLEVEL -gt 5 ]; then
+               exec 1>&2
+               echo $0:
+               echo "  Too many symbolic links encountered"
+               exit 1
+       fi
+       CLASS=`ls --color=no -l $CLASS | sed -e 's/^.* \([^ ]*\)$/\1/'`
+done
+
+if [ -z "$CLASSBASE" ]; then
+       if [ -z "$FQCLASSP" ]; then
+               GOODNAME=$FQCLASSN.class
+       else
+               GOODNAME=$FQCLASSP/$FQCLASSN.class
+       fi
+       exec 1>&2
+       echo $0:
+       echo "  $FQCLASS should be in a file called $GOODNAME"
+       exit 1
 fi
-CLASSN=`basename $CLASS .class`
-CLASSP=`dirname $CLASS`
-
-FOO=$PATH
-PATH=$CLASSPATH
-if [ -z "`type -p -a $CLASSN.class`" ] ; then
-        # class is not in CLASSPATH
-        if [ -e "$CLASSP/$CLASSN.class" ] ; then
-                # append dir of class to CLASSPATH
-                if [ -z "${CLASSPATH}" ] ; then
-                        export CLASSPATH=$CLASSP
-                else
-                        export CLASSPATH=$CLASSP:$CLASSPATH
-                fi
-        else
-                # uh! now we would have to create a symbolic link - really
-                # ugly, i.e. print a message that one has to change the setup
-                echo "Hey! This is not a good setup to run $1 !"
-                exit 1
-        fi
+
+if ! echo $CLASSPATH | grep -q "^\(.*:\)*$CLASSBASE\(:.*\)*"; then
+       # class is not in CLASSPATH, so prepend dir of class to CLASSPATH
+       if [ -z "${CLASSPATH}" ] ; then
+               export CLASSPATH=$CLASSBASE
+       else
+               export CLASSPATH=$CLASSBASE:$CLASSPATH
+       fi
 fi
-PATH=$FOO
 
 shift
-/usr/local/java/bin/java $CLASSN "$@"
+/usr/bin/java $FQCLASS "$@"
+====================== Cut here ===================
+
+
+====================== Cut here ===================
+/* javaclassname.c
+ *
+ * Extracts the class name from a Java class file; intended for use in a Java
+ * wrapper of the type supported by the binfmt_misc option in the Linux kernel.
+ *
+ * Copyright (C) 1999 Colin J. Watson <cjw44@cam.ac.uk>.
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+
+/* From Sun's Java VM Specification, as tag entries in the constant pool. */
+
+#define CP_UTF8 1
+#define CP_INTEGER 3
+#define CP_FLOAT 4
+#define CP_LONG 5
+#define CP_DOUBLE 6
+#define CP_CLASS 7
+#define CP_STRING 8
+#define CP_FIELDREF 9
+#define CP_METHODREF 10
+#define CP_INTERFACEMETHODREF 11
+#define CP_NAMEANDTYPE 12
+
+/* Define some commonly used error messages */
+
+#define seek_error() error("%s: Cannot seek\n", program)
+#define corrupt_error() error("%s: Class file corrupt\n", program)
+#define eof_error() error("%s: Unexpected end of file\n", program)
+#define utf8_error() error("%s: Only ASCII 1-255 supported\n", program);
+
+char *program;
+
+long *pool;
+
+u_int8_t read_8(FILE *classfile);
+u_int16_t read_16(FILE *classfile);
+void skip_constant(FILE *classfile, u_int16_t *cur);
+void error(const char *format, ...);
+int main(int argc, char **argv);
+
+/* Reads in an unsigned 8-bit integer. */
+u_int8_t read_8(FILE *classfile)
+{
+       int b = fgetc(classfile);
+       if(b == EOF)
+               eof_error();
+       return (u_int8_t)b;
+}
+
+/* Reads in an unsigned 16-bit integer. */
+u_int16_t read_16(FILE *classfile)
+{
+       int b1, b2;
+       b1 = fgetc(classfile);
+       if(b1 == EOF)
+               eof_error();
+       b2 = fgetc(classfile);
+       if(b2 == EOF)
+               eof_error();
+       return (u_int16_t)((b1 << 8) | b2);
+}
+
+/* Reads in a value from the constant pool. */
+void skip_constant(FILE *classfile, u_int16_t *cur)
+{
+       u_int16_t len;
+       int seekerr = 1;
+       pool[*cur] = ftell(classfile);
+       switch(read_8(classfile))
+       {
+       case CP_UTF8:
+               len = read_16(classfile);
+               seekerr = fseek(classfile, len, SEEK_CUR);
+               break;
+       case CP_CLASS:
+       case CP_STRING:
+               seekerr = fseek(classfile, 2, SEEK_CUR);
+               break;
+       case CP_INTEGER:
+       case CP_FLOAT:
+       case CP_FIELDREF:
+       case CP_METHODREF:
+       case CP_INTERFACEMETHODREF:
+       case CP_NAMEANDTYPE:
+               seekerr = fseek(classfile, 4, SEEK_CUR);
+               break;
+       case CP_LONG:
+       case CP_DOUBLE:
+               seekerr = fseek(classfile, 8, SEEK_CUR);
+               ++(*cur);
+               break;
+       default:
+               corrupt_error();
+       }
+       if(seekerr)
+               seek_error();
+}
+
+void error(const char *format, ...)
+{
+       va_list ap;
+       va_start(ap, format);
+       vfprintf(stderr, format, ap);
+       va_end(ap);
+       exit(1);
+}
+
+int main(int argc, char **argv)
+{
+       FILE *classfile;
+       u_int16_t cp_count, i, this_class, classinfo_ptr;
+       u_int8_t length;
+
+       program = argv[0];
+
+       if(!argv[1])
+               error("%s: Missing input file\n", program);
+       classfile = fopen(argv[1], "rb");
+       if(!classfile)
+               error("%s: Error opening %s\n", program, argv[1]);
+
+       if(fseek(classfile, 8, SEEK_SET))  /* skip magic and version numbers */
+               seek_error();
+       cp_count = read_16(classfile);
+       pool = calloc(cp_count, sizeof(long));
+       if(!pool)
+               error("%s: Out of memory for constant pool\n", program);
+
+       for(i = 1; i < cp_count; ++i)
+               skip_constant(classfile, &i);
+       if(fseek(classfile, 2, SEEK_CUR))       /* skip access flags */
+               seek_error();
+
+       this_class = read_16(classfile);
+       if(this_class < 1 || this_class >= cp_count)
+               corrupt_error();
+       if(!pool[this_class] || pool[this_class] == -1)
+               corrupt_error();
+       if(fseek(classfile, pool[this_class] + 1, SEEK_SET))
+               seek_error();
+
+       classinfo_ptr = read_16(classfile);
+       if(classinfo_ptr < 1 || classinfo_ptr >= cp_count)
+               corrupt_error();
+       if(!pool[classinfo_ptr] || pool[classinfo_ptr] == -1)
+               corrupt_error();
+       if(fseek(classfile, pool[classinfo_ptr] + 1, SEEK_SET))
+               seek_error();
+
+       length = read_16(classfile);
+       for(i = 0; i < length; ++i)
+       {
+               u_int8_t x = read_8(classfile);
+               if((x & 0x80) || !x)
+               {
+                       if((x & 0xE0) == 0xC0)
+                       {
+                               u_int8_t y = read_8(classfile);
+                               if((y & 0xC0) == 0x80)
+                               {
+                                       int c = ((x & 0x1f) << 6) + (y & 0x3f);
+                                       if(c) putchar(c);
+                                       else utf8_error();
+                               }
+                               else utf8_error();
+                       }
+                       else utf8_error();
+               }
+               else if(x == '/') putchar('.');
+               else putchar(x);
+       }
+       putchar('\n');
+       free(pool);
+       fclose(classfile);
+       return 0;
+}
 ====================== Cut here ===================
 
 
@@ -116,4 +375,6 @@ the execution bit, then just do
 
 
 originally by Brian A. Lantz, brian@lantz.com
-heavily edited for binfmt_misc by Richard Günther.
+heavily edited for binfmt_misc by Richard Günther
+new scripts by Colin J. Watson <cjw44@cam.ac.uk>.
+
index 108c3b645b626ee708ffa911071efd6855c3c44f..ebdef08735190877e781515a494b27c0088a42d0 100644 (file)
@@ -1,15 +1,16 @@
 Quick Summary
 -------------
 
-cd /usr/src/linux/scripts/ksymoops
-make ksymoops
-./ksymoops < the_oops.txt
+Install ksymoops from ftp://ftp.ocs.com.au/pub/ksymoops
+Read the ksymoops man page.
+ksymoops < the_oops.txt
 
 and send the output the maintainer of the kernel area that seems to be
-involved with the problem. Don't worry too much about getting the wrong
-person. If you are unsure send it to the person responsible for the code
-relevant to what you were doing. If it occurs repeatably try and describe
-how to recreate it. Thats worth even more than the oops
+involved with the problem, not to the ksymoops maintainer. Don't worry
+too much about getting the wrong person. If you are unsure send it to
+the person responsible for the code relevant to what you were doing.
+If it occurs repeatably try and describe how to recreate it. Thats
+worth even more than the oops
 
 If you are totally stumped as to whom to send the report, send it to 
 linux-kernel@vger.rutgers.edu. Thanks for your help in making Linux as
@@ -41,9 +42,8 @@ Oh, it helps if the report happens on a kernel that is compiled with the
 same compiler and similar setups.
 
 The other thing to do is disassemble the "Code:" part of the bug report: 
-ksymoops will do this too with the correct tools (and new version of 
-ksymoops), but if you don't have the tools you can just do a silly 
-program:
+ksymoops will do this too with the correct tools, but if you don't have
+the tools you can just do a silly program:
 
        char str[] = "\xXX\xXX\xXX...";
        main(){}
index 6cf09e631071d945395c18a6009ddacbcd566f28..15e3303c9e86bd89455c4737bf530fa3c8cee3e6 100644 (file)
@@ -28,17 +28,20 @@ architecture-dependent code with (for example):
 
 to tell the parport code that you want three PC-style ports, one at
 0x3bc with no IRQ, one at 0x378 using IRQ 7, and one at 0x278 with an
-auto-detected IRQ.  Currently, PC-style (parport_pc) and Sun Ultra/AX
-(parport_ax) hardware is supported; more is in the works.
+auto-detected IRQ.  Currently, PC-style (parport_pc), Sun Ultra/AX
+(parport_ax), Amiga, Atari, and MFC3 hardware is supported.
 
 
 KMod
 ----
 
 If you use kmod, you will find it useful to edit /etc/conf.modules.
-Here is an example of the lines that need to be added:
+When a driver needs to use the parport subsystem for the first time, a
+module by the name of parport_lowlevel will be automatically loaded
+via kmod.  No module actually exists with that name; it's just an
+alias.  Here is an example of the lines that need to be added:
 
-       alias parport_lowlevel parport_pc
+       post-install parport modprobe -k parport_pc
        options parport_pc io=0x378,0x278 irq=7,auto
 
 KMod will then automatically load parport_pc (with the options
@@ -49,20 +52,15 @@ KMod will then automatically load parport_pc (with the options
 Parport probe [optional]
 -------------
 
-Once the architecture-dependent part of the parport code is loaded
-into the kernel, you can insert the parport_probe module with:
-
-       # insmod parport_probe.o
-
-This will perform an IEEE1284 probe of any attached devices and log a
-message similar to:
+In 2.2 kernels there was a module called parport_probe, which was used
+for collecting IEEE 1284 device ID information.  This has now been
+enhanced and now lives with the IEEE 1284 support.  When a parallel
+port is detected, the devices that are connected to it are analysed,
+and information is logged like this:
 
        parport0: Printer, BJC-210 (Canon)
 
-(If you are using kmod and have configured parport_probe as a module,
-this will just happen.)
-
-The probe information is available in /proc/parport/?/autoprobe.
+The probe information is available from files in /proc/sys/dev/parport/.
 
 
 Parport linked into the kernel statically
@@ -85,29 +83,74 @@ Files in /proc
 ==============
 
 If you have configured the /proc filesystem into your kernel, you will
-see a new directory entry: /proc/parport.  In there will be a
+see a new directory entry: /proc/sys/dev/parport.  In there will be a
 directory entry for each parallel port for which parport is
-configured.  In each of those directories are four files describing
-that parallel port.  For example:
-
-File:                          Contents:
-
-/proc/parport/0/devices                A list of the device drivers using
-                               that port.  A "+" will appear by the
-                               name of the device currently using the
-                               port (it might not appear against any).
-
-/proc/parport/0/hardware       Parallel port's base address, IRQ line
-                               and DMA channel.
-
-/proc/parport/0/irq            The IRQ that parport is using for that
-                               port.  This is in a separate file to
-                                allow you to alter it by writing a new
-                               value in (IRQ number or "none").
-
-/proc/parport/0/autoprobe      Any IEEE-1284 device ID information
-                               that has been acquired.
-
+configured.  In each of those directories are a collection of files
+describing that parallel port.
+
+The /proc/sys/dev/parport directory tree looks like:
+
+parport
+|-- default
+|   |-- spintime
+|   `-- timeslice
+|-- parport0
+|   |-- autoprobe
+|   |-- autoprobe0
+|   |-- autoprobe1
+|   |-- autoprobe2
+|   |-- autoprobe3
+|   |-- devices
+|   |   |-- active
+|   |   `-- lp
+|   |       `-- timeslice
+|   |-- hardware
+|   `-- spintime
+`-- parport1
+    |-- autoprobe
+    |-- autoprobe0
+    |-- autoprobe1
+    |-- autoprobe2
+    |-- autoprobe3
+    |-- devices
+    |   |-- active
+    |   `-- ppa
+    |       `-- timeslice
+    |-- hardware
+    `-- spintime
+
+
+File:          Contents:
+
+devices/active A list of the device drivers using that port.  A "+"
+               will appear by the name of the device currently using
+               the port (it might not appear against any).  The
+               string "none" means that there are no device drivers
+               using that port.
+
+hardware       Parallel port's base address, IRQ line and DMA channel.
+
+autoprobe      Any IEEE-1284 device ID information that has been
+               acquired from the (non-IEEE 1284.3) device.
+
+autoprobe[0-3] IEEE 1284 device ID information retrieved from
+               daisy-chain devices that conform to IEEE 1284.3.
+
+spintime       The number of microseconds to busy-loop while waiting
+               for the peripheral to respond.  You might find that
+               adjusting this improves performance, depending on your
+               peripherals.  This is a port-wide setting, i.e. it
+               applies to all devices on a particular port.
+
+timeslice      The number of jiffies (FIXME: this should be in
+               milliseconds or something) that a device driver is
+               allowed to keep a port claimed for.  This is advisory,
+               and driver can ignore it if it must.
+
+default/*      The defaults for spintime and timeslice. When a new
+               port is registered, it picks up the default spintime.
+               When a new device is registered, it picks up the
+               default timeslice.
 
 Device drivers
 ==============
@@ -135,7 +178,7 @@ regardless of base address.
 
 Also:
 
- * If you selected the IEEE-1284 autoprobe at compile time, you can say
+ * If you selected the IEEE 1284 support at compile time, you can say
    `lp=auto' on the kernel command line, and lp will create devices
    only for those ports that seem to have printers attached.
 
index ec74c4044c72cc55e853c5d0a605946792257fae..5a6f7620471b75d7c13e98751b4c84ad38fdf4c9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 9
+SUBLEVEL = 10
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -351,8 +351,7 @@ endif
 
 clean: archclean
        rm -f kernel/ksyms.lst include/linux/compile.h
-       rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' \
-               ! -regex '.*ksymoops/.*' -print`
+       rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print`
        rm -f core `find . -type f -name 'core' -print`
        rm -f core `find . -name '.*.flags' -print`
        rm -f vmlinux System.map
@@ -376,7 +375,6 @@ mrproper: clean archmrproper
        rm -f .version .config* config.in config.old
        rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp
        rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
-       rm -f scripts/ksymoops/*.o scripts/ksymoops/ksymoops
        rm -f .menuconfig.log
        rm -f include/asm
        rm -rf include/config
diff --git a/README b/README
index dd95240e60ed27d25296f92925ee991e9fee6e9a..a1f137898f155c961b39cba1dc50e59a8558e50f 100644 (file)
--- a/README
+++ b/README
@@ -9,9 +9,9 @@ public use.  Different releases may have various and sometimes severe
 bugs.  It is *strongly* recommended that you back up the previous kernel
 before installing any new 2.3.xx release.
 
-If you need to use a proven and stable Linux kernel, please use 1.2.13,
-2.0.36 or 2.2.xx.  All features which will be in the 2.3.xx releases will
-be contained in 2.4.xx when the code base has stabilized again.
+If you need to use a proven and stable Linux kernel, please use 2.0.37
+or 2.2.xx.  All features which will be in the 2.3.xx releases will be
+contained in 2.4.xx when the code base has stabilized again. 
 
 If you decide to use 2.3, it is recommended that you join the kernel mailing
 list.  To do this, e-mail majordomo@vger.rutgers.edu, and put in the body
@@ -105,7 +105,7 @@ INSTALLING the kernel:
 
 SOFTWARE REQUIREMENTS
 
-   Compiling and running the 2.3.x kernels requires up-to-date
+   Compiling and running the 2.3.xx kernels requires up-to-date
    versions of various software packages.  Consult
    ./Documentation/Changes for the minimum version numbers required
    and how to get updates for these packages.  Beware that using
index 75b3e9563e7ef72248a1a407dc9c5449918b83d1..eb9752970c7974400e9b6fda5d4ffb4fd1d15394 100644 (file)
@@ -188,13 +188,7 @@ tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '  PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
-    bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
-  fi
-fi
+source drivers/misc/Config.in
 endmenu
 
 source drivers/pnp/Config.in
index e97021869ac7a445fc3bf1aa54968d3cd4109a99..eef452e57b61146ae2bcb73154ffcc1b718469c3 100644 (file)
@@ -603,7 +603,7 @@ smp_percpu_timer_interrupt(struct pt_regs *regs)
 
                update_one_process(current, 1, user, !user, cpu);
                if (current->pid) {
-                       if (--current->counter < 0) {
+                       if (--current->counter <= 0) {
                                current->counter = 0;
                                current->need_resched = 1;
                        }
index f0ac5e2c03e89ed8175a8ac3e0b39d566a0c210c..56b3fd802fc25b8810300e750096a21a32a88e0b 100644 (file)
@@ -92,13 +92,7 @@ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '   PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
-    bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
-  fi
-fi
+source drivers/misc/Config.in
 
 bool 'Advanced Power Management BIOS support' CONFIG_APM
 if [ "$CONFIG_APM" = "y" ]; then
index 856ceecf3a7f1cb21dbbcdff3250960de0adfd9c..80656a9971982ce8b61bf12cc623af43eb01c026 100644 (file)
@@ -69,11 +69,6 @@ CONFIG_BINFMT_MISC=y
 # CONFIG_I2O_SCSI is not set
 # CONFIG_I2O_PROC is not set
 
-#
-# Plug and Play support
-#
-# CONFIG_PNP is not set
-
 #
 # Block devices
 #
@@ -98,6 +93,8 @@ CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_BLK_DEV_IDEDMA_PCI is not set
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_AEC6210 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+CONFIG_BLK_DEV_PIIX=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
index 6a19d9884a7dbc4aceec1cca7c4e7ccef7abd860..1023cd4da31e1997af0f7633b2be94a5fa70e89f 100644 (file)
@@ -238,7 +238,7 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
  */
 static inline void x86_do_profile (unsigned long eip)
 {
-       if (prof_buffer && current->pid) {
+       if (prof_buffer) {
                eip -= (unsigned long) &_stext;
                eip >>= prof_shift;
                /*
index ad745f58ac8265c417e1869490b0252771375b72..ad522c6c755eb2885cf1e0c8716c4821ce6fcb3c 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/config.h>
 #include <linux/unistd.h>
 #include <linux/delay.h>
-#include <linux/smp.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
index 09664ba815c087c323b9a6aa5f749cd43ff298da..28aea16a8bc26d9a2e80b0f98c81140de9c756cf 100644 (file)
@@ -73,8 +73,7 @@ static inline int put_stack_long(struct task_struct *task, int offset,
  * and that it is in the task area before calling this: this routine does
  * no checking.
  */
-static unsigned long get_long(struct task_struct * tsk, 
-       struct vm_area_struct * vma, unsigned long addr)
+static unsigned long get_long(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr)
 {
        pgd_t * pgdir;
        pmd_t * pgmiddle;
@@ -84,7 +83,7 @@ static unsigned long get_long(struct task_struct * tsk,
 repeat:
        pgdir = pgd_offset(vma->vm_mm, addr);
        if (pgd_none(*pgdir)) {
-               handle_mm_fault(tsk, vma, addr, 0);
+               handle_mm_fault(mm, vma, addr, 0);
                goto repeat;
        }
        if (pgd_bad(*pgdir)) {
@@ -94,7 +93,7 @@ repeat:
        }
        pgmiddle = pmd_offset(pgdir, addr);
        if (pmd_none(*pgmiddle)) {
-               handle_mm_fault(tsk, vma, addr, 0);
+               handle_mm_fault(mm, vma, addr, 0);
                goto repeat;
        }
        if (pmd_bad(*pgmiddle)) {
@@ -104,7 +103,7 @@ repeat:
        }
        pgtable = pte_offset(pgmiddle, addr);
        if (!pte_present(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, 0);
+               handle_mm_fault(mm, vma, addr, 0);
                goto repeat;
        }
        page = pte_page(*pgtable);
@@ -124,7 +123,7 @@ repeat:
  * Now keeps R/W state of page so that a text page stays readonly
  * even if a debugger scribbles breakpoints into it.  -M.U-
  */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
+static void put_long(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr,
        unsigned long data)
 {
        pgd_t *pgdir;
@@ -135,7 +134,7 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi
 repeat:
        pgdir = pgd_offset(vma->vm_mm, addr);
        if (!pgd_present(*pgdir)) {
-               handle_mm_fault(tsk, vma, addr, 1);
+               handle_mm_fault(mm, vma, addr, 1);
                goto repeat;
        }
        if (pgd_bad(*pgdir)) {
@@ -145,7 +144,7 @@ repeat:
        }
        pgmiddle = pmd_offset(pgdir, addr);
        if (pmd_none(*pgmiddle)) {
-               handle_mm_fault(tsk, vma, addr, 1);
+               handle_mm_fault(mm, vma, addr, 1);
                goto repeat;
        }
        if (pmd_bad(*pgmiddle)) {
@@ -155,12 +154,12 @@ repeat:
        }
        pgtable = pte_offset(pgmiddle, addr);
        if (!pte_present(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, 1);
+               handle_mm_fault(mm, vma, addr, 1);
                goto repeat;
        }
        page = pte_page(*pgtable);
        if (!pte_write(*pgtable)) {
-               handle_mm_fault(tsk, vma, addr, 1);
+               handle_mm_fault(mm, vma, addr, 1);
                goto repeat;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -176,10 +175,10 @@ repeat:
  * This routine checks the page boundaries, and that the offset is
  * within the task area. It then calls get_long() to read a long.
  */
-static int read_long(struct task_struct * tsk, unsigned long addr,
+static int read_long(struct mm_struct * mm, unsigned long addr,
        unsigned long * result)
 {
-       struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+       struct vm_area_struct * vma = find_extend_vma(mm, addr);
 
        if (!vma)
                return -EIO;
@@ -192,8 +191,8 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
                        if (!vma_high || vma_high->vm_start != vma->vm_end)
                                return -EIO;
                }
-               low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
-               high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
+               low = get_long(mm, vma, addr & ~(sizeof(long)-1));
+               high = get_long(mm, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
                switch (addr & (sizeof(long)-1)) {
                        case 1:
                                low >>= 8;
@@ -210,7 +209,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
                }
                *result = low;
        } else
-               *result = get_long(tsk, vma, addr);
+               *result = get_long(mm, vma, addr);
        return 0;
 }
 
@@ -218,10 +217,10 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
  * This routine checks the page boundaries, and that the offset is
  * within the task area. It then calls put_long() to write a long.
  */
-static int write_long(struct task_struct * tsk, unsigned long addr,
+static int write_long(struct mm_struct * mm, unsigned long addr,
        unsigned long data)
 {
-       struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+       struct vm_area_struct * vma = find_extend_vma(mm, addr);
 
        if (!vma)
                return -EIO;
@@ -234,8 +233,8 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
                        if (!vma_high || vma_high->vm_start != vma->vm_end)
                                return -EIO;
                }
-               low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
-               high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
+               low = get_long(mm, vma, addr & ~(sizeof(long)-1));
+               high = get_long(mm, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
                switch (addr & (sizeof(long)-1)) {
                        case 0: /* shouldn't happen, but safety first */
                                low = data;
@@ -259,10 +258,10 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
                                high |= data >> 8;
                                break;
                }
-               put_long(tsk, vma, addr & ~(sizeof(long)-1),low);
-               put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
+               put_long(mm, vma, addr & ~(sizeof(long)-1),low);
+               put_long(mm, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
        } else
-               put_long(tsk, vma, addr, data);
+               put_long(mm, vma, addr, data);
        return 0;
 }
 
@@ -404,7 +403,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        unsigned long tmp;
 
                        down(&child->mm->mmap_sem);
-                       ret = read_long(child, addr, &tmp);
+                       ret = read_long(child->mm, addr, &tmp);
                        up(&child->mm->mmap_sem);
                        if (ret >= 0)
                                ret = put_user(tmp,(unsigned long *) data);
@@ -437,7 +436,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                case PTRACE_POKETEXT: /* write the word at location addr. */
                case PTRACE_POKEDATA:
                        down(&child->mm->mmap_sem);
-                       ret = write_long(child,addr,data);
+                       ret = write_long(child->mm,addr,data);
                        up(&child->mm->mmap_sem);
                        goto out;
 
index 9d3a8b4b58f26b21e54331afe248cfc156b0f484..f092d09059b2117aa6835fe850dbeadede9135fc 100644 (file)
@@ -1792,7 +1792,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs)
                update_one_process(p, 1, user, system, cpu);
                if (p->pid) {
                        p->counter -= 1;
-                       if (p->counter < 0) {
+                       if (p->counter <= 0) {
                                p->counter = 0;
                                p->need_resched = 1;
                        }
index 5a1f363bdf57738ec06b39fa619f064035163d7b..bb808c300ebb6e850d9190a89fb7f30c85a6b9b0 100644 (file)
@@ -50,7 +50,7 @@ good_area:
        start &= PAGE_MASK;
 
        for (;;) {
-               handle_mm_fault(current,vma, start, 1);
+               handle_mm_fault(current->mm, vma, start, 1);
                if (!size)
                        break;
                size--;
@@ -162,7 +162,7 @@ good_area:
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       if (!handle_mm_fault(tsk, vma, address, write))
+       if (!handle_mm_fault(mm, vma, address, write))
                goto do_sigbus;
 
        /*
index cc5d844e4c1f3b93c7295431b7a6f496488d4f5c..1fecee23f9dddc5da899e4cc449d7eeabc20a490 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/autoconf.h>
 
 #include <asm/bcache.h>
 #include <asm/sgi.h>
index 2881decd7ecff450bf2035fbec23a8d5199c28e6..e7a649a32ca0692db3033001a592ca192231a824 100644 (file)
@@ -66,13 +66,7 @@ define_bool CONFIG_BINFMT_ELF y
 define_bool CONFIG_KERNEL_ELF y
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
-tristate 'Parallel port support' CONFIG_PARPORT
-if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate '   PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
-  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
-    bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
-  fi
-fi
+source drivers/misc/Config.in
 
 bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
 bool 'Support for frame buffer devices' CONFIG_FB
index 2cb23188ab6be80c6ec12c39c9c8de7a6d121d59..523a1945fc09c5a2d815f79642aa2015764b71b7 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/malloc.h>
 #include <linux/user.h>
 #include <linux/elf.h>
-#include <linux/elf.h>
 #include <linux/init.h>
 
 #include <asm/pgtable.h>
index fc2613ddf423c1ff749904e862e1a14f2fee7da3..5c26da8cc653403db55208299dcf0a79657bc5af 100644 (file)
@@ -85,7 +85,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs)
                        update_one_process(p, 1, user, system, cpu);
 
                        p->counter -= 1;
-                       if (p->counter < 0) {
+                       if (p->counter <= 0) {
                                p->counter = 0;
                                current->need_resched = 1;
                        }
index edd736b41bd844e4d88d6380b0c2115d84ca0345..64ef31bbb4fb5232919762358fd29e0fd1dbe5ec 100644 (file)
@@ -473,7 +473,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
                if(current->pid) {
                        update_one_process(current, 1, user, !user, cpu);
 
-                       if(--current->counter < 0) {
+                       if(--current->counter <= 0) {
                                current->counter = 0;
                                current->need_resched = 1;
                        }
index c9acf609c47e98157031305c055b0cd3c1d68046..3fb1044f4db85c43b6855fa66ffc87de2fb4de18 100644 (file)
@@ -454,7 +454,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
                if(current->pid) {
                        update_one_process(current, 1, user, !user, cpu);
 
-                       if(--current->counter < 0) {
+                       if(--current->counter <= 0) {
                                current->counter = 0;
                                current->need_resched = 1;
                        }
index c501884ed9ae5605795ad863a151a92ba546b097..eb192c584be452b92de8b600d47a2f8be4652c02 100644 (file)
@@ -68,20 +68,8 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 fi
 
 if [ "$CONFIG_PCI" = "y" ]; then
-  tristate 'Parallel port support' CONFIG_PARPORT
-  if [ "$CONFIG_PARPORT" != "n" ]; then
-    dep_tristate '  Ultra/AX-style hardware' CONFIG_PARPORT_AX $CONFIG_PARPORT
-    if [ "$CONFIG_PARPORT_AX" = "m" ]; then
-      define_bool CONFIG_PARPORT_LOWLEVEL_MODULE y
-    fi
-    if [ "$CONFIG_PARPORT_AX" != "n" ]; then
-      bool '  Support foreign hardware' CONFIG_PARPORT_OTHER
-    fi
-    dep_tristate '  Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
-    if [ "$CONFIG_PRINTER" != "n" ]; then
-      bool '    Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
-    fi
-  fi
+  source drivers/misc/Config.in
+  dep_tristate '  Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
   tristate 'SUNW,envctrl support' CONFIG_ENVCTRL
 fi
 endmenu
index 7d638c5da33aaf03cdc51088e226a9a48a5c24b6..bc77266f90cbb37de915669d743bbee1e5cd1b60 100644 (file)
@@ -311,9 +311,10 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm,
                fd = open_dentry(bprm->dentry, O_RDONLY);
                if (fd < 0)
                        return fd;
-               file = fcheck(fd);
+               file = fget(fd);
 
                if (!file->f_op || !file->f_op->mmap) {
+                       fput(fd);
                        sys_close(fd);
                        do_brk(0, ex.a_text+ex.a_data);
                        read_exec(bprm->dentry, fd_offset,
@@ -327,6 +328,7 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm,
                        fd_offset);
 
                if (error != N_TXTADDR(ex)) {
+                       fput(file);
                        sys_close(fd);
                        send_sig(SIGKILL, current, 0);
                        return error;
@@ -336,6 +338,7 @@ static inline int do_load_aout32_binary(struct linux_binprm * bprm,
                                PROT_READ | PROT_WRITE | PROT_EXEC,
                                MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
                                fd_offset + ex.a_text);
+               fput(file);
                sys_close(fd);
                if (error != N_DATADDR(ex)) {
                        send_sig(SIGKILL, current, 0);
index b0e92d50bafd4289e5e3dff484c875095e041148..a0e8f7e6999f1ffc9f7acda4baa9d9864a6aa5ea 100644 (file)
@@ -615,7 +615,7 @@ do {        hardirq_enter(cpu);                     \
                                unsigned int *inc, *inc2;
 
                                update_one_process(current, 1, user, !user, cpu);
-                               if(--current->counter < 0) {
+                               if(--current->counter <= 0) {
                                        current->counter = 0;
                                        current->need_resched = 1;
                                }
index 0e73f0c65a43b1596733075e2f19f844e6237e71..d0b4a5d07555519e959a6bab94560a085b01c5c3 100644 (file)
@@ -41,30 +41,49 @@ else
         bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
         if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
           bool '     Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO
+          if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+            bool '       Good-Bad DMA Model-Firmware (EXPERIMENTAL)' IDEDMA_NEW_DRIVE_LISTINGS
+            bool '       Generic ATA-66 support (DANGEROUS)' CONFIG_IDEDMA_ULTRA_66
+            define_bool IDEDMA_PCI_EXPERIMENTAL y
+          else
+            define_bool IDEDMA_PCI_EXPERIMENTAL n
+          fi
         fi
         bool '     Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
         bool '     AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
+        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+          bool '     ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
+          bool '     CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
+          bool '     CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
+        fi
+        bool '     HPT34X chipset support' CONFIG_BLK_DEV_HPT34X
+        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
+             "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
+          bool '       HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA
+        fi
+        bool '     Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
+        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
+             "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+          bool '       PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING
+        fi
+        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+          bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
+        fi
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
           bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
-          bool '     Intel PIIXn chipsets support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX
-          if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
-            bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
-            bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
-            bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
-            bool '     CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
-            bool '     ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
-            bool '     CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
-            bool '     PDC20246 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20246
-            bool '     PDC20262 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC20262
-            if [ "$CONFIG_BLK_DEV_PDC20246" = "y" -o \
-                 "$CONFIG_BLK_DEV_PDC20262" = "y" ]; then
-              define_bool CONFIG_BLK_DEV_PDC202XX y
-            else
-              define_bool CONFIG_BLK_DEV_PDC202XX n
-            fi
-            bool '     HPT343 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT343
+        fi
+        if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+          bool '     PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX
+          if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
+               "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
+            bool '       Special UDMA Feature (EXPERIMENTAL)' PDC202XX_FORCE_BURST_BIT
+            bool '       Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE
           fi
         fi
+        if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+          bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
+          bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
+        fi
       fi
       if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
           bool '   Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
@@ -106,13 +125,12 @@ else
       bool '     ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
       bool '     DTC-2278 support' CONFIG_BLK_DEV_DTC2278
       bool '     Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+      if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \
+           "$CONFIG_EXPERIMENTAL" = "y" ]; then
+        bool '     PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+      fi
       bool '     QDI QD6580 support' CONFIG_BLK_DEV_QD6580
       bool '     UMC-8672 support' CONFIG_BLK_DEV_UMC8672
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" ]; then
-          bool '     PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
-        fi
-      fi
     fi
     if [ "$CONFIG_AMIGA" = "y" ]; then
       bool '   Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
@@ -182,13 +200,13 @@ if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
   source drivers/block/paride/Config.in
 fi
 
-
-if [ "$CONFIG_BLK_DEV_CMD640" = "y" -o \
-     "$CONFIG_IDE_CHIPSETS" = "y" -o \
-     "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
-     "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
+     "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
+     "$CONFIG_BLK_DEV_CMD640" = "y" -o \
      "$CONFIG_BLK_DEV_CY82C693" = "y" -o \
-     "$CONFIG_BLK_DEV_HPT343" = "y" -o \
+     "$CONFIG_BLK_DEV_HPT34X" = "y" -o \
+     "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+     "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
      "$CONFIG_BLK_DEV_PIIX" = "y" -o \
      "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
   define_bool CONFIG_BLK_DEV_IDE_MODES y
index 7d553f9b2b7293a9ddc44f697c0be5fe3b8cea1a..61909b033ff8665e871331db1d1877291b6c2b6e 100644 (file)
@@ -202,8 +202,8 @@ ifeq ($(CONFIG_BLK_DEV_AEC6210),y)
 IDE_OBJS += aec6210.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_HPT343),y)
-IDE_OBJS += hpt343.o
+ifeq ($(CONFIG_BLK_DEV_HPT34X),y)
+IDE_OBJS += hpt34x.o
 endif
 
 ### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored
index ce5d0cb63afb0f216750919c388a8c51e7975bf4..4ea590fa294726cab98aec0fe21d8b0c185b34b0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/alim15x3.c      Version 0.04    Feb. 8, 1999
+ * linux/drivers/block/alim15x3.c      Version 0.05    Jun. 29, 1999
  *
  *  Copyright (C) 1998-99 Michel Aubry, Maintainer
  *  Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer
@@ -20,6 +20,8 @@
 
 #include <asm/io.h>
 
+#include "ide_modes.h"
+
 #define DISPLAY_ALI_TIMINGS
 
 #if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
@@ -59,6 +61,55 @@ char *channel_status[8] = {
 };
 #endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
 
+static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
+{
+       ide_pio_data_t d;
+       ide_hwif_t *hwif = HWIF(drive);
+       struct pci_dev *dev = hwif->pci_dev;
+       int s_time, a_time, c_time;
+       byte s_clc, a_clc, r_clc;
+       unsigned long flags;
+       int bus_speed = ide_system_bus_speed();
+       int port = hwif->index ? 0x5c : 0x58;
+
+       pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+       s_time = ide_pio_timings[pio].setup_time;
+       a_time = ide_pio_timings[pio].active_time;
+       if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+               s_clc = 0;
+       if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+               a_clc = 0;
+       c_time = ide_pio_timings[pio].cycle_time;
+
+#if 0
+       if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+               r_clc = 0;
+#endif
+
+       if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+               r_clc = 1;
+       } else {
+               if (r_clc >= 16)
+               r_clc = 0;
+       }
+       save_flags(flags);
+       cli();
+       pci_write_config_byte(dev, port, s_clc);
+       pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+       restore_flags(flags);
+
+       /*
+        * setup   active  rec
+        * { 70,   165,    365 },   PIO Mode 0
+        * { 50,   125,    208 },   PIO Mode 1
+        * { 30,   100,    110 },   PIO Mode 2
+        * { 30,   80,     70  },   PIO Mode 3 with IORDY
+        * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
+        * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
+        */
+
+}
+
 __initfunc(unsigned int pci_init_ali15x3 (struct pci_dev *dev, const char *name))
 {
        byte confreg0 = 0, confreg1 =0, progif = 0;
@@ -146,19 +197,22 @@ int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 __initfunc(void ide_init_ali15x3 (ide_hwif_t *hwif))
 {
        struct pci_dev *dev;
-       byte ideic, inmir;
+       byte ideic, inmir, iderev;
        byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
                                      1, 11, 0, 12, 0, 14, 0, 15 };
+
+       pci_read_config_byte(hwif->pci_dev, PCI_REVISION_ID, &iderev);
+
        hwif->irq = hwif->channel ? 15 : 14;
        for (dev = pci_devices; dev; dev=dev->next) /* look for ISA bridge */
                if (dev->vendor==PCI_VENDOR_ID_AL &&
-                  dev->device==PCI_DEVICE_ID_AL_M1533)
+                   dev->device==PCI_DEVICE_ID_AL_M1533)
                        break;
        if (dev) {                      
                pci_read_config_byte(dev, 0x58, &ideic);
                ideic = ideic & 0x03;
                if ((hwif->channel && ideic == 0x03) ||
-                  (!hwif->channel && !ideic)) {
+                   (!hwif->channel && !ideic)) {
                        pci_read_config_byte(dev, 0x44, &inmir);
                        inmir = inmir & 0x0f;
                        hwif->irq = irq_routing_table[inmir];
@@ -174,8 +228,15 @@ __initfunc(void ide_init_ali15x3 (ide_hwif_t *hwif))
        ali_display_info = &ali_get_info;
 #endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-       if (hwif->dma_base)
+       hwif->tuneproc = &ali15x3_tune_drive;
+       if ((hwif->dma_base) && (iderev >= 0xC1)) {
+               /* M1543C or newer for DMAing */
                hwif->dmaproc = &ali15x3_dmaproc;
+       } else {
+               hwif->autodma = 0;
+               hwif->drives[0].autotune = 1;
+               hwif->drives[1].autotune = 1;
+       }
        return;
 }
 
index 63b4bbc091d69044569e64ace428d31c648710b5..4775093fb20d7663d397b25678839000fa57d959 100644 (file)
@@ -94,6 +94,9 @@ static __inline__ int wait_for_ready(ide_drive_t *drive)
 
 static void cmd646_do_setfeature(ide_drive_t *drive, byte command)
 {
+#if 0
+       (void) ide_config_drive_speed(drive, command);
+#else
        unsigned long flags;
        byte old_select;
 
@@ -116,6 +119,7 @@ static void cmd646_do_setfeature(ide_drive_t *drive, byte command)
 out:
        OUT_BYTE(old_select, IDE_SELECT_REG);
        restore_flags(flags);
+#endif
 }
 
 static void cmd646_dma2_enable(ide_drive_t *drive, unsigned long dma_base)
diff --git a/drivers/block/hpt343.c b/drivers/block/hpt343.c
deleted file mode 100644 (file)
index f759cbf..0000000
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * linux/drivers/block/hpt343.c                Version 0.23    May 12, 1999
- *
- * Copyright (C) 1998-99       Andre Hedrick
- *                                     (hedrick@astro.dyer.vanderbilt.edu)
- *
- * 00:12.0 Unknown mass storage controller:
- * Triones Technologies, Inc.
- * Unknown device 0003 (rev 01)
- *
- * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
- * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
- * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
- * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
- * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
- * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
- *
- * drive_number
- *     = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- *     = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)      ((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define HPT343_DEBUG_DRIVE_INFO                0
-#define HPT343_DISABLE_ALL_DMAING      0
-#define HPT343_DMA_DISK_ONLY           0
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static void hpt343_clear_chipset (ide_drive_t *drive)
-{
-       int drive_number        = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
-       unsigned int reg1       = 0, tmp1 = 0;
-       unsigned int reg2       = 0, tmp2 = 0;
-
-       pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-       pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-       tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
-       tmp2 = ((0x00 << drive_number) | reg2);
-       pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-       pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-}
-
-static int hpt343_tune_chipset (ide_drive_t *drive, byte speed)
-{
-       int                     err;
-       byte                    hi_speed, lo_speed;
-       int drive_number        = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
-       unsigned int reg1       = 0, tmp1 = 0;
-       unsigned int reg2       = 0, tmp2 = 0;
-
-       SPLIT_BYTE(speed, hi_speed, lo_speed);
-
-       if (hi_speed & 7) {
-               hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
-       } else {
-               lo_speed <<= 5;
-               lo_speed >>= 5;
-       }
-
-       pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-       pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-       tmp1 = ((lo_speed << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
-       tmp2 = ((hi_speed << drive_number) | reg2);
-       err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
-       pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-       pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-
-#if HPT343_DEBUG_DRIVE_INFO
-       printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
-               " (0x%02x 0x%02x) 0x%04x\n",
-               drive->name, ide_xfer_verbose(speed),
-               drive_number, reg1, tmp1, reg2, tmp2,
-               hi_speed, lo_speed, err);
-#endif /* HPT343_DEBUG_DRIVE_INFO */
-
-       return(err);
-}
-
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initally for designed for
- * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-       struct hd_driveid *id   = drive->id;
-       byte speed              = 0x00;
-
-#if HPT343_DISABLE_ALL_DMAING
-       return ((int) ide_dma_off);
-#elif HPT343_DMA_DISK_ONLY
-       if (drive->media != ide_disk)
-               return ((int) ide_dma_off_quietly);
-#endif /* HPT343_DISABLE_ALL_DMAING */
-
-       if (id->dma_ultra & 0x0004) {
-               if (!((id->dma_ultra >> 8) & 4)) {
-                       drive->id->dma_ultra &= ~0x0F00;
-                       drive->id->dma_ultra |= 0x0404;
-                       drive->id->dma_mword &= ~0x0F00;
-                       drive->id->dma_1word &= ~0x0F00;
-               }
-               speed = XFER_UDMA_2;
-       } else if (id->dma_ultra & 0x0002) {
-               if (!((id->dma_ultra >> 8) & 2)) {
-                       drive->id->dma_ultra &= ~0x0F00;
-                       drive->id->dma_ultra |= 0x0202;
-                       drive->id->dma_mword &= ~0x0F00;
-                       drive->id->dma_1word &= ~0x0F00;
-               }
-               speed = XFER_UDMA_1;
-       } else if (id->dma_ultra & 0x0001) {
-               if (!((id->dma_ultra >> 8) & 1)) {
-                       drive->id->dma_ultra &= ~0x0F00;
-                       drive->id->dma_ultra |= 0x0101;
-                       drive->id->dma_mword &= ~0x0F00;
-                       drive->id->dma_1word &= ~0x0F00;
-               }
-               speed = XFER_UDMA_0;
-       } else if (id->dma_mword & 0x0004) {
-               if (!((id->dma_mword >> 8) & 4)) {
-                       drive->id->dma_mword &= ~0x0F00;
-                       drive->id->dma_mword |= 0x0404;
-                       drive->id->dma_1word &= ~0x0F00;
-               }
-               speed = XFER_MW_DMA_2;
-       } else if (id->dma_mword & 0x0002) {
-               if (!((id->dma_mword >> 8) & 2)) {
-                       drive->id->dma_mword &= ~0x0F00;
-                       drive->id->dma_mword |= 0x0202;
-                       drive->id->dma_1word &= ~0x0F00;
-               }
-               speed = XFER_MW_DMA_1;
-       } else if (id->dma_mword & 0x0001) {
-               if (!((id->dma_mword >> 8) & 1)) {
-                       drive->id->dma_mword &= ~0x0F00;
-                       drive->id->dma_mword |= 0x0101;
-                       drive->id->dma_1word &= ~0x0F00;
-               }
-               speed = XFER_MW_DMA_0;
-       } else if (id->dma_1word & 0x0004) {
-               if (!((id->dma_1word >> 8) & 4)) {
-                       drive->id->dma_1word &= ~0x0F00;
-                       drive->id->dma_1word |= 0x0404;
-                       drive->id->dma_mword &= ~0x0F00;
-               }
-               speed = XFER_SW_DMA_2;
-       } else if (id->dma_1word & 0x0002) {
-               if (!((id->dma_1word >> 8) & 2)) {
-                       drive->id->dma_1word &= ~0x0F00;
-                       drive->id->dma_1word |= 0x0202;
-                       drive->id->dma_mword &= ~0x0F00;
-               }
-               speed = XFER_SW_DMA_1;
-       } else if (id->dma_1word & 0x0001) {
-               if (!((id->dma_1word >> 8) & 1)) {
-                       drive->id->dma_1word &= ~0x0F00;
-                       drive->id->dma_1word |= 0x0101;
-                       drive->id->dma_mword &= ~0x0F00;
-               }
-               speed = XFER_SW_DMA_0;
-        } else {
-               return ((int) ide_dma_off_quietly);
-       }
-
-       (void) hpt343_tune_chipset(drive, speed);
-
-       return ((int)   ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
-                       ((id->dma_1word >> 8) & 7) ? ide_dma_on :
-                                                    ide_dma_off_quietly);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-       unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
-       unsigned short xfer_pio = drive->id->eide_pio_modes;
-
-       byte                    timing, speed, pio;
-
-       pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-       if (xfer_pio> 4)
-               xfer_pio = 0;
-
-       if (drive->id->eide_pio_iordy > 0) {
-               for (xfer_pio = 5;
-                       xfer_pio>0 &&
-                       drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
-                       xfer_pio--);
-       } else {
-               xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-                          (drive->id->eide_pio_modes & 2) ? 0x04 :
-                          (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
-       }
-
-       timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-       switch(timing) {
-               case 4: speed = XFER_PIO_4;break;
-               case 3: speed = XFER_PIO_3;break;
-               case 2: speed = XFER_PIO_2;break;
-               case 1: speed = XFER_PIO_1;break;
-               default:
-                       speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-                       break;
-       }
-
-       (void) hpt343_tune_chipset(drive, speed);
-}
-
-#if 0
-static void hpt343_tune_drive (ide_drive_t *drive, byte pio)
-{
-}
-#endif
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-       struct hd_driveid *id = drive->id;
-       ide_dma_action_t dma_func = ide_dma_on;
-
-       if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-               /* Consult the list of known "bad" drives */
-               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-                       dma_func = ide_dma_off;
-                       goto fast_ata_pio;
-               }
-               dma_func = ide_dma_off_quietly;
-               if (id->field_valid & 4) {
-                       if (id->dma_ultra & 0x0007) {
-                               /* Force if Capable UltraDMA */
-                               dma_func = config_chipset_for_dma(drive);
-                               if ((id->field_valid & 2) &&
-                                   (dma_func != ide_dma_on))
-                                       goto try_dma_modes;
-                       }
-               } else if (id->field_valid & 2) {
-try_dma_modes:
-                       if ((id->dma_mword & 0x0007) ||
-                           (id->dma_1word & 0x0007)) {
-                               /* Force if Capable regular DMA modes */
-                               dma_func = config_chipset_for_dma(drive);
-                               if (dma_func != ide_dma_on)
-                                       goto no_dma_set;
-                       }
-               } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-                       if (id->eide_dma_time > 150) {
-                               goto no_dma_set;
-                       }
-                       /* Consult the list of known "good" drives */
-                       dma_func = config_chipset_for_dma(drive);
-                       if (dma_func != ide_dma_on)
-                               goto no_dma_set;
-               } else {
-                       goto fast_ata_pio;
-               }
-       } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-               dma_func = ide_dma_off_quietly;
-no_dma_set:
-
-               config_chipset_for_pio(drive);
-       }
-       return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * hpt343_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- *
- * This is specific to the HPT343 UDMA bios-less chipset
- * and HPT345 UDMA bios chipset (stamped HPT363)
- * by HighPoint|Triones Technologies, Inc.
- */
-
-int hpt343_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-       switch (func) {
-               case ide_dma_check:
-                       hpt343_clear_chipset(drive);
-                       return config_drive_xfer_rate(drive);
-#if 0
-               case ide_dma_off:
-               case ide_dma_off_quietly:
-               case ide_dma_on:
-               case ide_dma_check:
-                       return config_drive_xfer_rate(drive);
-               case ide_dma_read:
-               case ide_dma_write:
-               case ide_dma_begin:
-               case ide_dma_end:
-               case ide_dma_test_irq:
-#endif
-               default:
-                       break;
-       }
-       return ide_dmaproc(func, drive);        /* use standard DMA stuff */
-}
-
-/*
- * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
- */
-#define        HPT343_PCI_INIT_REG             0x80
-
-__initfunc(unsigned int pci_init_hpt343 (struct pci_dev *dev, const char *name))
-{
-       int i;
-       unsigned short cmd;
-       unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
-#if 0
-       unsigned char misc10 = inb(hpt343IoBase + 0x0010);
-       unsigned char misc11 = inb(hpt343IoBase + 0x0011);
-#endif
-
-       pci_write_config_byte(dev, HPT343_PCI_INIT_REG, 0x00);
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
-
-       dev->base_address[0] = (hpt343IoBase + 0x20);
-       dev->base_address[1] = (hpt343IoBase + 0x34);
-       dev->base_address[2] = (hpt343IoBase + 0x28);
-       dev->base_address[3] = (hpt343IoBase + 0x3c);
-
-       for(i=0; i<4; i++)
-               dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
-
-       /*
-        * Since 20-23 can be assigned and are R/W, we correct them.
-        */
-       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->base_address[0]);
-       pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->base_address[1]);
-       pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->base_address[2]);
-       pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->base_address[3]);
-       pci_write_config_word(dev, PCI_COMMAND, cmd);
-
-#if 0
-       outb(misc10|0x78, (hpt343IoBase + 0x0010));
-       outb(misc11, (hpt343IoBase + 0x0011));
-#endif
-
-#ifdef DEBUG
-       printk("%s: 0x%02x 0x%02x\n",
-               (pcicmd & PCI_COMMAND_MEMORY) ? "HPT345" : name,
-               inb(hpt343IoBase + 0x0010),
-               inb(hpt343IoBase + 0x0011));
-#endif
-
-       if (cmd & PCI_COMMAND_MEMORY) {
-               if (dev->rom_address) {
-                       pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
-                       printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address);
-               }
-       } else {
-               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-       }
-       return dev->irq;
-}
-
-__initfunc(void ide_init_hpt343 (ide_hwif_t *hwif))
-{
-       if (hwif->dma_base) {
-               unsigned short pcicmd = 0;
-
-               pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-               hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
-               hwif->dmaproc = &hpt343_dmaproc;
-       }
-}
diff --git a/drivers/block/hpt34x.c b/drivers/block/hpt34x.c
new file mode 100644 (file)
index 0000000..e853ee4
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * linux/drivers/block/hpt343.c                Version 0.23    May 12, 1999
+ *
+ * Copyright (C) 1998-99       Andre Hedrick
+ *                                     (hedrick@astro.dyer.vanderbilt.edu)
+ *
+ * 00:12.0 Unknown mass storage controller:
+ * Triones Technologies, Inc.
+ * Unknown device 0003 (rev 01)
+ *
+ * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
+ * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
+ * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
+ * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
+ *
+ * drive_number
+ *     = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ *     = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)      ((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define HPT343_DEBUG_DRIVE_INFO                0
+#define HPT343_DISABLE_ALL_DMAING      0
+#define HPT343_DMA_DISK_ONLY           0
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+static void hpt34x_clear_chipset (ide_drive_t *drive)
+{
+       int drive_number        = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+       unsigned int reg1       = 0, tmp1 = 0;
+       unsigned int reg2       = 0, tmp2 = 0;
+
+       pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
+       pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
+       tmp1 = ((0x00 << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
+       tmp2 = ((0x00 << drive_number) | reg2);
+       pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
+       pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+}
+
+static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
+{
+       int                     err;
+       byte                    hi_speed, lo_speed;
+       int drive_number        = ((HWIF(drive)->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+       unsigned int reg1       = 0, tmp1 = 0;
+       unsigned int reg2       = 0, tmp2 = 0;
+
+       SPLIT_BYTE(speed, hi_speed, lo_speed);
+
+       if (hi_speed & 7) {
+               hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
+       } else {
+               lo_speed <<= 5;
+               lo_speed >>= 5;
+       }
+
+       pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
+       pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
+       tmp1 = ((lo_speed << (3*drive_number)) | (reg1 & ~(7 << (3*drive_number))));
+       tmp2 = ((hi_speed << drive_number) | reg2);
+       err = ide_config_drive_speed(drive, speed);
+       pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
+       pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+
+#if HPT343_DEBUG_DRIVE_INFO
+       printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+               " (0x%02x 0x%02x) 0x%04x\n",
+               drive->name, ide_xfer_verbose(speed),
+               drive_number, reg1, tmp1, reg2, tmp2,
+               hi_speed, lo_speed, err);
+#endif /* HPT343_DEBUG_DRIVE_INFO */
+
+       return(err);
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+       struct hd_driveid *id   = drive->id;
+       byte speed              = 0x00;
+
+#if HPT343_DISABLE_ALL_DMAING
+       return ((int) ide_dma_off);
+#elif HPT343_DMA_DISK_ONLY
+       if (drive->media != ide_disk)
+               return ((int) ide_dma_off_quietly);
+#endif /* HPT343_DISABLE_ALL_DMAING */
+
+       if (id->dma_ultra & 0x0004) {
+               if (!((id->dma_ultra >> 8) & 4)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0404;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_UDMA_2;
+       } else if (id->dma_ultra & 0x0002) {
+               if (!((id->dma_ultra >> 8) & 2)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0202;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_UDMA_1;
+       } else if (id->dma_ultra & 0x0001) {
+               if (!((id->dma_ultra >> 8) & 1)) {
+                       drive->id->dma_ultra &= ~0x0F00;
+                       drive->id->dma_ultra |= 0x0101;
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_UDMA_0;
+       } else if (id->dma_mword & 0x0004) {
+               if (!((id->dma_mword >> 8) & 4)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0404;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_MW_DMA_2;
+       } else if (id->dma_mword & 0x0002) {
+               if (!((id->dma_mword >> 8) & 2)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0202;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_MW_DMA_1;
+       } else if (id->dma_mword & 0x0001) {
+               if (!((id->dma_mword >> 8) & 1)) {
+                       drive->id->dma_mword &= ~0x0F00;
+                       drive->id->dma_mword |= 0x0101;
+                       drive->id->dma_1word &= ~0x0F00;
+               }
+               speed = XFER_MW_DMA_0;
+       } else if (id->dma_1word & 0x0004) {
+               if (!((id->dma_1word >> 8) & 4)) {
+                       drive->id->dma_1word &= ~0x0F00;
+                       drive->id->dma_1word |= 0x0404;
+                       drive->id->dma_mword &= ~0x0F00;
+               }
+               speed = XFER_SW_DMA_2;
+       } else if (id->dma_1word & 0x0002) {
+               if (!((id->dma_1word >> 8) & 2)) {
+                       drive->id->dma_1word &= ~0x0F00;
+                       drive->id->dma_1word |= 0x0202;
+                       drive->id->dma_mword &= ~0x0F00;
+               }
+               speed = XFER_SW_DMA_1;
+       } else if (id->dma_1word & 0x0001) {
+               if (!((id->dma_1word >> 8) & 1)) {
+                       drive->id->dma_1word &= ~0x0F00;
+                       drive->id->dma_1word |= 0x0101;
+                       drive->id->dma_mword &= ~0x0F00;
+               }
+               speed = XFER_SW_DMA_0;
+        } else {
+               return ((int) ide_dma_off_quietly);
+       }
+
+       (void) hpt34x_tune_chipset(drive, speed);
+
+       return ((int)   ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+                       ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+                                                    ide_dma_off_quietly);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+       unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+       unsigned short xfer_pio = drive->id->eide_pio_modes;
+
+       byte                    timing, speed, pio;
+
+       pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+       if (xfer_pio> 4)
+               xfer_pio = 0;
+
+       if (drive->id->eide_pio_iordy > 0) {
+               for (xfer_pio = 5;
+                       xfer_pio>0 &&
+                       drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+                       xfer_pio--);
+       } else {
+               xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+                          (drive->id->eide_pio_modes & 2) ? 0x04 :
+                          (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+       }
+
+       timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+       switch(timing) {
+               case 4: speed = XFER_PIO_4;break;
+               case 3: speed = XFER_PIO_3;break;
+               case 2: speed = XFER_PIO_2;break;
+               case 1: speed = XFER_PIO_1;break;
+               default:
+                       speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+                       break;
+       }
+       (void) hpt34x_tune_chipset(drive, speed);
+}
+
+static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
+{
+       byte speed;
+
+       hpt34x_clear_chipset(drive);
+       switch(pio) {
+               case 4:         speed = XFER_PIO_4;break;
+               case 3:         speed = XFER_PIO_3;break;
+               case 2:         speed = XFER_PIO_2;break;
+               case 1:         speed = XFER_PIO_1;break;
+               default:        speed = XFER_PIO_0;break;
+       }
+       (void) hpt34x_tune_chipset(drive, speed);
+}
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+       struct hd_driveid *id = drive->id;
+       ide_dma_action_t dma_func = ide_dma_on;
+
+       if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+               /* Consult the list of known "bad" drives */
+               if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+                       dma_func = ide_dma_off;
+                       goto fast_ata_pio;
+               }
+               dma_func = ide_dma_off_quietly;
+               if (id->field_valid & 4) {
+                       if (id->dma_ultra & 0x0007) {
+                               /* Force if Capable UltraDMA */
+                               dma_func = config_chipset_for_dma(drive);
+                               if ((id->field_valid & 2) &&
+                                   (dma_func != ide_dma_on))
+                                       goto try_dma_modes;
+                       }
+               } else if (id->field_valid & 2) {
+try_dma_modes:
+                       if ((id->dma_mword & 0x0007) ||
+                           (id->dma_1word & 0x0007)) {
+                               /* Force if Capable regular DMA modes */
+                               dma_func = config_chipset_for_dma(drive);
+                               if (dma_func != ide_dma_on)
+                                       goto no_dma_set;
+                       }
+               } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+                       if (id->eide_dma_time > 150) {
+                               goto no_dma_set;
+                       }
+                       /* Consult the list of known "good" drives */
+                       dma_func = config_chipset_for_dma(drive);
+                       if (dma_func != ide_dma_on)
+                               goto no_dma_set;
+               } else {
+                       goto fast_ata_pio;
+               }
+       } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+               dma_func = ide_dma_off_quietly;
+no_dma_set:
+
+               config_chipset_for_pio(drive);
+       }
+       return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
+ *
+ * This is specific to the HPT343 UDMA bios-less chipset
+ * and HPT345 UDMA bios chipset (stamped HPT363)
+ * by HighPoint|Triones Technologies, Inc.
+ */
+
+int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+       switch (func) {
+               case ide_dma_check:
+                       hpt34x_clear_chipset(drive);
+                       return config_drive_xfer_rate(drive);
+#if 0
+               case ide_dma_off:
+               case ide_dma_off_quietly:
+               case ide_dma_on:
+               case ide_dma_check:
+                       return config_drive_xfer_rate(drive);
+               case ide_dma_read:
+               case ide_dma_write:
+               case ide_dma_begin:
+               case ide_dma_end:
+               case ide_dma_test_irq:
+#endif
+               default:
+                       break;
+       }
+       return ide_dmaproc(func, drive);        /* use standard DMA stuff */
+}
+
+/*
+ * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
+ */
+#define        HPT34X_PCI_INIT_REG             0x80
+
+__initfunc(unsigned int pci_init_hpt34x (struct pci_dev *dev, const char *name))
+{
+       int i;
+       unsigned short cmd;
+       unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+#if 0
+       unsigned char misc10 = inb(hpt34xIoBase + 0x0010);
+       unsigned char misc11 = inb(hpt34xIoBase + 0x0011);
+#endif
+
+       pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+
+       dev->base_address[0] = (hpt34xIoBase + 0x20);
+       dev->base_address[1] = (hpt34xIoBase + 0x34);
+       dev->base_address[2] = (hpt34xIoBase + 0x28);
+       dev->base_address[3] = (hpt34xIoBase + 0x3c);
+
+       for(i=0; i<4; i++)
+               dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
+
+       /*
+        * Since 20-23 can be assigned and are R/W, we correct them.
+        */
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->base_address[0]);
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->base_address[1]);
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->base_address[2]);
+       pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->base_address[3]);
+       pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+#if 0
+       outb(misc10|0x78, (hpt34xIoBase + 0x0010));
+       outb(misc11, (hpt34xIoBase + 0x0011));
+#endif
+
+#ifdef DEBUG
+       printk("%s: 0x%02x 0x%02x\n",
+               (pcicmd & PCI_COMMAND_MEMORY) ? "HPT345" : name,
+               inb(hpt34xIoBase + 0x0010),
+               inb(hpt34xIoBase + 0x0011));
+#endif
+
+       if (cmd & PCI_COMMAND_MEMORY) {
+               if (dev->rom_address) {
+                       pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+                       printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->rom_address);
+               }
+       } else {
+               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+       }
+       return dev->irq;
+}
+
+__initfunc(void ide_init_hpt34x (ide_hwif_t *hwif))
+{
+       hwif->tuneproc = &hpt34x_tune_drive;
+       if (hwif->dma_base) {
+               unsigned short pcicmd = 0;
+
+               pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
+#ifdef CONFIG_BLK_DEV_HPT34X_DMA
+               hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+#endif /* CONFIG_BLK_DEV_HPT34X_DMA */
+               hwif->dmaproc = &hpt34x_dmaproc;
+       } else {
+               hwif->drives[0].autotune = 1;
+               hwif->drives[1].autotune = 1;
+       }
+}
index 0d29761eec33e8f4dc073fabc3ea095a3b90a164..edffa0cf10144e411d67d7cbe7a8e96e3804d1f1 100644 (file)
@@ -299,6 +299,9 @@ icside_config_drive(ide_drive_t *drive, int mode)
                drive->drive_data = 250;
        }
 
+#if 1
+       err = ide_config_drive_speed(drive, (byte) speed);
+#else
        /*
         * Don't use ide_wait_cmd here - it will
         * attempt to set_geometry and recalibrate,
@@ -313,6 +316,7 @@ icside_config_drive(ide_drive_t *drive, int mode)
 
        err = ide_wait_stat(drive, DRIVE_READY,
                            BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
+#endif
 
        if (err == 0) {
                drive->id->dma_mword &= 0x00ff;
index 9f26ea6bc5b9f26d8aa1a495bf6243f2172694e8..0cda4398cadd80fd2af5f05a52efd2d9d3f98e01 100644 (file)
@@ -91,9 +91,8 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#define IDE_DMA_NEW_LISTINGS           0
+#ifdef IDEDMA_NEW_DRIVE_LISTINGS
 
-#if IDE_DMA_NEW_LISTINGS
 struct drive_list_entry {
        char * id_model;
        char * id_firmware;
@@ -130,7 +129,8 @@ int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
                        return 1;
        return 0;
 }
-#else /* !IDE_DMA_NEW_LISTINGS */
+
+#else /* !IDEDMA_NEW_DRIVE_LISTINGS */
 
 /*
  * good_dma_drives() lists the model names (from "hdparm -i")
@@ -162,7 +162,7 @@ const char *bad_dma_drives[] = {"WDC AC11000H",
                                "WDC AC31600H",
                                NULL};
 
-#endif /* IDE_DMA_NEW_LISTINGS */
+#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
 
 /*
  * Our Physical Region Descriptor (PRD) table should be large enough
@@ -314,8 +314,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
 {
        struct hd_driveid *id = drive->id;
 
-#if IDE_DMA_NEW_LISTINGS
-
+#ifdef IDEDMA_NEW_DRIVE_LISTINGS
        if (good_bad) {
                return in_drive_list(id, drive_whitelist);
        } else {
@@ -324,8 +323,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
                        printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
                return(blacklist);
        }
-#else /* !IDE_DMA_NEW_LISTINGS */
-
+#else /* !IDEDMA_NEW_DRIVE_LISTINGS */
        const char **list;
 
        if (good_bad) {
@@ -346,7 +344,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
                        }
                }
        }
-#endif /* IDE_DMA_NEW_LISTINGS */
+#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
        return 0;
 }
 
@@ -359,12 +357,12 @@ static int config_drive_for_dma (ide_drive_t *drive)
                /* Consult the list of known "bad" drives */
                if (ide_dmaproc(ide_dma_bad_drive, drive))
                        return hwif->dmaproc(ide_dma_off, drive);
-#if 0
+#ifdef CONFIG_IDEDMA_ULTRA_66
                /* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */
                if ((id->field_valid & 4) && (id->word93 & 0x2000))
                        if ((id->dma_ultra & (id->dma_ultra >> 11) & 3))
                                return hwif->dmaproc(ide_dma_on, drive);
-#endif
+#endif /* CONFIG_IDEDMA_ULTRA_66 */
                /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
                if (id->field_valid & 4)        /* UltraDMA */
                        if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
@@ -527,7 +525,7 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c
                }
        }
        if (dma_base) {
-               if (extra) /* PDC20246 & HPT343 */
+               if (extra) /* PDC20246, PDC20262, & HPT343 */
                        request_region(dma_base+16, extra, name);
                dma_base += hwif->channel ? 8 : 0;
                hwif->dma_extra = extra;
@@ -538,13 +536,15 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c
                                 * Lets attempt to use the same Ali tricks
                                 * to fix CMD643.....
                                 */
+#ifdef CONFIG_BLK_DEV_ALI15X3
                        case PCI_DEVICE_ID_AL_M5219:
                        case PCI_DEVICE_ID_AL_M5229:
-                               outb(inb(dma_base+2) & 0x60, dma_base+2);
                                /*
                                 * Ali 15x3 chipsets know as ALI IV and V report
                                 * this as simplex, skip this test for them.
                                 */
+#endif /* CONFIG_BLK_DEV_ALI15X3 */
+                               outb(inb(dma_base+2) & 0x60, dma_base+2);
                                if (inb(dma_base+2) & 0x80) {
                                        printk("%s: simplex device: DMA forced\n", name);
                                }
index 8b4c5fe2c56f0d11974acd6c6769452258e7377d..df3100d377a5d72b1f30d938cc99f352f767797f 100644 (file)
@@ -51,7 +51,7 @@
 #define DEVID_W82C105  ((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
 #define DEVID_UM8886A  ((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
 #define DEVID_UM8886BF ((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
-#define DEVID_HPT343   ((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
+#define DEVID_HPT34X   ((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
 #define DEVID_ALI15X3  ((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
 #define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ,  PCI_DEVICE_ID_CONTAQ_82C693})
 #define DEVID_HINT     ((ide_pci_devid_t){0x3388,                0x8013})
@@ -156,14 +156,14 @@ extern unsigned int pci_init_aec6210(struct pci_dev *, const char *);
 #define PCI_AEC6210    NULL
 #endif
 
-#ifdef CONFIG_BLK_DEV_HPT343
-extern unsigned int pci_init_hpt343(struct pci_dev *, const char *);
-extern void ide_init_hpt343(ide_hwif_t *);
-#define PCI_HPT343     &pci_init_hpt343
-#define        INIT_HPT343     &ide_init_hpt343
+#ifdef CONFIG_BLK_DEV_HPT34X
+extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
+extern void ide_init_hpt34x(ide_hwif_t *);
+#define PCI_HPT34X     &pci_init_hpt34x
+#define        INIT_HPT34X     &ide_init_hpt34x
 #else
-#define PCI_HPT343     NULL
-#define        INIT_HPT343     NULL
+#define PCI_HPT34X     NULL
+#define        INIT_HPT34X     NULL
 #endif
 
 #define INIT_SAMURAI   NULL
@@ -212,7 +212,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
        {DEVID_W82C105, "W82C105",      NULL,           INIT_W82C105,   NULL,           {{0x40,0x01,0x01}, {0x40,0x10,0x10}},   ON_BOARD,       0 },
        {DEVID_UM8886A, "UM8886A",      NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
        {DEVID_UM8886BF,"UM8886BF",     NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
-       {DEVID_HPT343,  "HPT343",       PCI_HPT343,     INIT_HPT343,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   NEVER_BOARD,    16 },
+       {DEVID_HPT34X,  "HPT34X",       PCI_HPT34X,     INIT_HPT34X,    NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   NEVER_BOARD,    16 },
        {DEVID_ALI15X3, "ALI15X3",      PCI_ALI15X3,    INIT_ALI15X3,   NULL,           {{0x09,0x20,0x20}, {0x09,0x10,0x10}},   ON_BOARD,       0 },
        {DEVID_CY82C693,"CY82C693",     NULL,           INIT_CY82C693,  NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
        {DEVID_HINT,    "HINT_IDE",     NULL,           NULL,           NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,       0 },
@@ -231,13 +231,13 @@ __initfunc(static unsigned int ide_special_settings (struct pci_dev *dev, const
                        {
                                int i;
                                unsigned short pcicmd = 0;
-                               unsigned long hpt343IoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
+                               unsigned long hpt34xIoBase = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK;
 
                                pci_write_config_byte(dev, 0x80, 0x00);
-                               dev->base_address[0] = (hpt343IoBase + 0x20);
-                               dev->base_address[1] = (hpt343IoBase + 0x34);
-                               dev->base_address[2] = (hpt343IoBase + 0x28);
-                               dev->base_address[3] = (hpt343IoBase + 0x3c);
+                               dev->base_address[0] = (hpt34xIoBase + 0x20);
+                               dev->base_address[1] = (hpt34xIoBase + 0x34);
+                               dev->base_address[2] = (hpt34xIoBase + 0x28);
+                               dev->base_address[3] = (hpt34xIoBase + 0x3c);
                                for(i=0; i<4; i++)
                                        dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO;
 
@@ -422,7 +422,7 @@ check_if_enabled:
                printk("%s: 100%% native mode on irq %d\n", d->name, pciirq);
 #endif
        }
-       if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343)) {
+       if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) {
                /*
                 * Since there are two cards that report almost identically,
                 * the only discernable difference is the values
@@ -490,9 +490,9 @@ check_if_enabled:
                if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
                    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
                    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
-#ifdef CONFIG_BLK_DEV_HPT343
-                   IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT343) ||
-#endif
+#ifdef CONFIG_BLK_DEV_HPT34X
+                   IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
+#endif /* CONFIG_BLK_DEV_HPT34X */
                    IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
                    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
                        unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
index 17b10593d2875d61f6317a45dd8ccb9920404677..6d324bea84895e4a532fe677ea504378d7aef930 100644 (file)
@@ -2235,6 +2235,27 @@ void ide_delay_50ms (void)
        while (0 < (signed long)(timeout - jiffies));
 }
 
+int ide_config_drive_speed (ide_drive_t *drive, byte speed)
+{
+       int err;
+
+       /*
+        * Don't use ide_wait_cmd here - it will
+        * attempt to set_geometry and recalibrate,
+        * but for some reason these don't work at
+        * this point (lost interrupt).
+        */
+       SELECT_DRIVE(HWIF(drive), drive);
+       OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
+       OUT_BYTE(speed, IDE_NSECTOR_REG);
+       OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+       OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+
+       err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
+
+       return(err);
+}
+
 static int ide_ioctl (struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
@@ -3416,6 +3437,7 @@ EXPORT_SYMBOL(ide_revalidate_disk);
 EXPORT_SYMBOL(ide_cmd);
 EXPORT_SYMBOL(ide_wait_cmd);
 EXPORT_SYMBOL(ide_delay_50ms);
+EXPORT_SYMBOL(ide_config_drive_speed);
 EXPORT_SYMBOL(ide_stall_queue);
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(ide_add_proc_entries);
index f0591397c01b7592f38cbf60759204edf6102d81..08f87655e81a3b8c29d61253d650b8d7a7445aa4 100644 (file)
@@ -90,8 +90,6 @@
 
 #define PDC202XX_DEBUG_DRIVE_INFO              0
 #define PDC202XX_DECODE_REGISTER_INFO          0
-#define PDC202XX_FORCE_BURST_BIT               0
-#define PDC202XX_FORCE_MASTER_MODE             0
 
 extern char *ide_xfer_verbose (byte xfer_rate);
 
@@ -225,16 +223,12 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
        switch(drive_number) {
                case 0: drive_pci = 0x60;
                        pci_read_config_dword(dev, drive_pci, &drive_conf);
-                       if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-                               goto chipset_is_set;
                        pci_read_config_byte(dev, (drive_pci), &test1);
                        if (!(test1 & SYNC_ERRDY_EN))
                                pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
                        break;
                case 1: drive_pci = 0x64;
                        pci_read_config_dword(dev, drive_pci, &drive_conf);
-                       if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-                               goto chipset_is_set;
                        pci_read_config_byte(dev, 0x60, &test1);
                        pci_read_config_byte(dev, (drive_pci), &test2);
                        if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
@@ -242,16 +236,12 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
                        break;
                case 2: drive_pci = 0x68;
                        pci_read_config_dword(dev, drive_pci, &drive_conf);
-                       if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-                               goto chipset_is_set;
                        pci_read_config_byte(dev, (drive_pci), &test1);
                        if (!(test1 & SYNC_ERRDY_EN))
                                pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
                        break;
                case 3: drive_pci = 0x6c;
                        pci_read_config_dword(dev, drive_pci, &drive_conf);
-                       if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-                               goto chipset_is_set;
                        pci_read_config_byte(dev, 0x68, &test1);
                        pci_read_config_byte(dev, (drive_pci), &test2);
                        if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
@@ -415,7 +405,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
                return ide_dma_off_quietly;
        }
 
-       err = ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
+       err = ide_config_drive_speed(drive, speed);
 
 #if PDC202XX_DECODE_REGISTER_INFO
        pci_read_config_byte(dev, (drive_pci), &AP);
@@ -436,8 +426,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
        printk("0x%08x\n", drive_conf);
 #endif /* PDC202XX_DEBUG_DRIVE_INFO */
 
-chipset_is_set:
-
        return ((int)   ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
                        ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
                        ((id->dma_mword >> 8) & 7) ? ide_dma_on : 
@@ -533,7 +521,7 @@ __initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name
                (primary_mode & 1) ? "MASTER" : "PCI",
                (secondary_mode & 1) ? "MASTER" : "PCI" );
 
-#if PDC202XX_FORCE_BURST_BIT
+#ifdef PDC202XX_FORCE_BURST_BIT
        if (!(udma_speed_flag & 1)) {
                printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
                outb(udma_speed_flag|1, high_16 + 0x001f);
@@ -541,7 +529,7 @@ __initfunc(unsigned int pci_init_pdc202xx (struct pci_dev *dev, const char *name
        }
 #endif /* PDC202XX_FORCE_BURST_BIT */
 
-#if PDC202XX_FORCE_MASTER_MODE
+#ifdef PDC202XX_FORCE_MASTER_MODE
        if (!(primary_mode & 1)) {
                printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
                        name, primary_mode, (primary_mode|1));
index e89e5dfb689f779fdebdf8f6515326f1e4bec94c..79a0e873f6daef27a2bd6b31b6e228c06f2c6b42 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/piix.c  Version 0.23    May 29, 1999
+ * linux/drivers/block/piix.c  Version 0.24    June 28, 1999
  *
  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
  *  Copyright (C) 1998-1999 Andre Hedrick, Author and Maintainer
  * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
  * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
  *
+ * #if 0
+ * int err;
+ * err = ide_config_drive_speed(drive, speed);
+ * (void) ide_config_drive_speed(drive, speed);
+ * #else
+ * #endif
  */
 
 #include <linux/types.h>
@@ -62,6 +68,7 @@
 
 extern char *ide_xfer_verbose (byte xfer_rate);
 
+#ifdef CONFIG_BLK_DEV_PIIX_TUNING
 /*
  *
  */
@@ -91,6 +98,7 @@ static byte piix_dma_2_pio (byte xfer_rate) {
                        return 0;
        }
 }
+#endif /* CONFIG_BLK_DEV_PIIX_TUNING */
 
 /*
  *  Based on settings done by AMI BIOS
@@ -111,11 +119,7 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio)
                                    { 2, 1 },
                                    { 2, 3 }, };
 
-#if 1
        pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-#else
-       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-#endif
        pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
        if (is_slave) {
                master_data = master_data | 0x4000;
@@ -142,6 +146,8 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio)
        restore_flags(flags);
 }
 
+#ifdef CONFIG_BLK_DEV_PIIX_TUNING
+
 static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra)
 {
        struct hd_driveid *id = drive->id;
@@ -246,17 +252,13 @@ static int piix_config_drive_for_dma(ide_drive_t *drive, int ultra)
                }
                speed = XFER_SW_DMA_2;
         } else {
-#if 0
-               speed = XFER_PIO_0;
-#else
                speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-#endif
        }
 
        restore_flags(flags);
        piix_tune_drive(drive, piix_dma_2_pio(speed));
 
-       (void) ide_wait_cmd(drive, WIN_SETFEATURES, speed, SETFEATURES_XFER, 0, NULL);
+       (void) ide_config_drive_speed(drive, speed);
 
 #if PIIX_DEBUG_DRIVE_INFO
        printk("%s: %s drive%d ",
@@ -284,11 +286,19 @@ static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
        /* Other cases are done by generic IDE-DMA code. */
        return ide_dmaproc(func, drive);
 }
+#endif /* CONFIG_BLK_DEV_PIIX_TUNING */
 
 void ide_init_piix (ide_hwif_t *hwif)
 {
        hwif->tuneproc = &piix_tune_drive;
+#ifdef CONFIG_BLK_DEV_PIIX_TUNING
        if (hwif->dma_base) {
                hwif->dmaproc = &piix_dmaproc;
+       } else
+#endif /* CONFIG_BLK_DEV_PIIX_TUNING */
+       {
+               hwif->drives[0].autotune = 1;
+               hwif->drives[1].autotune = 1;
        }
+
 }
index 6c9f0a6510a68e1a6b54071604e3ed0db2d3f7db..8bc1b4feb484069801eccd649aa41f0ac1f5a198 100644 (file)
@@ -52,7 +52,7 @@ fi
 if [ "$CONFIG_PARPORT" != "n" ]; then
   dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
   if [ "$CONFIG_PRINTER" != "n" ]; then
-    bool '  Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+    bool '  Support for console on line printer' CONFIG_LP_CONSOLE
   fi
 fi
 
index 5f9341eaca55050e7be42ca9d47707e0a272036e..41586b58f1321e8cb3d42e2d16d5a3cfa98a633c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *     Video4Linux Colour QuickCam driver
- *     Copyright 1997-1998 Philip Blundell <philb@gnu.org>
+ *     Copyright 1997-1999 Philip Blundell <philb@gnu.org>
  *
  */
 
@@ -294,7 +294,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
        if (is_bi_dir)
        {
                /* Turn the port around */
-               parport_frob_control(q->pport, 0x20, 0x20);
+               parport_data_reverse(q->pport);
                mdelay(3);
                qcam_set_ack(q, 0);
                if (qcam_await_ready1(q, 1)) {
@@ -336,7 +336,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
        {
                printk("qcam: short read.\n");
                if (is_bi_dir)
-                       parport_frob_control(q->pport, 0x20, 0);
+                       parport_data_forward(q->pport);
                qc_setup(q);
                return len;
        }
@@ -355,11 +355,11 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
                if (qcam_await_ready1(q, 1))
                {
                        printk("qcam: no ack after EOF\n");
-                       parport_frob_control(q->pport, 0x20, 0);
+                       parport_data_forward(q->pport);
                        qc_setup(q);
                        return len;
                }
-               parport_frob_control(q->pport, 0x20, 0);
+               parport_data_forward(q->pport);
                mdelay(3);
                qcam_set_ack(q, 1);
                if (qcam_await_ready1(q, 0))
@@ -646,7 +646,7 @@ static struct qcam_device *qcam_init(struct parport *port)
        q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
                                          NULL, 0, NULL);
 
-       q->bidirectional = (q->pport->modes & PARPORT_MODE_PCPS2)?1:0;
+       q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE)?1:0;
 
        if (q->pdev == NULL) 
        {
@@ -678,10 +678,7 @@ int init_cqcam(struct parport *port)
        struct qcam_device *qcam;
 
        if (num_cams == MAX_CAMS)
-       {
-               printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS);
                return -ENOSPC;
-       }
 
        qcam = qcam_init(port);
        if (qcam==NULL)
@@ -725,19 +722,40 @@ void close_cqcam(struct qcam_device *qcam)
        kfree(qcam);
 }
 
-#define BANNER "Connectix Colour Quickcam driver v0.02\n"
+#define BANNER "Connectix Colour Quickcam driver v0.03"
 
-#ifdef MODULE
-int init_module(void)
+static void cq_attach(struct parport *port)
 {
-       struct parport *port;
+       init_cqcam(port);
+}
 
-       printk(BANNER);
+static void cq_detach(struct parport *port)
+{
+       /* Write this some day. */
+}
 
-       for (port = parport_enumerate(); port; port=port->next)
-               init_cqcam(port);
+static struct parport_driver cqcam_driver = {
+       "cqcam",
+       cq_attach,
+       cq_detach,
+       NULL
+};
 
-       return (num_cams)?0:-ENODEV;
+static void cqcam_init(void)
+{
+       printk(BANNER "\n");
+       parport_register_driver(&cqcam_driver);
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
+MODULE_DESCRIPTION(BANNER);
+
+int init_module(void)
+{
+       cqcam_init();
+       return 0;
 }
 
 void cleanup_module(void)
@@ -749,12 +767,7 @@ void cleanup_module(void)
 #else
 __initfunc(int init_colour_qcams(struct video_init *unused))
 {
-       struct parport *port;
-
-       printk(BANNER);
-
-       for (port = parport_enumerate(); port; port=port->next)
-               init_cqcam(port);
+       cqcam_init();
        return 0;
 }
 #endif
index a5e8ff891dfac6bacb2403faba02d149f65a8957..2d84f18c32af7cf51625f2e9110da6543628ed23 100644 (file)
@@ -2640,7 +2640,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
            printk("Not clean (jiff=%lu)...", jiffies);
 #endif
            current->state = TASK_INTERRUPTIBLE;
-           current->counter = 0;       /* make us low-priority */
            schedule_timeout(char_time);
            if (signal_pending(current))
                break;
@@ -2653,7 +2652,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
     }
     /* Run one more char cycle */
     current->state = TASK_INTERRUPTIBLE;
-    current->counter = 0;      /* make us low-priority */
     schedule_timeout(char_time * 5);
     current->state = TASK_RUNNING;
 #ifdef CY_DEBUG_WAIT_UNTIL_SENT
index 53d67f19ea42b393e5e1949d0b9af6f8127ac62b..e4d98cc0c00e6bc2e5c3ccb2dc9bf7df37951c67 100644 (file)
@@ -2180,7 +2180,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
        while ((serial_in(info, UART_ESI_STAT1) != 0x03) ||
                (serial_in(info, UART_ESI_STAT2) != 0xff)) {
                current->state = TASK_INTERRUPTIBLE;
-               current->counter = 0;
                schedule_timeout(char_time);
 
                if (signal_pending(current))
index cafe38f378d06c055802d91e4ac6df9ab7c66f04..29b5e16c9550a9a464b4a42ae55f38f63c9d816f 100644 (file)
@@ -36,9 +36,7 @@ struct parport_i2c_bus
 
 static struct parport_i2c_bus *bus_list;
 
-#ifdef __SMP__
 static spinlock_t bus_list_lock = SPIN_LOCK_UNLOCKED;
-#endif
 
 /* software I2C functions */
 
index 82a5c6a0fa23b72e59973afeaf5ce847a95f56fd..b459b91f5da4afea05652bae067788ecf463a37b 100644 (file)
@@ -337,7 +337,7 @@ static struct js_port __init *js_db9_probe(int *config, struct js_port *port)
                        return port;
                }
 
-               if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2))) {
+               if (!(pp->modes & PARPORT_MODE_TRISTATE)) {
                        printk(KERN_ERR "js-db9: specified parport is not bidirectional\n");
                        return port;
                }
index 4b005b96daf630f199df78ef0964c6fea05655ea..7aa14a88614315adcd01ac0474410114a7866877 100644 (file)
@@ -27,6 +27,9 @@
  * Obsoleted the CAREFUL flag since a printer that doesn' t work with
  * CAREFUL will block a bit after in lp_check_status().
  *                             Andrea Arcangeli, 15 Oct 1998
+ * Obsoleted and removed all the lowlevel stuff implemented in the last
+ * month to use the IEEE1284 functions (that handle the _new_ compatibilty
+ * mode fine).
  */
 
 /* This driver should, in theory, work with any parallel port that has an
  *     # insmod lp.o reset=1
  */
 
-/*
- * LP OPTIMIZATIONS
- *
- * - TRUST_IRQ flag
- * 
- * Epson Stylus Color, HP and many other new printers want the TRUST_IRQ flag
- * set when printing with interrupts. This is a long story. Such printers
- * use a broken handshake (see the timing graph below) when printing with
- * interrupts. The lp driver as default is just able to handle such bogus
- * handshake, but setting such flag cause lp to go faster and probably do
- * what such printers want (even if not documented).
- *
- * NOTE that setting the TRUST_IRQ flag in some printer can cause the irq
- * printing to fail completly. You must try, to know if your printer
- * will handle it. I suggest a graphics printing to force a major flow of
- * characters to the printer for do the test. NOTE also that the TRUST_IRQ
- * flag _should_ be fine everywhere but there is a lot of buggy hardware out
- * there, so I am forced to implement it as a not-default thing.
- * WARNING: before to do the test, be sure to have not played with the
- * `-w' parameter of tunelp!
- *
- * Note also that lp automagically warn you (with a KERN_WARNING) if it
- * detects that you could _try_ to set the TRUST_IRQ flag to speed up the
- * printing and decrease the CPU load.
- *
- * To set the TRUST_IRQ flag you can use this command:
- *
- * tunelp /dev/lp? -T on
- *
- * If you have an old tunelp executable you can (hack and) use this simple
- * C lazy proggy to set the flag in the lp driver:
-
--------------------------- cut here -------------------------------------
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#define        LPTRUSTIRQ  0x060f
-
-int main(int argc, char **argv)
-{
-       int fd = open("/dev/lp0", O_RDONLY);
-       ioctl(fd, LPTRUSTIRQ, argc - 1);
-       if (argc - 1)
-               printf("trusting the irq\n");
-       else
-               printf("untrusting the irq\n");
-       return 0;
-}
--------------------------- cut here -------------------------------------
-
- * - LP_WAIT time
- *
- * You can use this setting if your printer is fast enough and/or your
- * machine is slow enough ;-).
- *
- * tunelp /dev/lp? -w 0
- *
- * - LP_CHAR tries
- *
- * If you print with irqs probably you can decrease the CPU load a lot using
- * this setting. This is not the default because the printing is reported to
- * be jerky somewhere...
- *
- * tunelp /dev/lp? -c 1
- *
- *                                     11 Nov 1998, Andrea Arcangeli
- */
-
 /* COMPATIBILITY WITH OLD KERNELS
  *
  * Under Linux 2.0 and previous versions, lp devices were bound to ports at
@@ -162,6 +97,15 @@ int main(int argc, char **argv)
  * this case fine too.
  *
  *                                     15 Oct 1998, Andrea Arcangeli
+ *
+ * The so called `buggy' handshake is really the well documented
+ * compatibility mode IEEE1284 handshake. They changed the well known
+ * Centronics handshake acking in the middle of busy expecting to not
+ * break drivers or legacy application, while they broken linux lp
+ * until I fixed it reverse engineering the protocol by hand some
+ * month ago...
+ *
+ *                                     14 Dec 1998, Andrea Arcangeli
  */
 
 #include <linux/module.h>
@@ -175,6 +119,8 @@ int main(int argc, char **argv)
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/console.h>
 
 #include <linux/parport.h>
 #undef LP_STATS
@@ -189,6 +135,8 @@ int main(int argc, char **argv)
 
 struct lp_struct lp_table[LP_NO];
 
+static unsigned int lp_count = 0;
+
 /* Test if printer is ready */
 #define        LP_READY(status)        ((status) & LP_PBUSY)
 /* Test if the printer is not acking the strobe */
@@ -197,7 +145,9 @@ struct lp_struct lp_table[LP_NO];
 #define LP_NO_ERROR(status)    ((status) & LP_PERRORP)
 
 #undef LP_DEBUG
-#undef LP_READ_DEBUG
+
+/* If you want to see if you can get lp_poll working, define this. */
+#undef SUPPORT_POLL
 
 /* --- parport support ----------------------------------------- */
 
@@ -205,15 +155,62 @@ static int lp_preempt(void *handle)
 {
        struct lp_struct *lps = (struct lp_struct *)handle;
 
-       if (waitqueue_active (&lps->wait_q))
-               wake_up_interruptible(&lps->wait_q);
+       if (!(lps->flags & LP_PORT_BUSY)) {
+              /* Let the port go. */
+              clear_bit (LP_HAVE_PORT_BIT, &lps->flags);
+              return 0;
+       }
+
+       if (!(lps->flags & LP_PORT_BUSY)) {
+              /* Let the port go. */
+              clear_bit (LP_HAVE_PORT_BIT, &lps->flags);
+              return 0;
+       }
 
        /* Don't actually release the port now */
        return 1;
 }
 
-#define lp_parport_release(x)  do { parport_release(lp_table[(x)].dev); } while (0);
-#define lp_parport_claim(x)    do { parport_claim_or_block(lp_table[(x)].dev); } while (0);
+static void lp_check_data (struct lp_struct *lp)
+{
+#if !defined(CONFIG_PARPORT_1284) || !defined (SUPPORT_POLL)
+       return;
+#else
+       struct pardevice *dev = lp->dev;
+       if (!(lp->flags & LP_NO_REVERSE)) {
+               int err = parport_negotiate (dev->port, IEEE1284_MODE_NIBBLE);
+               if (err)
+                       lp->flags |= LP_NO_REVERSE;
+               else {
+                       unsigned char s = parport_read_status (dev->port);
+                       if (s & PARPORT_STATUS_ERROR)
+                               lp->flags &= ~LP_DATA_AVAIL;
+                       else {
+                               lp->flags |= LP_DATA_AVAIL;
+                               if (waitqueue_active (&lp->dataq))
+                                       wake_up_interruptible (&lp->dataq);
+                       }
+               }
+       }
+#endif /* IEEE 1284 support */
+}
+
+static void lp_parport_release (int minor)
+{
+       lp_check_data (&lp_table[minor]);
+       if (test_and_clear_bit (LP_HAVE_PORT_BIT, &lp_table[minor].flags))
+               parport_release (lp_table[minor].dev);
+
+       lp_table[minor].flags &= ~LP_PORT_BUSY;
+}
+
+static void lp_parport_claim (int minor)
+{
+       if (!test_and_set_bit (LP_HAVE_PORT_BIT, &lp_table[minor].flags))
+               parport_claim_or_block (lp_table[minor].dev);
+
+       lp_table[minor].flags |= LP_PORT_BUSY;
+}
 
 /* --- low-level port access ----------------------------------- */
 
@@ -222,29 +219,6 @@ static int lp_preempt(void *handle)
 #define w_ctr(x,y)     do { parport_write_control(lp_table[(x)].dev->port, (y)); } while (0)
 #define w_dtr(x,y)     do { parport_write_data(lp_table[(x)].dev->port, (y)); } while (0)
 
-static __inline__ void lp_yield (int minor)
-{
-       if (!parport_yield_blocking (lp_table[minor].dev))
-       {
-               if (current->need_resched)
-                       schedule ();
-       } else
-               lp_table[minor].irq_missed = 1;
-}
-
-static __inline__ void lp_schedule(int minor, long timeout)
-{
-       struct pardevice *dev = lp_table[minor].dev;
-       register unsigned long int timeslip = (jiffies - dev->time);
-       if ((timeslip > dev->timeslice) && (dev->port->waithead != NULL)) {
-               lp_parport_release(minor);
-               lp_table[minor].irq_missed = 1;
-               schedule_timeout(timeout);
-               lp_parport_claim(minor);
-       } else
-               schedule_timeout(timeout);
-}
-
 static int lp_reset(int minor)
 {
        int retval;
@@ -257,161 +231,51 @@ static int lp_reset(int minor)
        return retval;
 }
 
-#define        lp_wait(minor)  udelay(LP_WAIT(minor))
-
-static inline int lp_char(char lpchar, int minor)
+static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-       unsigned long count = 0;
-#ifdef LP_STATS
-       struct lp_stats *stats;
-#endif
-
-       if (signal_pending(current))
-               return 0;
-
-       for (;;)
-       {
-               unsigned char status;
-               int irq_ok = 0;
-
-               /*
-                * Give a chance to other pardevice to run in the meantime.
-                */
-               lp_yield(minor);
-
-               status = r_str(minor);
-               if (LP_NO_ERROR(status))
-               {
-                       if (LP_READY(status))
-                               break;
-
-                       /*
-                        * This is a crude hack that should be well known
-                        * at least by Epson device driver developers. -arca
-                        */
-                       irq_ok = (!LP_POLLED(minor) &&
-                                 LP_NO_ACKING(status) &&
-                                 lp_table[minor].irq_detected);
-                       if ((LP_F(minor) & LP_TRUST_IRQ) && irq_ok)
-                               break;
-               }
-               /*
-                * NOTE: if you run with irqs you _must_ use
-                * `tunelp /dev/lp? -c 1' to be rasonable efficient!
-                */
-               if (++count == LP_CHAR(minor))
-               {
-                       if (irq_ok)
-                       {
-                               static int first_time = 1;
-                               /*
-                                * The printer is using a buggy handshake, so
-                                * revert to polling to not overload the
-                                * machine and warn the user that its printer
-                                * could get optimized trusting the irq. -arca
-                                */
-                               lp_table[minor].irq_missed = 1;
-                               if (first_time)
-                               {
-                                       first_time = 0;
-                                       printk(KERN_WARNING "lp%d: the "
-                                              "printing could be optimized "
-                                              "using the TRUST_IRQ flag, "
-                                              "see the top of "
-                                              "linux/drivers/char/lp.c\n",
-                                              minor);
-                               }
-                       }
-                       return 0;
-               }
-       }
-
-       w_dtr(minor, lpchar);
-
-#ifdef LP_STATS
-       stats = &LP_STAT(minor);
-       stats->chars++;
-#endif
-
-       /* must wait before taking strobe high, and after taking strobe
-          low, according spec.  Some printers need it, others don't. */
-       lp_wait(minor);
+       struct lp_struct *lp_dev = (struct lp_struct *) dev_id;
+       if (!(lp_dev->flags & LP_PORT_BUSY))
+               /* We must have the port since we got an interrupt. */
+               lp_check_data (lp_dev);
+       if (waitqueue_active (&lp_dev->waitq))
+               wake_up_interruptible (&lp_dev->waitq);
+}
 
-       /* control port takes strobe high */
-       if (LP_POLLED(minor))
-       {
-               w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
-               lp_wait(minor);
-               w_ctr(minor, LP_PSELECP | LP_PINITP);
-       } else {
-               /*
-                * Epson Stylus Color generate the IRQ on the rising edge of
-                * strobe so clean the irq's information before playing with
-                * the strobe. -arca
-                */
-               lp_table[minor].irq_detected = 0;
-               lp_table[minor].irq_missed = 0;
-               /*
-                * Be sure that the CPU doesn' t reorder instructions. -arca
-                */
-               mb();
-               w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE | LP_PINTEN);
-               lp_wait(minor);
-               w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
-       }
+static void lp_wakeup (void *handle)
+{
+       struct lp_struct *lp_dev = handle;
 
-       /*
-        * Give to the printer a chance to put BUSY low. Really we could
-        * remove this because we could _guess_ that we are slower to reach
-        * again lp_char() than the printer to put BUSY low, but I' d like
-        * to remove this variable from the function I go solve
-        * when I read bug reports ;-). -arca
-        */
-       lp_wait(minor);
+       if (lp_dev->flags & LP_PORT_BUSY)
+               return;
 
-#ifdef LP_STATS
-       /* update waittime statistics */
-       if (count > stats->maxwait) {
-#ifdef LP_DEBUG
-               printk(KERN_DEBUG "lp%d success after %d counts.\n",
-                      minor, count);
-#endif
-               stats->maxwait = count;
+       /* Grab the port if it can help (i.e. reverse mode is possible). */
+       if (!(lp_dev->flags & LP_NO_REVERSE)) {
+               parport_claim (lp_dev->dev);
+               set_bit (LP_HAVE_PORT_BIT, &lp_dev->flags);
+               lp_check_data (lp_dev);
+               if (waitqueue_active (&lp_dev->waitq))
+                       wake_up_interruptible (&lp_dev->waitq);
        }
-       count *= 256;
-       wait = (count > stats->meanwait) ? count - stats->meanwait :
-           stats->meanwait - count;
-       stats->meanwait = (255 * stats->meanwait + count + 128) / 256;
-       stats->mdev = ((127 * stats->mdev) + wait + 64) / 128;
-#endif
-
-       return 1;
 }
 
-static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void lp_error (int minor)
 {
-       struct lp_struct *lp_dev = (struct lp_struct *) dev_id;
+       int polling;
 
-       if (waitqueue_active (&lp_dev->wait_q))
-               wake_up_interruptible(&lp_dev->wait_q);
+       if (LP_F(minor) & LP_ABORT)
+               return;
 
-       lp_dev->irq_detected = 1;
-       lp_dev->irq_missed = 0;
-}
-
-static void lp_error(int minor)
-{
-       if (LP_POLLED(minor) || LP_PREEMPTED(minor)) {
-               current->state = TASK_INTERRUPTIBLE;
-               lp_parport_release(minor);
-               schedule_timeout(LP_TIMEOUT_POLLED);
-               lp_parport_claim(minor);
-               lp_table[minor].irq_missed = 1;
-       }
+       polling = lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE;
+       if (polling) lp_parport_release (minor);
+       interruptible_sleep_on_timeout (&lp_table[minor].waitq,
+                                       LP_TIMEOUT_POLLED);
+       if (polling) lp_parport_claim (minor);
+       else parport_yield_blocking (lp_table[minor].dev);
 }
 
 static int lp_check_status(int minor)
 {
+       int error = 0;
        unsigned int last = lp_table[minor].last_error;
        unsigned char status = r_str(minor);
        if (status & LP_PERRORP)
@@ -422,155 +286,112 @@ static int lp_check_status(int minor)
                        last = LP_POUTPA;
                        printk(KERN_INFO "lp%d out of paper\n", minor);
                }
+               error = -ENOSPC;
        } else if (!(status & LP_PSELECD)) {
                if (last != LP_PSELECD) {
                        last = LP_PSELECD;
                        printk(KERN_INFO "lp%d off-line\n", minor);
                }
+               error = -EIO;
        } else {
                if (last != LP_PERRORP) {
                        last = LP_PERRORP;
                        printk(KERN_INFO "lp%d on fire\n", minor);
                }
+               error = -EIO;
        }
 
        lp_table[minor].last_error = last;
 
-       if (last != 0) {
-               if (LP_F(minor) & LP_ABORT)
-                       return 1;
+       if (last != 0)
                lp_error(minor);
-       }
 
-       return 0;
+       return error;
 }
 
-static int lp_write_buf(unsigned int minor, const char *buf, int count)
+static ssize_t lp_write(struct file * file, const char * buf,
+                       size_t count, loff_t *ppos)
 {
-       unsigned long copy_size;
-       unsigned long total_bytes_written = 0;
-       unsigned long bytes_written;
-       struct lp_struct *lp = &lp_table[minor];
-
-       if (minor >= LP_NO)
-               return -ENXIO;
-       if (lp->dev == NULL)
-               return -ENXIO;
-
-       lp_table[minor].last_error = 0;
-       lp_table[minor].irq_detected = 0;
-       lp_table[minor].irq_missed = 1;
-
-       if (LP_POLLED(minor))
-               w_ctr(minor, LP_PSELECP | LP_PINITP);
-       else
-               w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
-
-       do {
-               bytes_written = 0;
-               copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
-
-               if (copy_from_user(lp->lp_buffer, buf, copy_size))
-               {
-                       w_ctr(minor, LP_PSELECP | LP_PINITP);
-                       return -EFAULT;
-               }
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct parport *port = lp_table[minor].dev->port;
+       char *kbuf = lp_table[minor].lp_buffer;
+       ssize_t retv = 0;
+       ssize_t written;
+       size_t copy_size = count;
 
-               while (copy_size) {
-                       if (lp_char(lp->lp_buffer[bytes_written], minor)) {
-                               --copy_size;
-                               ++bytes_written;
 #ifdef LP_STATS
-                               lp->runchars++;
-#endif
-                       } else {
-                               int rc = total_bytes_written + bytes_written;
+       if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
+               lp_table[minor].runchars = 0;
 
-#ifdef LP_STATS
-                               if (lp->runchars > LP_STAT(minor).maxrun)
-                                       LP_STAT(minor).maxrun = lp->runchars;
-                               LP_STAT(minor).sleeps++;
+       lp_table[minor].lastcall = jiffies;
 #endif
 
-                               if (signal_pending(current))
-                               {
-                                       w_ctr(minor, LP_PSELECP | LP_PINITP);
-                                       if (total_bytes_written + bytes_written)
-                                               return total_bytes_written + bytes_written;
-                                       else
-                                               return -EINTR;
-                               }
+       /* Need to copy the data from user-space. */
+       if (copy_size > LP_BUFFER_SIZE)
+               copy_size = LP_BUFFER_SIZE;
 
-#ifdef LP_STATS
-                               lp->runchars = 0;
-#endif
+       if (copy_from_user (kbuf, buf, copy_size))
+               return -EFAULT;
 
-                               if (lp_check_status(minor))
-                               {
-                                       w_ctr(minor, LP_PSELECP | LP_PINITP);
-                                       return rc ? rc : -EIO;
-                               }
+       /* Claim Parport or sleep until it becomes available
+        */
+       lp_parport_claim (minor);
 
-                               if (LP_POLLED(minor) ||
-                                   lp_table[minor].irq_missed)
-                               {
-                               lp_polling:
-#if defined(LP_DEBUG) && defined(LP_STATS)
-                                       printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp->runchars, LP_TIME(minor));
-#endif
-                                       current->state = TASK_INTERRUPTIBLE;
-                                       lp_schedule(minor, LP_TIME(minor));
-                               } else {
-                                       cli();
-                                       if (LP_PREEMPTED(minor))
-                                       {
-                                               /*
-                                                * We can' t sleep on the interrupt
-                                                * since another pardevice need the port.
-                                                * We must check this in a cli() protected
-                                                * envinroment to avoid parport sharing
-                                                * starvation.
-                                                */
-                                               sti();
-                                               goto lp_polling;
-                                       }
-                                       if (!lp_table[minor].irq_detected)
-                                               interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT);
-                                       sti();
-                               }
-                       }
+       /* Go to compatibility mode. */
+       parport_negotiate (port, IEEE1284_MODE_COMPAT);
+
+       do {
+               /* Wait until lp_read has finished. */
+               if (down_interruptible (&lp_table[minor].port_mutex))
+                       break;
+
+               /* Write the data. */
+               written = parport_write (port, kbuf, copy_size);
+               if (written >= 0) {
+                       copy_size -= written;
+                       count -= written;
+                       buf  += written;
+                       retv += written;
                }
 
-               total_bytes_written += bytes_written;
-               buf += bytes_written;
-               count -= bytes_written;
+               up (&lp_table[minor].port_mutex);
 
-       } while (count > 0);
+               if (signal_pending (current)) {
+                       if (retv == 0)
+                               retv = -EINTR;
 
-       w_ctr(minor, LP_PSELECP | LP_PINITP);
-       return total_bytes_written;
-}
+                       break;
+               }
 
-static ssize_t lp_write(struct file * file, const char * buf,
-                       size_t count, loff_t *ppos)
-{
-       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
-       ssize_t retv;
+               if (copy_size > 0) {
+                       /* incomplete write -> check error ! */
+                       int error = lp_check_status (minor);
 
-#ifdef LP_STATS
-       if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
-               lp_table[minor].runchars = 0;
+                       if (LP_F(minor) & LP_ABORT) {
+                               if (retv == 0)
+                                       retv = error;
+                               break;
+                       }
 
-       lp_table[minor].lastcall = jiffies;
-#endif
+                       parport_yield_blocking (lp_table[minor].dev);
+               } else if (current->need_resched)
+                       schedule ();
 
-       /* Claim Parport or sleep until it becomes available
-        */
-       lp_parport_claim (minor);
+               if (count) {
+                       copy_size = count;
+                       if (copy_size > LP_BUFFER_SIZE)
+                               copy_size = LP_BUFFER_SIZE;
 
-       retv = lp_write_buf(minor, buf, count);
+                       if (copy_from_user(kbuf, buf, copy_size)) {
+                               if (retv == 0)
+                                       retv = -EFAULT;
+                               break;
+                       }
+               }       
+       } while (count > 0);
 
        lp_parport_release (minor);
+
        return retv;
 }
 
@@ -579,109 +400,54 @@ static long long lp_lseek(struct file * file, long long offset, int origin)
        return -ESPIPE;
 }
 
-#ifdef CONFIG_PRINTER_READBACK
-
-static int lp_read_nibble(int minor) 
-{
-       unsigned char i;
-       i = r_str(minor)>>3;
-       i &= ~8;
-       if ((i & 0x10) == 0) i |= 8;
-       return (i & 0x0f);
-}
+#ifdef CONFIG_PARPORT_1284
 
-static void lp_read_terminate(struct parport *port) {
-       parport_write_control(port, (parport_read_control(port) & ~2) | 8);
-       /* SelectIN high, AutoFeed low */
-       if (parport_wait_peripheral(port, 0x80, 0)) 
-               /* timeout, SelectIN high, Autofeed low */
-               return;
-       parport_write_control(port, parport_read_control(port) | 2);
-       /* AutoFeed high */
-       parport_wait_peripheral(port, 0x80, 0x80);
-       /* no timeout possible, Autofeed low, SelectIN high */
-       parport_write_control(port, (parport_read_control(port) & ~2) | 8);
-}
-
-/* Status readback confirming to ieee1284 */
+/* Status readback conforming to ieee1284 */
 static ssize_t lp_read(struct file * file, char * buf,
-                      size_t length, loff_t *ppos)
+                      size_t count, loff_t *ppos)
 {
-       int i;
        unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev);
-       char *temp = buf;
-       ssize_t count = 0;
-       unsigned char z = 0;
-       unsigned char Byte = 0;
        struct parport *port = lp_table[minor].dev->port;
+       ssize_t retval = 0;
+       char *kbuf = lp_table[minor].lp_buffer;
+
+       if (count > LP_BUFFER_SIZE)
+               count = LP_BUFFER_SIZE;
 
        lp_parport_claim (minor);
 
-       switch (parport_ieee1284_nibble_mode_ok(port, 0))
-       {
-       case 0:
-               /* Handshake failed. */
-               lp_read_terminate(port);
-               lp_parport_release (minor);
-               return -EIO;
-       case 1:
-               /* No data. */
-               lp_read_terminate(port);
-               lp_parport_release (minor);
-               return 0;
-       default:
-               /* Data available. */
+       if (!down_interruptible (&lp_table[minor].port_mutex)) {
+               for (;;) {
+                       retval = parport_read (port, kbuf, count);
 
-               /* Hack: Wait 10ms (between events 6 and 7) */
-                schedule_timeout((HZ+99)/100);
-                break;
-       }
+                       if (retval)
+                               break;
 
-       for (i=0; ; i++) {
-               parport_frob_control(port, 2, 2); /* AutoFeed high */
-               if (parport_wait_peripheral(port, 0x40, 0)) {
-#ifdef LP_READ_DEBUG
-                       /* Some peripherals just time out when they've sent
-                          all their data.  */
-                       printk("%s: read1 timeout.\n", port->name);
-#endif
-                       parport_frob_control(port, 2, 0); /* AutoFeed low */
-                       break;
-               }
-               z = lp_read_nibble(minor);
-               parport_frob_control(port, 2, 0); /* AutoFeed low */
-               if (parport_wait_peripheral(port, 0x40, 0x40)) {
-                       printk("%s: read2 timeout.\n", port->name);
-                       break;
-               }
-               if ((i & 1) != 0) {
-                       Byte |= (z<<4);
-                       if (__put_user (Byte, temp))
-                       {
-                               count = -EFAULT;
+                       if (file->f_flags & O_NONBLOCK)
                                break;
-                       } else {
-                               temp++;
 
-                               if (++count == length)
-                                       break;
-                       }
-                       /* Does the error line indicate end of data? */
-                       if ((parport_read_status(port) & LP_PERRORP) == 
-                           LP_PERRORP) 
+                       /* Wait for an interrupt. */
+                       interruptible_sleep_on_timeout (&lp_table[minor].waitq,
+                                                       LP_TIMEOUT_POLLED);
+
+                       if (signal_pending (current)) {
+                               retval = -EINTR;
                                break;
-               } else 
-                       Byte=z;
-       }
+                       }
+               }
 
-       lp_read_terminate(port);
+               up (&lp_table[minor].port_mutex);
+       }
 
        lp_parport_release (minor);
 
-       return count;
+       if (retval > 0 && copy_to_user (buf, kbuf, retval))
+               retval = -EFAULT;
+
+       return retval;
 }
 
-#endif
+#endif /* IEEE 1284 support */
 
 static int lp_open(struct inode * inode, struct file * file)
 {
@@ -729,7 +495,6 @@ static int lp_open(struct inode * inode, struct file * file)
                LP_F(minor) &= ~LP_BUSY;
                return -ENOMEM;
        }
-       init_waitqueue_head(&(lp_table[minor].wait_q));
        return 0;
 }
 
@@ -752,7 +517,7 @@ static int lp_ioctl(struct inode *inode, struct file *file,
        int retval = 0;
 
 #ifdef LP_DEBUG
-       printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
+       printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg);
 #endif
        if (minor >= LP_NO)
                return -ENODEV;
@@ -785,12 +550,6 @@ static int lp_ioctl(struct inode *inode, struct file *file,
                                LP_F(minor) &= ~LP_CAREFUL;
                        break;
 #endif
-               case LPTRUSTIRQ:
-                       if (arg)
-                               LP_F(minor) |= LP_TRUST_IRQ;
-                       else
-                               LP_F(minor) &= ~LP_TRUST_IRQ;
-                       break;
                case LPWAIT:
                        LP_WAIT(minor) = arg;
                        break;
@@ -834,16 +593,35 @@ static int lp_ioctl(struct inode *inode, struct file *file,
        return retval;
 }
 
+#ifdef CONFIG_PARPORT_1284
+static unsigned int lp_poll (struct file *filp, struct poll_table_struct *wait)
+{
+       unsigned int minor = MINOR (filp->f_dentry->d_inode->i_rdev);
+       unsigned int mask = POLLOUT | POLLWRNORM; /* always writable */
+
+       poll_wait (filp, &lp_table[minor].dataq, wait);
+
+       if (lp_table[minor].flags & LP_DATA_AVAIL)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+#endif /* IEEE 1284 support */
+
 static struct file_operations lp_fops = {
        lp_lseek,
-#ifdef CONFIG_PRINTER_READBACK
+#ifdef CONFIG_PARPORT_1284
        lp_read,
 #else
        NULL,
 #endif
        lp_write,
        NULL,           /* lp_readdir */
-       NULL,           /* lp_poll */
+#ifdef CONFIG_PARPORT_1284
+       lp_poll,
+#else
+       NULL,
+#endif
        lp_ioctl,
        NULL,           /* lp_mmap */
        lp_open,
@@ -851,6 +629,70 @@ static struct file_operations lp_fops = {
        lp_release
 };
 
+/* --- support for console on the line printer ----------------- */
+
+#ifdef CONFIG_LP_CONSOLE
+
+#define CONSOLE_LP 0
+
+/* If the printer is out of paper, we can either lose the messages or
+ * stall until the printer is happy again.  Define CONSOLE_LP_STRICT
+ * non-zero to get the latter behaviour. */
+#define CONSOLE_LP_STRICT 1
+
+static void lp_console_write (struct console *co, const char *s,
+                             unsigned count)
+{
+       struct pardevice *dev = lp_table[CONSOLE_LP].dev;
+       struct parport *port = dev->port;
+       ssize_t written;
+       signed long old_to;
+
+       if (!(lp_table[CONSOLE_LP].flags & (1<<LP_HAVE_PORT_BIT))) {
+               if (parport_claim (dev))
+                       /* Nothing we can do. */
+                       return;
+               set_bit (LP_HAVE_PORT_BIT, &lp_table[CONSOLE_LP].flags);
+       }
+
+       old_to = parport_set_timeout (dev, 0);
+
+       /* Go to compatibility mode. */
+       parport_negotiate (port, IEEE1284_MODE_COMPAT);
+
+       do {
+               /* Write the data. */
+               written = parport_write (port, s, count);
+               if (written > 0) {
+                       s += written;
+                       count -= written;
+               }
+       } while (count > 0 && (CONSOLE_LP_STRICT || written > 0));
+
+       parport_set_timeout (dev, old_to);
+}
+
+static kdev_t lp_console_device (struct console *c)
+{
+       return MKDEV(LP_MAJOR, CONSOLE_LP);
+}
+
+static struct console lpcons = {
+       "lp",
+       lp_console_write,
+       NULL,
+       lp_console_device,
+       NULL,
+       NULL,
+       NULL,
+       CON_PRINTBUFFER,
+       -1,
+       0,
+       NULL
+};
+
+#endif /* console on line printer */
+
 /* --- initialisation code ------------------------------------- */
 
 #ifdef MODULE
@@ -864,8 +706,8 @@ MODULE_PARM(reset, "i");
 
 #else
 
-static int parport_nr[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
-static int reset __initdata = 0;
+static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
+static int reset = 0;
 
 static int parport_ptr = 0;
 
@@ -896,10 +738,10 @@ __initfunc(void lp_setup(char *str, int *ints))
 
 #endif
 
-int lp_register(int nr, struct parport *port)
+static int lp_register(int nr, struct parport *port)
 {
        lp_table[nr].dev = parport_register_device(port, "lp", 
-                                                  lp_preempt, NULL,
+                                                  lp_preempt, lp_wakeup,
                                                   lp_interrupt, 
                                                   0,
                                                   (void *) &lp_table[nr]);
@@ -916,13 +758,56 @@ int lp_register(int nr, struct parport *port)
        return 0;
 }
 
-int lp_init(void)
+static void lp_attach (struct parport *port)
 {
-       unsigned int count = 0;
        unsigned int i;
-       struct parport *port;
 
-       for(i = 0; i < LP_NO; i++) {
+       switch (parport_nr[0])
+       {
+       case LP_PARPORT_UNSPEC:
+       case LP_PARPORT_AUTO:
+               if (parport_nr[0] == LP_PARPORT_AUTO &&
+                   port->probe_info[0].class != PARPORT_CLASS_PRINTER)
+                       return;
+
+               if (!lp_register(lp_count, port))
+                       if (++lp_count == LP_NO)
+                               break;
+
+               break;
+
+       default:
+               for (i = 0; i < LP_NO; i++) {
+                       if (port->number == parport_nr[i]) {
+                               if (!lp_register(i, port))
+                                       lp_count++;
+                               break;
+                       }
+               }
+               break;
+       }
+}
+
+static void lp_detach (struct parport *port)
+{
+       /* Write this some day. */
+}
+
+static struct parport_driver lp_driver = {
+       "lp",
+       lp_attach,
+       lp_detach,
+       NULL
+};
+
+int __init lp_init (void)
+{
+       int i;
+
+       if (parport_nr[0] == LP_PARPORT_OFF)
+               return 0;
+
+       for (i = 0; i < LP_NO; i++) {
                lp_table[i].dev = NULL;
                lp_table[i].flags = 0;
                lp_table[i].chars = LP_INIT_CHAR;
@@ -932,55 +817,37 @@ int lp_init(void)
 #ifdef LP_STATS
                lp_table[i].lastcall = 0;
                lp_table[i].runchars = 0;
-               memset(&lp_table[i].stats, 0, sizeof(struct lp_stats));
+               memset (&lp_table[i].stats, 0, sizeof (struct lp_stats));
 #endif
-               init_waitqueue_head(&lp_table[i].wait_q);
                lp_table[i].last_error = 0;
-               lp_table[i].irq_detected = 0;
-               lp_table[i].irq_missed = 0;
+               init_waitqueue_head (&lp_table[i].waitq);
+               init_waitqueue_head (&lp_table[i].dataq);
+               init_MUTEX (&lp_table[i].port_mutex);
        }
 
-       switch (parport_nr[0])
-       {
-       case LP_PARPORT_OFF:
-               return 0;
-
-       case LP_PARPORT_UNSPEC:
-       case LP_PARPORT_AUTO:
-               for (port = parport_enumerate(); port; port = port->next) {
-
-                       if (parport_nr[0] == LP_PARPORT_AUTO &&
-                           port->probe_info.class != PARPORT_CLASS_PRINTER)
-                               continue;
-
-                       if (!lp_register(count, port))
-                               if (++count == LP_NO)
-                                       break;
-               }
-               break;
+       if (register_chrdev (LP_MAJOR, "lp", &lp_fops)) {
+               printk ("lp: unable to get major %d\n", LP_MAJOR);
+               return -EIO;
+       }
 
-       default:
-               for (i = 0; i < LP_NO; i++) {
-                       for (port = parport_enumerate(); port; 
-                            port = port->next) {
-                               if (port->number == parport_nr[i]) {
-                                       if (!lp_register(i, port))
-                                               count++;
-                                       break;
-                               }
-                       }
-               }
-               break;
+       if (parport_register_driver (&lp_driver)) {
+               printk ("lp: unable to register with parport\n");
+               return -EIO;
        }
 
-       if (count) {
-               if (register_chrdev(LP_MAJOR, "lp", &lp_fops)) {
-                       printk("lp: unable to get major %d\n", LP_MAJOR);
-                       return -EIO;
-               }
-       } else {
-               printk(KERN_INFO "lp: driver loaded but no devices found\n");
+       if (!lp_count) {
+               printk (KERN_INFO "lp: driver loaded but no devices found\n");
+#ifndef CONFIG_PARPORT_12843
+               if (parport_nr[0] == LP_PARPORT_AUTO)
+                       printk (KERN_INFO "lp: (is IEEE 1284.3 support enabled?)\n");
+#endif
+       }
+#ifdef CONFIG_LP_CONSOLE
+       else {
+               register_console (&lpcons);
+               printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP);
        }
+#endif
 
        return 0;
 }
@@ -1018,10 +885,18 @@ void cleanup_module(void)
 {
        unsigned int offset;
 
+       parport_unregister_driver (&lp_driver);
+
+#ifdef CONFIG_LP_CONSOLE
+       unregister_console (&lpcons);
+#endif
+
        unregister_chrdev(LP_MAJOR, "lp");
        for (offset = 0; offset < LP_NO; offset++) {
                if (lp_table[offset].dev == NULL)
                        continue;
+               if (lp_table[offset].flags & (1<<LP_HAVE_PORT_BIT))
+                       parport_release (lp_table[offset].dev);
                parport_unregister_device(lp_table[offset].dev);
        }
 }
index 8c7020379fa6daf641398d486ba1f50e40ead63e..8674c4ee06cd3c5207d7cc172e9f8be11666174c 100644 (file)
@@ -1664,7 +1664,6 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
                       jiffies, check_time);
 #endif
                current->state = TASK_INTERRUPTIBLE;
-               current->counter = 0;   /* make us low-priority */
                schedule_timeout(check_time);
                if (signal_pending(current))
                        break;
index 487c0cb3933bba872db7b0a363d3439a54185e3e..e33a31ee2b0eec88abf24f7b545200c33ebb7ec5 100644 (file)
@@ -2380,7 +2380,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
                printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
                current->state = TASK_INTERRUPTIBLE;
-               current->counter = 0;   /* make us low-priority */
                schedule_timeout(char_time);
                if (signal_pending(current))
                        break;
index 2ef67d1b0c4aa70f81be27ed596b3c0e480e3e0f..9cf844c217b311f447b520ab1995ccf2571608f9 100644 (file)
@@ -1558,7 +1558,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
                char_time = MIN(char_time, timeout);
        while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
                current->state = TASK_INTERRUPTIBLE;
-               current->counter = 0;   /* make us low-priority */
                schedule_timeout(char_time);
                if (signal_pending(current))
                        break;
diff --git a/drivers/misc/Config.in b/drivers/misc/Config.in
new file mode 100644 (file)
index 0000000..e2d96d0
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+# Parport configuration.
+#
+
+tristate 'Parallel port support' CONFIG_PARPORT
+if [ "$CONFIG_PARPORT" != "n" ]; then
+  dep_tristate '   PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+  if [ "$CONFIG_PARPORT_PC" != "n" ]; then
+    bool '   Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
+  fi
+  if [ "$CONFIG_ARM" = "y" ]; then
+    dep_tristate '   Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+  fi
+  if [ "$CONFIG_AMIGA" = "y" ]; then
+    dep_tristate '   Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+    if [ "$CONFIG_ZORRO" != "n" ]; then
+      dep_tristate '   Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+    fi
+  else
+    define_bool CONFIG_PARPORT_AMIGA n
+    define_bool CONFIG_PARPORT_MFC3 n
+  fi
+  if [ "$CONFIG_ATARI" = "y" ]; then
+    dep_tristate '   Atari hardware' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
+  else
+    define_bool CONFIG_PARPORT_ATARI n
+  fi
+
+  # If exactly one hardware type is selected then parport will optimise away
+  # support for loading any others.  Defeat this if the user is keen.
+  bool '   Support foreign hardware' CONFIG_PARPORT_OTHER
+
+  bool '   IEEE 1284 transfer modes' CONFIG_PARPORT_1284
+fi
index 4036ac94c96ab401d7c3a5e3fb2980cb1c785bac..505a9d100470c6feae2ef2f34ff03ed167a1936a 100644 (file)
@@ -23,7 +23,13 @@ MI_OBJS  :=
 MIX_OBJS :=
 
 ifeq ($(CONFIG_PARPORT),y)
-  L_OBJS += parport_share.o parport_ieee1284.o parport_procfs.o
+  L_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o \
+            parport_procfs.o
+
+  ifeq ($(CONFIG_PARPORT_1284),y)
+    L_OBJS += parport_daisy.o parport_probe.o
+  endif
+
   ifeq ($(CONFIG_PARPORT_PC),y)
     LX_OBJS += parport_pc.o
   else
@@ -62,7 +68,10 @@ ifeq ($(CONFIG_PARPORT),y)
   LX_OBJS += parport_init.o
 else
   ifeq ($(CONFIG_PARPORT),m)
-    MI_OBJS += parport_share.o parport_ieee1284.o
+    MI_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o
+    ifeq ($(CONFIG_PARPORT_1284),y)
+      MI_OBJS += parport_daisy.o parport_probe.o
+    endif
     ifneq ($(CONFIG_PROC_FS),n) 
       MI_OBJS += parport_procfs.o
     endif
index 26fca9c9736e33df84e6561494295832f448e827..11581e2536d59cc9cbaad8ea60f68a375eec7ca8 100644 (file)
@@ -98,41 +98,36 @@ static struct parport_operations parport_arc_ops =
        arc_read_control,
        arc_frob_control,
 
-       NULL, /* write_econtrol */
-       NULL, /* read_econtrol */
-       NULL, /* frob_econtrol */
-
-       arc_write_status,
        arc_read_status,
 
-       NULL, /* write_fifo */
-       NULL, /* read_fifo */
-       
-       NULL, /* change_mode */
-       
-       NULL, /* epp_write_data */
-       NULL, /* epp_read_data */
-       NULL, /* epp_write_addr */
-       NULL, /* epp_read_addr */
-       NULL, /* epp_check_timeout */
+       arc_enable_irq,
+       arc_disable_irq,
 
-       NULL, /* epp_write_block */
-       NULL, /* epp_read_block */
+       arc_data_forward,
+       arc_data_reverse,
+
+       arc_interrupt,
 
-       NULL, /* ecp_write_block */
-       NULL, /* epp_write_block */
-       
        arc_init_state,
        arc_save_state,
        arc_restore_state,
 
-       arc_enable_irq,
-       arc_disable_irq,
-       arc_interrupt,
-
        arc_inc_use_count,
        arc_dec_use_count,
-       arc_fill_inode
+       arc_fill_inode,
+
+       parport_ieee1284_epp_write_data,
+       parport_ieee1284_epp_read_data,
+       parport_ieee1284_epp_write_addr,
+       parport_ieee1284_epp_read_addr,
+
+       parport_ieee1284_ecp_write_data,
+       parport_ieee1284_ecp_read_data,
+       parport_ieee1284_ecp_write_addr,
+       
+       parport_ieee1284_write_compat,
+       parport_ieee1284_read_nibble,
+       parport_ieee1284_read_byte,
 };
 
 /* --- Initialisation code -------------------------------- */
@@ -142,11 +137,11 @@ int parport_arc_init(void)
        /* Archimedes hardware provides only one port, at a fixed address */
        struct parport *p;
 
-       if (check_region(PORT_BASE, 4))
+       if (check_region(PORT_BASE, 1))
                return 0;
-       
-       p = parport_register_port(base, IRQ_PRINTERACK, 
-                                 PARPORT_DMA_NONE, &parport_arc_ops);
+
+       p = parport_register_port (PORT_BASE, IRQ_PRINTERACK,
+                                  PARPORT_DMA_NONE, &parport_arc_ops);
 
        if (!p)
                return 0;
@@ -158,9 +153,6 @@ int parport_arc_init(void)
               p->irq);
        parport_proc_register(p);
 
-       if (parport_probe_hook)
-               (*parport_probe_hook)(p);
-
        /* Tell the high-level drivers about the port. */
        parport_announce_port (p);
 
index 5aed4994b340955eeed3301554072b196ef6cb85..1222130336689d922272f8aaa71b577a0131077b 100644 (file)
@@ -221,9 +221,6 @@ parport_atari_init(void)
                printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
                parport_proc_register(p);
 
-               if (parport_probe_hook)
-                       (*parport_probe_hook)(p);
-
                parport_announce_port (p);
 
                return 1;
index 5baf7d25e49602dbe7beed01dce873c176b46d3f..40ef8d0d9e1c9e1345244d59014b1fb6ad49bd41 100644 (file)
@@ -164,6 +164,7 @@ parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char va
 void
 parport_ax_change_mode(struct parport *p, int m)
 {
+       /* FIXME */
        parport_ax_frob_econtrol(p, 0xe0, m << 5);
 }
 
@@ -201,58 +202,40 @@ parport_ax_enable_irq(struct parport *p)
        writel(dcsr, (unsigned long)&dma->dcsr);
 }
 
-int
-parport_ax_claim_resources(struct parport *p)
-{
-}
-
 void
-parport_ax_init_state(struct parport_state *s)
+parport_ax_init_state(struct pardevice *dev, struct parport_state *s)
 {
-       s->u.pc.ctr = 0xc;
-       s->u.pc.ecr = 0x0;
+       struct linux_ebus_dma *dma = dev->port->private_data;
+
+       s->u.ax.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+       s->u.ax.ecr = 0x0;
+
+       if (dev->irq_func)
+               s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
+                               | EBUS_DCSR_INT_EN);
+       else
+               s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
+                               & ~EBUS_DCSR_INT_EN);
 }
 
 void
 parport_ax_save_state(struct parport *p, struct parport_state *s)
 {
-       s->u.pc.ctr = parport_ax_read_control(p);
-       s->u.pc.ecr = parport_ax_read_econtrol(p);
+       struct linux_ebus_dma *dma = p->private_data;
+
+       s->u.ax.ctr = parport_ax_read_control(p);
+       s->u.ax.ecr = parport_ax_read_econtrol(p);
+       s->u.ax.dcsr = readl((unsigned long)&dma->dcsr);
 }
 
 void
 parport_ax_restore_state(struct parport *p, struct parport_state *s)
 {
-       parport_ax_write_control(p, s->u.pc.ctr);
-       parport_ax_write_econtrol(p, s->u.pc.ecr);
-}
-
-size_t
-parport_ax_epp_read_block(struct parport *p, void *buf, size_t length)
-{
-       return 0; /* FIXME */
-}
-
-size_t
-parport_ax_epp_write_block(struct parport *p, void *buf, size_t length)
-{
-       return 0; /* FIXME */
-}
-
-int
-parport_ax_ecp_read_block(struct parport *p, void *buf, size_t length,
-                         void (*fn)(struct parport *, void *, size_t),
-                         void *handle)
-{
-       return 0; /* FIXME */
-}
+       struct linux_ebus_dma *dma = p->private_data;
 
-int
-parport_ax_ecp_write_block(struct parport *p, void *buf, size_t length,
-                          void (*fn)(struct parport *, void *, size_t),
-                          void *handle)
-{
-       return 0; /* FIXME */
+       parport_ax_write_control(p, s->u.ax.ctr);
+       parport_ax_write_econtrol(p, s->u.ax.ecr);
+       writel(s->u.ax.dcsr, (unsigned long)&dma->dcsr);
 }
 
 void
@@ -290,41 +273,36 @@ static struct parport_operations parport_ax_ops =
        parport_ax_read_control,
        parport_ax_frob_control,
 
-       parport_ax_write_econtrol,
-       parport_ax_read_econtrol,
-       parport_ax_frob_econtrol,
-
-       parport_ax_write_status,
        parport_ax_read_status,
 
-       parport_ax_write_fifo,
-       parport_ax_read_fifo,
-       
-       parport_ax_change_mode,
-       
-       parport_ax_write_epp,
-       parport_ax_read_epp,
-       parport_ax_write_epp_addr,
-       parport_ax_read_epp_addr,
-       parport_ax_check_epp_timeout,
+       parport_ax_enable_irq,
+       parport_ax_disable_irq,
 
-       parport_ax_epp_write_block,
-       parport_ax_epp_read_block,
+       parport_ax_data_forward,
+       parport_ax_data_reverse,
+
+       parport_ax_interrupt,
 
-       parport_ax_ecp_write_block,
-       parport_ax_ecp_read_block,
-       
        parport_ax_init_state,
        parport_ax_save_state,
        parport_ax_restore_state,
 
-       parport_ax_enable_irq,
-       parport_ax_disable_irq,
-       parport_ax_interrupt,
-
        parport_ax_inc_use_count,
        parport_ax_dec_use_count,
-       parport_ax_fill_inode
+       parport_ax_fill_inode,
+
+       parport_ieee1284_epp_write_data,
+       parport_ieee1284_epp_read_data,
+       parport_ieee1284_epp_write_addr,
+       parport_ieee1284_epp_read_addr,
+
+       parport_ieee1284_ecp_write_data,
+       parport_ieee1284_ecp_read_data,
+       parport_ieee1284_ecp_write_addr,
+
+       parport_ieee1284_write_compat,
+       parport_ieee1284_read_nibble,
+       parport_ieee1284_read_byte,
 };
 
 
@@ -539,20 +517,6 @@ init_one_port(struct linux_ebus_device *dev)
        if (p->dma == PARPORT_DMA_AUTO)
                p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE;
 
-       if (p->irq != PARPORT_IRQ_NONE) {
-               int err;
-               if ((err = request_irq(p->irq, parport_ax_interrupt,
-                                      0, p->name, p)) != 0)
-                       return err;
-               else
-                       parport_ax_enable_irq(p);
-       }
-       request_region(p->base, p->size, p->name);
-       if (p->modes & PARPORT_MODE_PCECR)
-               request_region(p->base+0x400, 3, p->name);
-       request_region((unsigned long)p->private_data,
-                      sizeof(struct linux_ebus_dma), p->name);
-
        printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
        if (p->irq != PARPORT_IRQ_NONE)
                printk(", irq %s", __irq_itoa(p->irq));
@@ -569,12 +533,21 @@ init_one_port(struct linux_ebus_device *dev)
        printk("]\n");
        parport_proc_register(p);
 
+       if (p->irq != PARPORT_IRQ_NONE)
+               if ((err = request_irq(p->irq, parport_ax_interrupt,
+                                      0, p->name, p)) != 0)
+                       return 0;               /* @@@ FIXME */
+
+       request_region(p->base, p->size, p->name);
+       if (p->modes & PARPORT_MODE_PCECR)
+               request_region(p->base+0x400, 3, p->name);
+       request_region((unsigned long)p->private_data,
+                      sizeof(struct linux_ebus_dma), p->name);
+
        p->ops->write_control(p, 0x0c);
        p->ops->write_data(p, 0);
 
-       if (parport_probe_hook)
-               (*parport_probe_hook)(p);
-
+       /* Tell the high-level drivers about the port. */
        parport_announce_port (p);
 
        return 1;
diff --git a/drivers/misc/parport_daisy.c b/drivers/misc/parport_daisy.c
new file mode 100644 (file)
index 0000000..78b63ce
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * IEEE 1284.3 Parallel port daisy chain and multiplexor code
+ * 
+ * Copyright (C) 1999  Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * 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.
+ *
+ * ??-12-1998: Initial implementation.
+ * 31-01-1999: Make port-cloning transparent.
+ * 13-02-1999: Move DeviceID technique from parport_probe.
+ * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+static struct daisydev {
+       struct daisydev *next;
+       struct parport *port;
+       int daisy;
+       int devnum;
+} *topology = NULL;
+
+static int numdevs = 0;
+
+/* Forward-declaration of lower-level functions. */
+static int mux_present (struct parport *port);
+static int num_mux_ports (struct parport *port);
+static int select_port (struct parport *port);
+static int assign_addrs (struct parport *port);
+
+/* Add a device to the discovered topology. */
+static void add_dev (int devnum, struct parport *port, int daisy)
+{
+       struct daisydev *newdev;
+       newdev = kmalloc (GFP_KERNEL, sizeof (struct daisydev));
+       if (newdev) {
+               newdev->port = port;
+               newdev->daisy = daisy;
+               newdev->devnum = devnum;
+               newdev->next = topology;
+               if (!topology || topology->devnum >= devnum)
+                       topology = newdev;
+               else {
+                       struct daisydev *prev = topology;
+                       while (prev->next && prev->next->devnum < devnum)
+                               prev = prev->next;
+                       newdev->next = prev->next;
+                       prev->next = newdev;
+               }
+       }
+}
+
+/* Clone a parport (actually, make an alias). */
+static struct parport *clone_parport (struct parport *real, int muxport)
+{
+       struct parport *extra = parport_register_port (real->base,
+                                                      real->irq,
+                                                      real->dma,
+                                                      real->ops);
+       if (extra) {
+               extra->portnum = real->portnum;
+               extra->physport = real;
+               extra->muxport = muxport;
+       }
+
+       return extra;
+}
+
+/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */
+int parport_daisy_init (struct parport *port)
+{
+       char *deviceid;
+       static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
+       int num_ports;
+       int i;
+
+       /* Because this is called before any other devices exist,
+        * we don't have to claim exclusive access.  */
+
+       /* If mux present on normal port, need to create new
+        * parports for each extra port. */
+       if (port->muxport < 0 && mux_present (port) &&
+           /* don't be fooled: a mux must have 2 or 4 ports. */
+           ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {
+               /* Leave original as port zero. */
+               port->muxport = 0;
+               printk (KERN_INFO
+                       "%s: 1st (default) port of %d-way multiplexor\n",
+                       port->name, num_ports);
+               for (i = 1; i < num_ports; i++) {
+                       /* Clone the port. */
+                       struct parport *extra = clone_parport (port, i);
+                       if (!extra) {
+                               if (signal_pending (current))
+                                       break;
+
+                               schedule ();
+                               continue;
+                       }
+
+                       printk (KERN_INFO
+                               "%s: %d%s port of %d-way multiplexor on %s\n",
+                               extra->name, i + 1, th[i + 1], num_ports,
+                               port->name);
+
+                       /* Analyse that port too.  We won't recurse
+                          forever because of the 'port->muxport < 0'
+                          test above. */
+                       parport_announce_port (extra);
+               }
+       }
+
+       if (port->muxport >= 0)
+               select_port (port);
+
+       parport_daisy_deselect_all (port);
+       assign_addrs (port);
+
+       /* Count the potential legacy device at the end. */
+       add_dev (numdevs++, port, -1);
+
+       /* Find out the legacy device's IEEE 1284 device ID. */
+       deviceid = kmalloc (1000, GFP_KERNEL);
+       if (deviceid) {
+               parport_device_id (numdevs - 1, deviceid, 1000);
+               kfree (deviceid);
+       }
+
+       return 0;
+}
+
+/* Forget about devices on a physical port. */
+void parport_daisy_fini (struct parport *port)
+{
+       struct daisydev *dev, *prev = topology;
+       while (prev && prev->port == port)
+               prev = topology = topology->next;
+
+       while (prev) {
+               dev = prev->next;
+               if (dev && dev->port == port)
+                       prev->next = dev->next;
+
+               prev = prev->next;
+       }
+
+       /* Gaps in the numbering could be handled better.  How should
+           someone enumerate through all IEEE1284.3 devices in the
+           topology?. */
+       if (!topology) numdevs = 0;
+       return; }
+
+/* Find a device by canonical device number. */
+struct pardevice *parport_open (int devnum, const char *name,
+                               int (*pf) (void *), void (*kf) (void *),
+                               void (*irqf) (int, void *, struct pt_regs *),
+                               int flags, void *handle)
+{
+       struct parport *port = parport_enumerate ();
+       struct pardevice *dev;
+       int portnum;
+       int muxnum;
+       int daisynum;
+
+       if (parport_device_coords (devnum,  &portnum, &muxnum, &daisynum))
+               return NULL;
+
+       while (port && ((port->portnum != portnum) ||
+                       (port->muxport != muxnum)))
+               port = port->next;
+
+       if (!port)
+               /* No corresponding parport. */
+               return NULL;
+
+       dev = parport_register_device (port, name, pf, kf,
+                                      irqf, flags, handle);
+       if (dev)
+               dev->daisy = daisynum;
+
+       /* Check that there really is a device to select. */
+       if (daisynum >= 0) {
+               int selected;
+               parport_claim_or_block (dev);
+               selected = port->daisy;
+               parport_release (dev);
+
+               if (selected != port->daisy) {
+                       /* No corresponding device. */
+                       parport_unregister_device (dev);
+                       return NULL;
+               }
+       }
+
+       return dev;
+}
+
+/* The converse of parport_open. */
+void parport_close (struct pardevice *dev)
+{
+       parport_unregister_device (dev);
+}
+
+/* Convert device coordinates into a canonical device number. */
+int parport_device_num (int parport, int mux, int daisy)
+{
+       struct daisydev *dev = topology;
+
+       while (dev && dev->port->portnum != parport &&
+              dev->port->muxport != mux && dev->daisy != daisy)
+               dev = dev->next;
+
+       if (!dev)
+               return -ENXIO;
+
+       return dev->devnum;
+}
+
+/* Convert a canonical device number into device coordinates. */
+int parport_device_coords (int devnum, int *parport, int *mux, int *daisy)
+{
+       struct daisydev *dev = topology;
+
+       while (dev && dev->devnum != devnum)
+               dev = dev->next;
+
+       if (!dev)
+               return -ENXIO;
+
+       if (parport) *parport = dev->port->portnum;
+       if (mux) *mux = dev->port->muxport;
+       if (daisy) *daisy = dev->daisy;
+       return 0;
+}
+
+/* Send a daisy-chain-style CPP command packet. */
+static int cpp_daisy (struct parport *port, int cmd)
+{
+       unsigned char s;
+
+       parport_write_data (port, 0xaa); udelay (2);
+       parport_write_data (port, 0x55); udelay (2);
+       parport_write_data (port, 0x00); udelay (2);
+       parport_write_data (port, 0xff); udelay (2);
+       s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+                                         | PARPORT_STATUS_PAPEROUT
+                                         | PARPORT_STATUS_SELECT
+                                         | PARPORT_STATUS_ERROR);
+       if (s != (PARPORT_STATUS_BUSY
+                 | PARPORT_STATUS_PAPEROUT
+                 | PARPORT_STATUS_SELECT
+                 | PARPORT_STATUS_ERROR)) {
+               DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
+                        port->name, s);
+               return -ENXIO;
+       }
+
+       parport_write_data (port, 0x87); udelay (2);
+       s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+                                         | PARPORT_STATUS_PAPEROUT
+                                         | PARPORT_STATUS_SELECT
+                                         | PARPORT_STATUS_ERROR);
+       if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+               DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
+                        port->name, s);
+               return -ENXIO;
+       }
+
+       parport_write_data (port, 0x78); udelay (2);
+       parport_write_data (port, cmd); udelay (2);
+       parport_frob_control (port,
+                             PARPORT_CONTROL_STROBE,
+                             PARPORT_CONTROL_STROBE);
+       udelay (1);
+       parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+       udelay (1);
+       s = parport_read_status (port);
+       parport_write_data (port, 0xff); udelay (2);
+
+       return s;
+}
+
+/* Send a mux-style CPP command packet. */
+static int cpp_mux (struct parport *port, int cmd)
+{
+       unsigned char s;
+       int rc;
+
+       parport_write_data (port, 0xaa); udelay (2);
+       parport_write_data (port, 0x55); udelay (2);
+       parport_write_data (port, 0xf0); udelay (2);
+       parport_write_data (port, 0x0f); udelay (2);
+       parport_write_data (port, 0x52); udelay (2);
+       parport_write_data (port, 0xad); udelay (2);
+       parport_write_data (port, cmd); udelay (2);
+
+       s = parport_read_status (port);
+       if (!(s & PARPORT_STATUS_ACK)) {
+               DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
+                        port->name, cmd, s);
+               return -EIO;
+       }
+
+       rc = (((s & PARPORT_STATUS_SELECT   ? 1 : 0) << 0) |
+             ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) |
+             ((s & PARPORT_STATUS_BUSY     ? 0 : 1) << 2) |
+             ((s & PARPORT_STATUS_ERROR    ? 0 : 1) << 3));
+
+       return rc;
+}
+
+void parport_daisy_deselect_all (struct parport *port)
+{
+       cpp_daisy (port, 0x30);
+}
+
+int parport_daisy_select (struct parport *port, int daisy, int mode)
+{
+       /* mode is currently ignored. FIXME? */
+       return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR;
+}
+
+static int mux_present (struct parport *port)
+{
+       return cpp_mux (port, 0x51) == 3;
+}
+
+static int num_mux_ports (struct parport *port)
+{
+       return cpp_mux (port, 0x58);
+}
+
+static int select_port (struct parport *port)
+{
+       int muxport = port->muxport;
+       return cpp_mux (port, 0x60 + muxport) == muxport;
+}
+
+static int assign_addrs (struct parport *port)
+{
+       unsigned char s, last_dev;
+       unsigned char daisy;
+       int thisdev = numdevs;
+       char *deviceid;
+
+       parport_write_data (port, 0xaa); udelay (2);
+       parport_write_data (port, 0x55); udelay (2);
+       parport_write_data (port, 0x00); udelay (2);
+       parport_write_data (port, 0xff); udelay (2);
+       s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+                                         | PARPORT_STATUS_PAPEROUT
+                                         | PARPORT_STATUS_SELECT
+                                         | PARPORT_STATUS_ERROR);
+       if (s != (PARPORT_STATUS_BUSY
+                 | PARPORT_STATUS_PAPEROUT
+                 | PARPORT_STATUS_SELECT
+                 | PARPORT_STATUS_ERROR)) {
+               DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
+                        port->name, s);
+               return -ENXIO;
+       }
+
+       parport_write_data (port, 0x87); udelay (2);
+       s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+                                         | PARPORT_STATUS_PAPEROUT
+                                         | PARPORT_STATUS_SELECT
+                                         | PARPORT_STATUS_ERROR);
+       if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+               DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
+                        port->name, s);
+               return -ENXIO;
+       }
+
+       parport_write_data (port, 0x78); udelay (2);
+       last_dev = 0; /* We've just been speaking to a device, so we
+                        know there must be at least _one_ out there. */
+
+       for (daisy = 0; daisy < 4; daisy++) {
+               parport_write_data (port, daisy);
+               udelay (2);
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_STROBE,
+                                     PARPORT_CONTROL_STROBE);
+               udelay (1);
+               parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+               udelay (1);
+
+               if (last_dev)
+                       /* No more devices. */
+                       break;
+
+               last_dev = !(parport_read_status (port)
+                            & PARPORT_STATUS_BUSY);
+
+               add_dev (numdevs++, port, daisy);
+       }
+
+       parport_write_data (port, 0xff); udelay (2);
+       DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
+               numdevs - thisdev);
+
+       /* Ask the new devices to introduce themselves. */
+       deviceid = kmalloc (1000, GFP_KERNEL);
+       if (!deviceid) return 0;
+
+       for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
+               parport_device_id (thisdev, deviceid, 1000);
+
+       kfree (deviceid);
+       return 0;
+}
+
+/* Find a device with a particular manufacturer and model string,
+   starting from a given device number.  Like the PCI equivalent,
+   'from' itself is skipped. */
+int parport_find_device (const char *mfg, const char *mdl, int from)
+{
+       struct daisydev *d = topology; /* sorted by devnum */
+
+       /* Find where to start. */
+       while (d && d->devnum <= from)
+               d = d->next;
+
+       /* Search. */
+       while (d) {
+               struct parport_device_info *info;
+               info = &d->port->probe_info[1 + d->daisy];
+               if ((!mfg || !strcmp (mfg, info->mfr)) &&
+                   (!mdl || !strcmp (mdl, info->model)))
+                       break;
+
+               d = d->next;
+       }
+
+       if (d)
+               return d->devnum;
+
+       return -1;
+}
+
+/* Find a device in a particular class.  Like the PCI equivalent,
+   'from' itself is skipped. */
+int parport_find_class (parport_device_class cls, int from)
+{
+       struct daisydev *d = topology; /* sorted by devnum */
+
+       /* Find where to start. */
+       while (d && d->devnum <= from)
+               d = d->next;
+
+       /* Search. */
+       while (d && d->port->probe_info[1 + d->daisy].class != cls)
+               d = d->next;
+
+       if (d)
+               return d->devnum;
+
+       return -1;
+}
index 91f6c262b939c67a41d449cf8393fe061040e463..6cac030a195b520b422336d9479648c665acd721 100644 (file)
@@ -4,12 +4,73 @@
  * Authors: Phil Blundell <Philip.Blundell@pobox.com>
  *          Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
  *         Jose Renau <renau@acm.org>
+ *          Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
+ *
+ * This file is responsible for IEEE 1284 negotiation, and for handing
+ * read/write requests to low-level drivers.
  */
 
+#include <linux/config.h>
 #include <linux/tasks.h>
 #include <linux/parport.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
+#include <linux/interrupt.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef CONFIG_LP_CONSOLE
+#undef DEBUG /* Don't want a garbled console */
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+/* Make parport_wait_peripheral wake up.
+ * It will be useful to call this from an interrupt handler. */
+void parport_ieee1284_wakeup (struct parport *port)
+{
+       up (&port->physport->ieee1284.irq);
+}
+
+static struct parport *port_from_cookie[PARPORT_MAX];
+static void timeout_waiting_on_port (unsigned long cookie)
+{
+       parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]);
+}
+
+/* Wait for a parport_ieee1284_wakeup.
+ * 0:      success
+ * <0:     error (exit as soon as possible)
+ * >0:     timed out
+ */
+int parport_wait_event (struct parport *port, signed long timeout)
+{
+       int ret;
+       struct timer_list timer;
+
+       if (!port->physport->cad->timeout)
+               /* Zero timeout is special, and we can't down() the
+                  semaphore. */
+               return 1;
+
+       init_timer (&timer);
+       timer.expires = jiffies + timeout;
+       timer.function = timeout_waiting_on_port;
+       port_from_cookie[port->number % PARPORT_MAX] = port;
+       timer.data = port->number;
+
+       add_timer (&timer);
+       ret = down_interruptible (&port->physport->ieee1284.irq);
+       if (!del_timer (&timer) && !ret)
+               /* Timed out. */
+               ret = 1;
+
+       return ret;
+}
 
 /* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to
  * 25 for this. After this time we can create a timeout because the
  * are able to eat the time up to 40ms.
  */ 
 
-int parport_wait_peripheral(struct parport *port, unsigned char mask, 
-       unsigned char result)
+int parport_wait_peripheral(struct parport *port,
+                           unsigned char mask, 
+                           unsigned char result)
 {
        int counter;
-       unsigned char status; 
-       
-       for (counter = 0; counter < 20; counter++) {
-               status = parport_read_status(port);
+       long deadline;
+       unsigned char status;
+
+       counter = port->physport->spintime; /* usecs of fast polling */
+       if (!port->physport->cad->timeout)
+               /* A zero timeout is "special": busy wait for the
+                  entire 35ms. */
+               counter = 35000;
+
+       /* Fast polling.
+        *
+        * This should be adjustable.
+        * How about making a note (in the device structure) of how long
+        * it takes, so we know for next time?
+        */
+       for (counter /= 5; counter > 0; counter--) {
+               status = parport_read_status (port);
                if ((status & mask) == result)
                        return 0;
-               udelay(25);
+               if (signal_pending (current))
+                       return -EINTR;
                if (current->need_resched)
-                       schedule();
+                       break;
+               udelay(5);
+       }
+
+       if (!port->physport->cad->timeout)
+               /* We may be in an interrupt handler, so we can't poll
+                * slowly anyway. */
+               return 1;
+
+       /* 40ms of slow polling. */
+       deadline = jiffies + (HZ + 24) / 25;
+       while (time_before (jiffies, deadline)) {
+               int ret;
+
+               if (signal_pending (current))
+                       return -EINTR;
+
+               /* Wait for 10ms (or until an interrupt occurs if
+                * the handler is set) */
+               if ((ret = parport_wait_event (port, (HZ + 99) / 100)) < 0)
+                       return ret;
+
+               status = parport_read_status (port);
+               if ((status & mask) == result)
+                       return 0;
+
+               if (!ret) {
+                       /* parport_wait_event didn't time out, but the
+                        * peripheral wasn't actually ready either.
+                        * Wait for another 10ms. */
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout ((HZ+ 99) / 100);
+               }
+       }
+
+       return 1;
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Terminate a negotiated mode. */
+static void parport_ieee1284_terminate (struct parport *port)
+{
+       port = port->physport;
+
+       port->ieee1284.phase = IEEE1284_PH_TERMINATE;
+
+       /* EPP terminates differently. */
+       switch (port->ieee1284.mode) {
+       case IEEE1284_MODE_EPP:
+       case IEEE1284_MODE_EPPSL:
+       case IEEE1284_MODE_EPPSWE:
+               /* Terminate from EPP mode. */
+
+               /* Event 68: Set nInit low */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_INIT,
+                                     PARPORT_CONTROL_INIT);
+               udelay (50);
+
+               /* Event 69: Set nInit high, nSelectIn low */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_SELECT,
+                                     PARPORT_CONTROL_SELECT);
+               break;
+               
+       default:
+               /* Terminate from all other modes. */
+
+               /* Event 22: Set nSelectIn low, nAutoFd high */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_SELECT
+                                     | PARPORT_CONTROL_AUTOFD,
+                                     PARPORT_CONTROL_SELECT);
+
+               /* Event 24: nAck goes low */
+               parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
+
+               /* Event 25: Set nAutoFd low */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_AUTOFD,
+                                     PARPORT_CONTROL_AUTOFD);
+
+               /* Event 27: nAck goes high */
+               parport_wait_peripheral (port,
+                                        PARPORT_STATUS_ACK, 
+                                        PARPORT_STATUS_ACK);
+
+               /* Event 29: Set nAutoFd high */
+               parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
        }
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(HZ/25);                                /* wait for 40ms */
-       status = parport_read_status(port);
-       return ((status & mask) == result)?0:1;
+
+       port->ieee1284.mode = IEEE1284_MODE_COMPAT;
+       port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+       DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n",
+                port->name);
 }              
+#endif /* IEEE1284 support */
 
-/* Test if the peripheral is IEEE 1284 compliant.
+/* Negotiate an IEEE 1284 mode.
  * return values are:
- *   0 - handshake failed; peripheral is not compliant (or none present)
- *   1 - handshake OK; IEEE1284 peripheral present but no data available
- *   2 - handshake OK; IEEE1284 peripheral and data available
+ *   0 - handshake OK; IEEE1284 peripheral and mode available
+ *  -1 - handshake failed; peripheral is not compliant (or none present)
+ *   1 - handshake OK; IEEE1284 peripheral present but mode not available
  */
-int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode) 
+int parport_negotiate (struct parport *port, int mode)
 {
-       /* make sure it's a valid state, set nStrobe & nAutoFeed high */
-       parport_frob_control (port, (1|2), 0);
-       udelay(1);
-       parport_write_data(port, mode);
-       udelay(400);
-       /* nSelectIn high, nAutoFd low */
-       parport_frob_control(port, (2|8), 2);
-       if (parport_wait_peripheral(port, 0x78, 0x38)) {
-               parport_frob_control(port, (2|8), 8);
+#ifndef CONFIG_PARPORT_1284
+       if (mode == IEEE1284_MODE_COMPAT)
+               return 0;
+       printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
+       return -1;
+#else
+       int m = mode;
+       unsigned char xflag;
+
+       port = port->physport;
+
+       /* Is there anything to do? */
+       if (port->ieee1284.mode == mode)
+               return 0;
+
+       /* Go to compability forward idle mode */
+       if (port->ieee1284.mode != IEEE1284_MODE_COMPAT)
+               parport_ieee1284_terminate (port);
+
+       if (mode == IEEE1284_MODE_COMPAT)
+               /* Compatibility mode: no negotiation. */
                return 0; 
+
+       switch (mode) {
+       case IEEE1284_MODE_ECPSWE:
+               m = IEEE1284_MODE_ECP;
+               break;
+       case IEEE1284_MODE_EPPSL:
+       case IEEE1284_MODE_EPPSWE:
+               m = IEEE1284_MODE_EPP;
+               break;
+       case IEEE1284_MODE_BECP:
+               return -ENOSYS; /* FIXME (implement BECP) */
        }
-       /* nStrobe low */
-       parport_frob_control (port, 1, 1);
-       udelay(1);                                   /* Strobe wait */
-       /* nStrobe high, nAutoFeed low, last step before transferring 
-        *  reverse data */
-       parport_frob_control (port, (1|2), 0);
+
+       port->ieee1284.phase = IEEE1284_PH_NEGOTIATION;
+
+       /* Start off with nStrobe and nAutoFd high, and nSelectIn low */
+       parport_frob_control (port,
+                             PARPORT_CONTROL_STROBE
+                             | PARPORT_CONTROL_AUTOFD
+                             | PARPORT_CONTROL_SELECT,
+                             PARPORT_CONTROL_SELECT);
        udelay(1);
-       /* Data available? */
-       parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK);
-       return (parport_read_status(port) & PARPORT_STATUS_ERROR)?1:2;
+
+       /* Event 0: Set data */
+       parport_write_data (port, m);
+       udelay (400); /* Shouldn't need to wait this long. */
+
+       /* Event 1: Set nSelectIn high, nAutoFd low */
+       parport_frob_control (port,
+                             PARPORT_CONTROL_SELECT
+                             | PARPORT_CONTROL_AUTOFD,
+                             PARPORT_CONTROL_AUTOFD);
+
+       /* Event 2: PError, Select, nFault go high, nAck goes low */
+       if (parport_wait_peripheral (port,
+                                    PARPORT_STATUS_ERROR
+                                    | PARPORT_STATUS_SELECT
+                                    | PARPORT_STATUS_PAPEROUT
+                                    | PARPORT_STATUS_ACK,
+                                    PARPORT_STATUS_ERROR
+                                    | PARPORT_STATUS_SELECT
+                                    | PARPORT_STATUS_PAPEROUT)) {
+               /* Timeout */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_SELECT
+                                     | PARPORT_CONTROL_AUTOFD,
+                                     PARPORT_CONTROL_SELECT);
+               DPRINTK (KERN_DEBUG
+                        "%s: Peripheral not IEEE1284 compliant (0x%02X)\n",
+                        port->name, parport_read_status (port));
+               port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+               return -1; /* Not IEEE1284 compliant */
+       }
+
+       /* Event 3: Set nStrobe low */
+       parport_frob_control (port,
+                             PARPORT_CONTROL_STROBE,
+                             PARPORT_CONTROL_STROBE);
+
+       /* Event 4: Set nStrobe and nAutoFd high */
+       udelay (5);
+       parport_frob_control (port,
+                             PARPORT_CONTROL_STROBE
+                             | PARPORT_CONTROL_AUTOFD,
+                             0);
+
+       /* Event 6: nAck goes high */
+       if (parport_wait_peripheral (port,
+                                    PARPORT_STATUS_ACK
+                                    | PARPORT_STATUS_PAPEROUT,
+                                    PARPORT_STATUS_ACK)) {
+               if (parport_read_status (port) & PARPORT_STATUS_ACK)
+                       printk (KERN_DEBUG
+                               "%s: working around buggy peripheral: tell "
+                               "Tim what make it is\n", port->name);
+               DPRINTK (KERN_DEBUG
+                        "%s: Mode 0x%02x not supported? (0x%02x)\n",
+                        port->name, mode, port->ops->read_status (port));
+               parport_ieee1284_terminate (port);
+               return 1;
+       }
+
+       xflag = parport_read_status (port) & PARPORT_STATUS_SELECT;
+
+       /* xflag should be high for all modes other than nibble (0). */
+       if (mode && !xflag) {
+               /* Mode not supported. */
+               DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported\n",
+                        port->name, mode);
+               parport_ieee1284_terminate (port);
+               return 1;
+       }
+
+       /* Mode is supported */
+       DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode);
+       port->ieee1284.mode = mode;
+
+       /* But ECP is special */
+       if (mode & IEEE1284_MODE_ECP) {
+               port->ieee1284.phase = IEEE1284_PH_ECP_SETUP;
+
+               /* Event 30: Set nAutoFd low */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_AUTOFD,
+                                     PARPORT_CONTROL_AUTOFD);
+
+               /* Event 31: PError goes high. */
+               parport_wait_peripheral (port,
+                                        PARPORT_STATUS_PAPEROUT,
+                                        PARPORT_STATUS_PAPEROUT);
+               /* (Should check that this works..) */
+
+               port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+               DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+                        port->name);
+       } else switch (mode) {
+       case IEEE1284_MODE_NIBBLE:
+       case IEEE1284_MODE_BYTE:
+               port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+               break;
+       default:
+               port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+       }
+
+
+       return 0;
+#endif /* IEEE1284 support */
+}
+
+/* Acknowledge that the peripheral has data available.
+ * Events 18-20, in order to get from Reverse Idle phase
+ * to Host Busy Data Available.
+ * This will most likely be called from an interrupt.
+ * Returns zero if data was available.
+ */
+#ifdef CONFIG_PARPORT_1284
+static int parport_ieee1284_ack_data_avail (struct parport *port)
+{
+       if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+               /* Event 18 didn't happen. */
+               return -1;
+
+       /* Event 20: nAutoFd goes high. */
+       port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+       port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+       return 0;
+}
+#endif /* IEEE1284 support */
+
+/* Handle an interrupt. */
+void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs)
+{
+       struct parport *port = handle;
+       parport_ieee1284_wakeup (port);
+
+#ifdef CONFIG_PARPORT_1284
+       if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) {
+               /* An interrupt in this phase means that data
+                * is now available. */
+               DPRINTK (KERN_DEBUG "%s: Data available\n", port->name);
+               parport_ieee1284_ack_data_avail (port);
+       }
+#endif /* IEEE1284 support */
+}
+
+/* Write a block of data. */
+ssize_t parport_write (struct parport *port, const void *buffer, size_t len)
+{
+#ifndef CONFIG_PARPORT_1284
+       return port->ops->compat_write_data (port, buffer, len, 0);
+#else
+       ssize_t retval;
+       int mode = port->ieee1284.mode;
+       size_t (*fn) (struct parport *, const void *, size_t, int);
+
+       /* Ignore the device-ID-request bit. */
+       mode &= ~IEEE1284_DEVICEID;
+
+       /* Use the mode we're in. */
+       switch (mode) {
+       case IEEE1284_MODE_NIBBLE:
+               parport_negotiate (port, IEEE1284_MODE_COMPAT);
+       case IEEE1284_MODE_COMPAT:
+               DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n",
+                        port->name);
+               fn = port->ops->compat_write_data;
+               break;
+
+       case IEEE1284_MODE_EPP:
+               DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
+               fn = port->ops->epp_write_data;
+               break;
+
+       case IEEE1284_MODE_ECP:
+       case IEEE1284_MODE_ECPRLE:
+               DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
+               fn = port->ops->ecp_write_data;
+               break;
+
+       case IEEE1284_MODE_ECPSWE:
+               DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
+                        port->name);
+               /* The caller has specified that it must be emulated,
+                * even if we have ECP hardware! */
+               fn = parport_ieee1284_ecp_write_data;
+               break;
+
+       default:
+               DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
+                       port->ieee1284.mode);
+               return -ENOSYS;
+       }
+
+       retval = (*fn) (port, buffer, len, 0);
+       DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval,
+                len);
+       return retval;
+#endif /* IEEE1284 support */
+}
+
+/* Read a block of data. */
+ssize_t parport_read (struct parport *port, void *buffer, size_t len)
+{
+#ifndef CONFIG_PARPORT_1284
+       printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
+       return -ENODEV;
+#else
+       int mode = port->physport->ieee1284.mode;
+       size_t (*fn) (struct parport *, void *, size_t, int);
+
+       /* Ignore the device-ID-request bit. */
+       mode &= ~IEEE1284_DEVICEID;
+
+       /* Use the mode we're in. */
+       switch (mode) {
+       case IEEE1284_MODE_COMPAT:
+               if (parport_negotiate (port, IEEE1284_MODE_NIBBLE))
+                       return -EIO;
+       case IEEE1284_MODE_NIBBLE:
+               DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name);
+               fn = port->ops->nibble_read_data;
+               break;
+
+       case IEEE1284_MODE_BYTE:
+               DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name);
+               fn = port->ops->byte_read_data;
+               break;
+
+       case IEEE1284_MODE_EPP:
+               DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
+               fn = port->ops->epp_read_data;
+               break;
+
+       case IEEE1284_MODE_ECP:
+       case IEEE1284_MODE_ECPRLE:
+               DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
+               fn = port->ops->ecp_read_data;
+               break;
+
+       case IEEE1284_MODE_ECPSWE:
+               DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
+                        port->name);
+               fn = parport_ieee1284_ecp_read_data;
+               break;
+
+       default:
+               DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
+                        port->physport->ieee1284.mode);
+               return -ENOSYS;
+       }
+
+       return (*fn) (port, buffer, len, 0);
+#endif /* IEEE1284 support */
+}
+
+/* Set the amount of time we wait while nothing's happening. */
+long parport_set_timeout (struct pardevice *dev, long inactivity)
+{
+       long int old = dev->timeout;
+
+       dev->timeout = inactivity;
+
+       if (dev->port->physport->cad == dev)
+               parport_ieee1284_wakeup (dev->port);
+
+       return old;
 }
diff --git a/drivers/misc/parport_ieee1284_ops.c b/drivers/misc/parport_ieee1284_ops.c
new file mode 100644 (file)
index 0000000..7c4945f
--- /dev/null
@@ -0,0 +1,736 @@
+/* IEEE-1284 operations for parport.
+ *
+ * This file is for generic IEEE 1284 operations.  The idea is that
+ * they are used by the low-level drivers.  If they have a special way
+ * of doing something, they can provide their own routines (and put
+ * the function pointers in port->ops); if not, they can just use these
+ * as a fallback.
+ *
+ * Note: Make no assumptions about hardware or architecture in this file!
+ *
+ * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
+ */
+
+#include <linux/config.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef CONFIG_LP_CONSOLE
+#undef DEBUG /* Don't want a garbled console */
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+/***                                *
+ * One-way data transfer functions. *
+ *                                ***/
+
+static inline
+int polling (struct pardevice *dev)
+{
+       return dev->port->irq == PARPORT_IRQ_NONE;
+}
+
+/* Compatibility mode. */
+size_t parport_ieee1284_write_compat (struct parport *port,
+                                     const void *buffer, size_t len,
+                                     int flags)
+{
+       ssize_t count = 0;
+       const unsigned char *addr = buffer;
+       unsigned char byte;
+       struct pardevice *dev = port->physport->cad;
+       unsigned char ctl = (PARPORT_CONTROL_SELECT
+                            | PARPORT_CONTROL_INIT);
+
+       if (port->irq != PARPORT_IRQ_NONE)
+               parport_enable_irq (port);
+
+       port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+       while (count < len) {
+               long expire = jiffies + dev->timeout;
+               long wait = (HZ + 99) / 100;
+               unsigned char mask = (PARPORT_STATUS_ERROR
+                                     | PARPORT_STATUS_BUSY);
+               unsigned char val = (PARPORT_STATUS_ERROR
+                                    | PARPORT_STATUS_BUSY);
+               int i;
+
+               /* Write the character to the data lines. */
+               byte = *addr++;
+               parport_write_data (port, byte);
+               udelay (1);
+
+               /* Wait until the peripheral's ready */
+               do {
+                       /* Is the peripheral ready yet? */
+                       if (!parport_wait_peripheral (port, mask, val))
+                               /* Skip the loop */
+                               goto ready;
+
+                       /* Is the peripheral upset? */
+                       if ((parport_read_status (port) &
+                            (PARPORT_STATUS_PAPEROUT |
+                             PARPORT_STATUS_SELECT |
+                             PARPORT_STATUS_ERROR))
+                           != (PARPORT_STATUS_SELECT |
+                               PARPORT_STATUS_ERROR))
+                               /* If nFault is asserted (i.e. no
+                                * error) and PAPEROUT and SELECT are
+                                * just red herrings, give the driver
+                                * a chance to check it's happy with
+                                * that before continuing. */
+                               goto stop;
+
+                       /* Have we run out of time? */
+                       if (!time_before (jiffies, expire))
+                               break;
+
+                       /* Yield the port for a while.  If this is the
+                           first time around the loop, don't let go of
+                           the port.  This way, we find out if we have
+                           our interrupt handler called. */
+                       if (count && polling (dev)) {
+                               parport_release (dev);
+                               current->state = TASK_INTERRUPTIBLE;
+                               schedule_timeout (wait);
+                               parport_claim_or_block (dev);
+                       }
+                       else
+                               /* We must have the device claimed here */
+                               parport_wait_event (port, wait);
+
+                       /* Is there a signal pending? */
+                       if (signal_pending (current))
+                               goto stop;
+
+                       /* Wait longer next time. */
+                       wait *= 2;
+               } while (time_before (jiffies, expire));
+
+               DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name);
+               break;
+
+       ready:
+               /* Clear out previous irqs. */
+               while (!down_trylock (&port->physport->ieee1284.irq));
+
+               /* Pulse strobe. */
+               parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+               udelay (1); /* strobe */
+
+               parport_write_control (port, ctl);
+               udelay (1); /* hold */
+
+               /* Wait until it's received (up to 20us). */
+               for (i = 0; i < 20; i++) {
+                       if (!down_trylock (&port->physport->ieee1284.irq) ||
+                           !(parport_read_status (port) & PARPORT_STATUS_ACK))
+                               break;
+                       udelay (1);
+               }
+
+               count++;
+
+                /* Let another process run if it needs to. */
+               if (time_before (jiffies, expire))
+                       if (!parport_yield_blocking (dev)
+                           && current->need_resched)
+                               schedule ();
+       }
+ stop:
+       port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+       return count;
+}
+
+/* Nibble mode. */
+size_t parport_ieee1284_read_nibble (struct parport *port, 
+                                    void *buffer, size_t len,
+                                    int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+       return 0;
+#else
+       unsigned char *buf = buffer;
+       int i;
+       unsigned char byte = 0;
+
+       len *= 2; /* in nibbles */
+       for (i=0; i < len; i++) {
+               unsigned char nibble;
+
+               /* Does the error line indicate end of data? */
+               if (((i & 1) == 0) &&
+                   (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
+                       port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+                       DPRINTK (KERN_DEBUG
+                               "%s: No more nibble data (%d bytes)\n",
+                               port->name, i/2);
+
+                       /* Go to reverse idle phase. */
+                       parport_frob_control (port,
+                                             PARPORT_CONTROL_AUTOFD,
+                                             PARPORT_CONTROL_AUTOFD);
+                       port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+                       break;
+               }
+
+               /* Event 7: Set nAutoFd low. */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_AUTOFD,
+                                     PARPORT_CONTROL_AUTOFD);
+
+               /* Event 9: nAck goes low. */
+               port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+               if (parport_wait_peripheral (port,
+                                            PARPORT_STATUS_ACK, 0)) {
+                       /* Timeout -- no more data? */
+                       DPRINTK (KERN_DEBUG
+                                "%s: Nibble timeout at event 9 (%d bytes)\n",
+                                port->name, i/2);
+                       break;
+               }
+
+
+               /* Read a nibble. */
+               nibble = parport_read_status (port) >> 3;
+               nibble &= ~8;
+               if ((nibble & 0x10) == 0)
+                       nibble |= 8;
+               nibble &= 0xf;
+
+               /* Event 10: Set nAutoFd high. */
+               parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+               /* Event 11: nAck goes high. */
+               if (parport_wait_peripheral (port,
+                                            PARPORT_STATUS_ACK,
+                                            PARPORT_STATUS_ACK)) {
+                       /* Timeout -- no more data? */
+                       DPRINTK (KERN_DEBUG
+                                "%s: Nibble timeout at event 11\n",
+                                port->name);
+                       break;
+               }
+
+               if (i & 1) {
+                       /* Second nibble */
+                       byte |= nibble << 4;
+                       *buf++ = byte;
+               } else 
+                       byte = nibble;
+       }
+
+       i /= 2; /* i is now in bytes */
+
+       if (i == len) {
+               /* Read the last nibble without checking data avail. */
+               port = port->physport;
+               if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+                       port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+               else
+                       port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+       }
+
+       return i;
+#endif /* IEEE1284 support */
+}
+
+/* Byte mode. */
+size_t parport_ieee1284_read_byte (struct parport *port,
+                                  void *buffer, size_t len,
+                                  int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+       return 0;
+#else
+       unsigned char *buf = buffer;
+       ssize_t count = 0;
+
+       for (count = 0; count < len; count++) {
+               unsigned char byte;
+
+               /* Data available? */
+               if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
+                       port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+                       DPRINTK (KERN_DEBUG
+                                "%s: No more byte data (%d bytes)\n",
+                                port->name, count);
+
+                       /* Go to reverse idle phase. */
+                       parport_frob_control (port,
+                                             PARPORT_CONTROL_AUTOFD,
+                                             PARPORT_CONTROL_AUTOFD);
+                       port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+                       break;
+               }
+
+               /* Event 7: Set nAutoFd low. */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_AUTOFD,
+                                     PARPORT_CONTROL_AUTOFD);
+
+               /* Event 9: nAck goes low. */
+               port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;
+               if (parport_wait_peripheral (port,
+                                            PARPORT_STATUS_ACK,
+                                            0)) {
+                       /* Timeout -- no more data? */
+                       parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+                                                0);
+                       DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n",
+                                port->name);
+                       break;
+               }
+
+               byte = parport_read_data (port);
+               *buf++ = byte;
+
+               /* Event 10: Set nAutoFd high */
+               parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+               /* Event 11: nAck goes high. */
+               if (parport_wait_peripheral (port,
+                                            PARPORT_STATUS_ACK,
+                                            PARPORT_STATUS_ACK)) {
+                       /* Timeout -- no more data? */
+                       DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n",
+                                port->name);
+                       break;
+               }
+
+               /* Event 16: Set nStrobe low. */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_STROBE,
+                                     PARPORT_CONTROL_STROBE);
+               udelay (5);
+
+               /* Event 17: Set nStrobe high. */
+               parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+       }
+
+       if (count == len) {
+               /* Read the last byte without checking data avail. */
+               port = port->physport;
+               if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+                       port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+               else
+                       port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+       }
+
+       return count;
+#endif /* IEEE1284 support */
+}
+
+/***              *
+ * ECP Functions. *
+ *              ***/
+
+#ifdef CONFIG_PARPORT_1284
+
+static inline
+int ecp_forward_to_reverse (struct parport *port)
+{
+       int retval;
+
+       /* Event 38: Set nAutoFd low */
+       parport_frob_control (port,
+                             PARPORT_CONTROL_AUTOFD,
+                             PARPORT_CONTROL_AUTOFD);
+       parport_data_reverse (port);
+       udelay (5);
+
+       /* Event 39: Set nInit low to initiate bus reversal */
+       parport_frob_control (port,
+                             PARPORT_CONTROL_INIT,
+                             PARPORT_CONTROL_INIT);
+
+       /* Event 40: PError goes low */
+       retval = parport_wait_peripheral (port,
+                                         PARPORT_STATUS_PAPEROUT, 0);
+
+       if (!retval) {
+               DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n",
+                        port->name);
+               port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+       }
+
+       return retval;
+}
+
+static inline
+int ecp_reverse_to_forward (struct parport *port)
+{
+       int retval;
+
+       /* Event 47: Set nInit high */
+       parport_frob_control (port,
+                             PARPORT_CONTROL_INIT,
+                             PARPORT_CONTROL_INIT);
+       parport_data_reverse (port);
+
+       /* Event 49: PError goes high */
+       retval = parport_wait_peripheral (port,
+                                         PARPORT_STATUS_PAPEROUT,
+                                         PARPORT_STATUS_PAPEROUT);
+
+       if (!retval) {
+               parport_data_forward (port);
+               DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+                        port->name);
+               port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+       }
+
+       return retval;
+}
+
+#endif /* IEEE1284 support */
+
+/* ECP mode, forward channel, data. */
+size_t parport_ieee1284_ecp_write_data (struct parport *port,
+                                       const void *buffer, size_t len,
+                                       int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+       return 0;
+#else
+       const unsigned char *buf = buffer;
+       size_t written;
+       int ctl = parport_read_control (port) & ~PARPORT_CONTROL_AUTOFD;
+       int retry;
+
+       port = port->physport;
+
+       if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+               if (ecp_reverse_to_forward (port))
+                       return 0;
+
+       port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+       /* HostAck high (data, not command) */
+       parport_write_control (port, ctl);
+       for (written = 0; written < len; written++, buf++) {
+               long expire = jiffies + port->cad->timeout;
+               unsigned char byte;
+
+               byte = *buf;
+       try_again:
+               parport_write_data (port, byte);
+               parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+               udelay (5);
+               for (retry = 0; retry < 100; retry++) {
+                       if (!parport_wait_peripheral (port,
+                                                     PARPORT_STATUS_BUSY, 0))
+                               goto success;
+
+                       if (signal_pending (current)) {
+                               parport_write_control (port, ctl);
+                               break;
+                       }
+               }
+
+               /* Time for Host Transfer Recovery (page 41 of IEEE1284) */
+               DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
+
+               parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
+               udelay (50);
+               if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
+                       /* It's buggered. */
+                       parport_write_control (port, ctl);
+                       break;
+               }
+
+               parport_write_control (port, ctl);
+               udelay (50);
+               if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
+                       break;
+
+               DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
+                        port->name);
+
+               if (time_after_eq (jiffies, expire)) break;
+               goto try_again;
+       success:
+               parport_write_control (port, ctl);
+               udelay (5);
+               if (parport_wait_peripheral (port,
+                                            PARPORT_STATUS_BUSY,
+                                            PARPORT_STATUS_BUSY))
+                       /* Peripheral hasn't accepted the data. */
+                       break;
+       }
+
+       port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+       return written;
+#endif /* IEEE1284 support */
+}
+
+/* ECP mode, reverse channel, data. */
+size_t parport_ieee1284_ecp_read_data (struct parport *port,
+                                      void *buffer, size_t len, int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+       return 0;
+#else
+       struct pardevice *dev = port->cad;
+       unsigned char *buf = buffer;
+       int rle_count = 0; /* shut gcc up */
+       int rle = 0;
+       ssize_t count = 0;
+
+       port = port->physport;
+
+       if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
+               if (ecp_forward_to_reverse (port))
+                       return 0;
+
+       port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+
+       /* Set HostAck low to start accepting data. */
+       parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+                             PARPORT_CONTROL_AUTOFD);
+       while (count < len) {
+               long expire = jiffies + dev->timeout;
+               unsigned char byte;
+               int command;
+
+               /* Event 43: Peripheral sets nAck low. It can take as
+                   long as it wants. */
+               while (parport_wait_peripheral (port,
+                                               PARPORT_STATUS_ACK,
+                                               PARPORT_STATUS_ACK)) {
+                       /* The peripheral hasn't given us data in
+                          35ms.  If we have data to give back to the
+                          caller, do it now. */
+                       if (count)
+                               goto out;
+
+                       /* If we've used up all the time we were allowed,
+                          give up altogether. */
+                       if (!time_before (jiffies, expire))
+                               goto out;
+
+                       /* Yield the port for a while. */
+                       if (count && polling (dev)) {
+                               parport_release (dev);
+                               current->state = TASK_INTERRUPTIBLE;
+                               schedule_timeout ((HZ + 99) / 25);
+                               parport_claim_or_block (dev);
+                       }
+                       else
+                               /* We must have the device claimed here. */
+                               parport_wait_event (port, (HZ + 99) / 25);
+
+                       /* Is there a signal pending? */
+                       if (signal_pending (current))
+                               goto out;
+               }
+
+               /* Is this a command? */
+               if (rle)
+                       /* The last byte was a run-length count, so
+                           this can't be as well. */
+                       command = 0;
+               else
+                       command = (parport_read_status (port) &
+                                  PARPORT_STATUS_BUSY) ? 1 : 0;
+
+               /* Read the data. */
+               byte = parport_read_data (port);
+
+               /* If this is a channel command, rather than an RLE
+                   command or a normal data byte, don't accept it. */
+               if (command) {
+                       if (byte & 0x80) {
+                               DPRINTK (KERN_DEBUG "%s: stopping short at "
+                                        "channel command (%02x)\n",
+                                        port->name, byte);
+                               goto out;
+                       }
+                       else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE)
+                               DPRINTK (KERN_DEBUG "%s: device illegally "
+                                        "using RLE; accepting anyway\n",
+                                        port->name);
+
+                       rle_count = byte + 1;
+
+                       /* Are we allowed to read that many bytes? */
+                       if (rle_count > (len - count)) {
+                               DPRINTK (KERN_DEBUG "%s: leaving %d RLE bytes "
+                                        "for next time\n", port->name,
+                                        rle_count);
+                               break;
+                       }
+
+                       rle = 1;
+               }
+
+               /* Event 44: Set HostAck high, acknowledging handshake. */
+               parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+               /* Event 45: The peripheral has 35ms to set nAck high. */
+               if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
+                       /* It's gone wrong.  Return what data we have
+                           to the caller. */
+                       DPRINTK (KERN_DEBUG "ECP read timed out at 45\n");
+
+                       if (command)
+                               printk (KERN_WARNING
+                                       "%s: command ignored (%02x)\n",
+                                       port->name, byte);
+
+                       break;
+               }
+
+               /* Event 46: Set HostAck low and accept the data. */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_AUTOFD,
+                                     PARPORT_CONTROL_AUTOFD);
+
+               /* If we just read a run-length count, fetch the data. */
+               if (command)
+                       continue;
+
+               /* If this is the byte after a run-length count, decompress. */
+               if (rle) {
+                       rle = 0;
+                       memset (buf, byte, rle_count);
+                       buf += rle_count;
+                       count += rle_count;
+                       DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n",
+                                port->name, rle_count);
+               }
+               else
+                       /* Normal data byte. */
+                       *buf++ = byte, count++;
+       }
+
+ out:
+       return count;
+#endif /* IEEE1284 support */
+}
+
+/* ECP mode, forward channel, commands. */
+size_t parport_ieee1284_ecp_write_addr (struct parport *port,
+                                       const void *buffer, size_t len,
+                                       int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+       return 0;
+#else
+       const unsigned char *buf = buffer;
+       size_t written;
+       int ctl = parport_read_control (port) | PARPORT_CONTROL_AUTOFD;
+       int retry;
+
+       port = port->physport;
+
+       if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+               if (ecp_reverse_to_forward (port))
+                       return 0;
+
+       port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+       /* HostAck low (command, not data) */
+       parport_write_control (port, ctl);
+       for (written = 0; written < len; written++, buf++) {
+               long expire = jiffies + port->cad->timeout;
+               unsigned char byte;
+
+               byte = *buf;
+       try_again:
+               parport_write_data (port, byte);
+               parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+               udelay (5);
+               for (retry = 0; retry < 100; retry++) {
+                       if (!parport_wait_peripheral (port,
+                                                     PARPORT_STATUS_BUSY, 0))
+                               goto success;
+
+                       if (signal_pending (current)) {
+                               parport_write_control (port, ctl);
+                               break;
+                       }
+               }
+
+               /* Time for Host Transfer Recovery (page 41 of IEEE1284) */
+               DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
+
+               parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
+               udelay (50);
+               if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
+                       /* It's buggered. */
+                       parport_write_control (port, ctl);
+                       break;
+               }
+
+               parport_write_control (port, ctl);
+               udelay (50);
+               if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
+                       break;
+
+               DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
+                        port->name);
+
+               if (time_after_eq (jiffies, expire)) break;
+               goto try_again;
+       success:
+               parport_write_control (port, ctl);
+               udelay (5);
+               if (parport_wait_peripheral (port,
+                                            PARPORT_STATUS_BUSY,
+                                            PARPORT_STATUS_BUSY))
+                       /* Peripheral hasn't accepted the data. */
+                       break;
+       }
+
+       port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+       return written;
+#endif /* IEEE1284 support */
+}
+
+/***              *
+ * EPP functions. *
+ *              ***/
+
+/* EPP mode, forward channel, data. */
+size_t parport_ieee1284_epp_write_data (struct parport *port,
+                                       const void *buffer, size_t len,
+                                       int flags)
+{
+       return 0; /* FIXME */
+}
+
+/* EPP mode, reverse channel, data. */
+size_t parport_ieee1284_epp_read_data (struct parport *port,
+                                      void *buffer, size_t len,
+                                      int flags)
+{
+       return 0; /* FIXME */
+}
+
+/* EPP mode, forward channel, addresses. */
+size_t parport_ieee1284_epp_write_addr (struct parport *port,
+                                       const void *buffer, size_t len,
+                                       int flags)
+{
+       return 0; /* FIXME */
+}
+
+/* EPP mode, reverse channel, addresses. */
+size_t parport_ieee1284_epp_read_addr (struct parport *port,
+                                      void *buffer, size_t len,
+                                      int flags)
+{
+       return 0; /* FIXME */
+}
index c250c77a7bec53a1215675da70066e5deb03f6e9..974dcf7253fa41cdb8a4ecc65a91cdf0ef5a85fd 100644 (file)
@@ -22,7 +22,7 @@
 static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
 static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
 static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
-static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_AUTO };
+static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
 
 extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma);
 extern int parport_ax_init(void);
@@ -119,10 +119,7 @@ __initfunc(int parport_init(void))
        if (io[0] == PARPORT_DISABLE) 
                return 1;
 
-#ifdef CONFIG_PNP_PARPORT
-       parport_probe_hook = &parport_probe_one;
-#endif
-#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_SYSCTL
        parport_default_proc_register ();
 #endif
 
@@ -161,13 +158,42 @@ EXPORT_SYMBOL(parport_unregister_driver);
 EXPORT_SYMBOL(parport_register_device);
 EXPORT_SYMBOL(parport_unregister_device);
 EXPORT_SYMBOL(parport_enumerate);
-EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
+EXPORT_SYMBOL(parport_negotiate);
+EXPORT_SYMBOL(parport_write);
+EXPORT_SYMBOL(parport_read);
+EXPORT_SYMBOL(parport_ieee1284_wakeup);
 EXPORT_SYMBOL(parport_wait_peripheral);
+EXPORT_SYMBOL(parport_wait_event);
+EXPORT_SYMBOL(parport_set_timeout);
+EXPORT_SYMBOL(parport_ieee1284_interrupt);
+EXPORT_SYMBOL(parport_ieee1284_ecp_write_data);
+EXPORT_SYMBOL(parport_ieee1284_ecp_read_data);
+EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr);
+EXPORT_SYMBOL(parport_ieee1284_write_compat);
+EXPORT_SYMBOL(parport_ieee1284_read_nibble);
+EXPORT_SYMBOL(parport_ieee1284_read_byte);
+EXPORT_SYMBOL(parport_ieee1284_epp_write_data);
+EXPORT_SYMBOL(parport_ieee1284_epp_read_data);
+EXPORT_SYMBOL(parport_ieee1284_epp_write_addr);
+EXPORT_SYMBOL(parport_ieee1284_epp_read_addr);
 EXPORT_SYMBOL(parport_proc_register);
 EXPORT_SYMBOL(parport_proc_unregister);
-EXPORT_SYMBOL(parport_probe_hook);
+EXPORT_SYMBOL(parport_device_proc_register);
+EXPORT_SYMBOL(parport_device_proc_unregister);
+EXPORT_SYMBOL(parport_default_proc_register);
+EXPORT_SYMBOL(parport_default_proc_unregister);
 EXPORT_SYMBOL(parport_parse_irqs);
 EXPORT_SYMBOL(parport_parse_dmas);
+#ifdef CONFIG_PARPORT_12843
+EXPORT_SYMBOL(parport_open);
+EXPORT_SYMBOL(parport_close);
+EXPORT_SYMBOL(parport_device_id);
+EXPORT_SYMBOL(parport_device_num);
+EXPORT_SYMBOL(parport_device_coords);
+EXPORT_SYMBOL(parport_daisy_deselect_all);
+EXPORT_SYMBOL(parport_daisy_select);
+EXPORT_SYMBOL(parport_daisy_init);
+#endif
 
 void inc_parport_count(void)
 {
index 63b67f3baf25e4071766bd3869cd29834e99fe28..bfba506ea3c3b03ac64b2c2ab8045c0401c91a2b 100644 (file)
@@ -9,6 +9,7 @@
  * based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
  *
  * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
+ * DMA support - Bert De Jonghe <bert@sophis.be>
  * Better EPP probing - Carlos Henrique Bauer <chbauer@acm.org>
  */
 
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 #include <linux/pci.h>
+#include <linux/sysctl.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
+#include <asm/uaccess.h>
 
 #include <linux/parport.h>
 #include <linux/parport_pc.h>
    than PARPORT_MAX (in <linux/parport.h>).  */
 #define PARPORT_PC_MAX_PORTS  8
 
+/* ECR modes */
+#define ECR_SPP 00
+#define ECR_PS2 01
+#define ECR_PPF 02
+#define ECR_ECP 03
+#define ECR_EPP 04
+#define ECR_VND 05
+#define ECR_TST 06
+#define ECR_CNF 07
+
 static int user_specified __initdata = 0;
 
+/* frob_control, but for ECR */
+static void frob_econtrol (struct parport *pb, unsigned char m,
+                          unsigned char v)
+{
+       outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Safely change the mode bits in the ECR */
+static int change_mode(struct parport *p, int m)
+{
+       const struct parport_pc_private *priv = p->physport->private_data;
+       int ecr = ECONTROL(p);
+       unsigned char oecr;
+       int mode;
+
+       if (!priv->ecr) {
+               printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
+               return 0;
+       }
+
+       /* Bits <7:5> contain the mode. */
+       oecr = inb (ecr);
+       mode = (oecr >> 5) & 0x7;
+       if (mode == m) return 0;
+       if (mode && m)
+               /* We have to go through mode 000 */
+               change_mode (p, ECR_SPP);
+
+       if (m < 2 && !(parport_read_control (p) & 0x20)) {
+               /* This mode resets the FIFO, so we may
+                * have to wait for it to drain first. */
+               long expire = jiffies + p->physport->cad->timeout;
+               int counter;
+               switch (mode) {
+               case ECR_PPF: /* Parallel Port FIFO mode */
+               case ECR_ECP: /* ECP Parallel Port mode */
+                       /* Busy wait for 200us */
+                       for (counter = 0; counter < 40; counter++) {
+                               if (inb (ECONTROL (p)) & 0x01)
+                                       break;
+                               if (signal_pending (current)) break;
+                               udelay (5);
+                       }
+
+                       /* Poll slowly. */
+                       while (!(inb (ECONTROL (p)) & 0x01)) {
+                               if (time_after_eq (jiffies, expire))
+                                       /* The FIFO is stuck. */
+                                       return -EBUSY;
+                               current->state = TASK_INTERRUPTIBLE;
+                               schedule_timeout ((HZ + 99) / 100);
+                               if (signal_pending (current))
+                                       break;
+                       }
+               }
+       }
+
+       /* Set the mode. */
+       oecr &= ~(7 << 5);
+       oecr |= m << 5;
+       outb (oecr, ecr);
+       return 0;
+}
+
+/* Find FIFO lossage; FIFO is reset */
+static int get_fifo_residue (struct parport *p)
+{
+       int residue;
+       int cnfga;
+       const struct parport_pc_private *priv = p->physport->private_data;
+
+       /* Prevent further data transfer. */
+       parport_frob_control (p,
+                             PARPORT_CONTROL_STROBE,
+                             PARPORT_CONTROL_STROBE);
+
+       /* Adjust for the contents of the FIFO. */
+       for (residue = priv->fifo_depth; ; residue--) {
+               if (inb (ECONTROL (p)) & 0x2)
+                               /* Full up. */
+                       break;
+
+               outb (0, FIFO (p));
+       }
+
+       printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
+               residue);
+
+       /* Reset the FIFO. */
+       frob_econtrol (p, 0xe0, 0x20);
+       parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
+
+       /* Now change to config mode and clean up. FIXME */
+       frob_econtrol (p, 0xe0, 0xe0);
+       cnfga = inb (CONFIGA (p));
+       printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
+
+       if (!(cnfga & (1<<2))) {
+               printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
+               residue++;
+       }
+
+       /* Don't care about partial PWords until support is added for
+        * PWord != 1 byte. */
+
+       /* Back to PS2 mode. */
+       frob_econtrol (p, 0xe0, 0x20);
+
+       return residue;
+}
+
+#endif /* IEEE 1284 support */
+
 /*
  * Clear TIMEOUT BIT in EPP MODE
+ *
+ * This is also used in SPP detection.
  */
-int parport_pc_epp_clear_timeout(struct parport *pb)
+static int clear_epp_timeout(struct parport *pb)
 {
        unsigned char r;
 
@@ -72,187 +201,719 @@ int parport_pc_epp_clear_timeout(struct parport *pb)
        /* To clear timeout some chips require double read */
        parport_pc_read_status(pb);
        r = parport_pc_read_status(pb);
-       parport_pc_write_status(pb, r | 0x01); /* Some reset by writing 1 */
-       parport_pc_write_status(pb, r & 0xfe); /* Others by writing 0 */
+       outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */
+       outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */
        r = parport_pc_read_status(pb);
 
        return !(r & 0x01);
 }
 
+/*
+ * Access functions.
+ *
+ * These aren't static because they may be used by the parport_xxx_yyy
+ * macros.  extern __inline__ versions of several of these are in
+ * parport_pc.h.
+ */
+
 static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        parport_generic_irq(irq, (struct parport *) dev_id, regs);
 }
 
-void parport_pc_write_epp(struct parport *p, unsigned char d)
+void parport_pc_write_data(struct parport *p, unsigned char d)
 {
-       outb(d, EPPDATA(p));
+       outb (d, DATA (p));
 }
 
-unsigned char parport_pc_read_epp(struct parport *p)
+unsigned char parport_pc_read_data(struct parport *p)
 {
-       return inb(EPPDATA(p));
+       return inb (DATA (p));
 }
 
-void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
+unsigned char __frob_control (struct parport *p, unsigned char mask,
+                             unsigned char val)
 {
-       outb(d, EPPADDR(p));
+       struct parport_pc_private *priv = p->physport->private_data;
+       unsigned char ctr = priv->ctr;
+       ctr = (ctr & ~mask) ^ val;
+       ctr &= priv->ctr_writable; /* only write writable bits. */
+       outb (ctr, CONTROL (p));
+       return priv->ctr = ctr; /* update soft copy */
 }
 
-unsigned char parport_pc_read_epp_addr(struct parport *p)
+void parport_pc_write_control(struct parport *p, unsigned char d)
 {
-       return inb(EPPADDR(p));
-}
+       const unsigned char wm = (PARPORT_CONTROL_STROBE |
+                                 PARPORT_CONTROL_AUTOFD |
+                                 PARPORT_CONTROL_INIT |
+                                 PARPORT_CONTROL_SELECT);
+
+       /* Take this out when drivers have adapted to the newer interface. */
+       if (d & 0x20) {
+                       printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+                                       p->name, p->cad->name);
+                       parport_pc_data_reverse (p);
+       }
 
-int parport_pc_check_epp_timeout(struct parport *p)
-{
-       if (!(inb(STATUS(p)) & 1))
-               return 0;
-       parport_pc_epp_clear_timeout(p);
-       return 1;
+       __frob_control (p, wm, d & wm);
 }
 
-unsigned char parport_pc_read_configb(struct parport *p)
+unsigned char parport_pc_read_control(struct parport *p)
 {
-       return inb(CONFIGB(p));
+       const struct parport_pc_private *priv = p->physport->private_data;
+       return priv->ctr; /* Use soft copy */
 }
 
-void parport_pc_write_data(struct parport *p, unsigned char d)
+unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
+                                      unsigned char val)
 {
-       outb(d, DATA(p));
+       const unsigned char wm = (PARPORT_CONTROL_STROBE |
+                                 PARPORT_CONTROL_AUTOFD |
+                                 PARPORT_CONTROL_INIT |
+                                 PARPORT_CONTROL_SELECT);
+
+       /* Take this out when drivers have adapted to the newer interface. */
+       if (mask & 0x20) {
+                       printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+                                       p->name, p->cad->name);
+                       parport_pc_data_reverse (p);
+       }
+
+       /* Restrict mask and val to control lines. */
+       mask &= wm;
+       val &= wm;
+
+       return __frob_control (p, mask, val);
 }
 
-unsigned char parport_pc_read_data(struct parport *p)
+unsigned char parport_pc_read_status(struct parport *p)
 {
-       return inb(DATA(p));
+       return inb (STATUS (p));
 }
 
-void parport_pc_write_control(struct parport *p, unsigned char d)
+void parport_pc_disable_irq(struct parport *p)
 {
-       struct parport_pc_private *priv = p->private_data;
-       priv->ctr = d;/* update soft copy */
-       outb(d, CONTROL(p));
+       __frob_control (p, 0x10, 0);
 }
 
-unsigned char parport_pc_read_control(struct parport *p)
+void parport_pc_enable_irq(struct parport *p)
 {
-       struct parport_pc_private *priv = p->private_data;
-       return priv->ctr;
+       __frob_control (p, 0x10, 0x10);
 }
 
-unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
+void parport_pc_data_forward (struct parport *p)
 {
-       struct parport_pc_private *priv = p->private_data;
-       unsigned char ctr = priv->ctr;
-       ctr = (ctr & ~mask) ^ val;
-       outb (ctr, CONTROL(p));
-       return priv->ctr = ctr; /* update soft copy */
+       __frob_control (p, 0x20, 0);
 }
 
-void parport_pc_write_status(struct parport *p, unsigned char d)
+void parport_pc_data_reverse (struct parport *p)
 {
-       outb(d, STATUS(p));
+       __frob_control (p, 0x20, 0x20);
 }
 
-unsigned char parport_pc_read_status(struct parport *p)
+void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
 {
-       return inb(STATUS(p));
+       struct parport_pc_private *priv = dev->port->physport->private_data;
+       priv->ctr = s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+       s->u.pc.ecr = 0x24;
 }
 
-void parport_pc_write_econtrol(struct parport *p, unsigned char d)
+void parport_pc_save_state(struct parport *p, struct parport_state *s)
 {
-       outb(d, ECONTROL(p));
+       const struct parport_pc_private *priv = p->physport->private_data;
+       s->u.pc.ctr = inb (CONTROL (p));
+       if (priv->ecr)
+               s->u.pc.ecr = inb (ECONTROL (p));
 }
 
-unsigned char parport_pc_read_econtrol(struct parport *p)
+void parport_pc_restore_state(struct parport *p, struct parport_state *s)
 {
-       return inb(ECONTROL(p));
+       const struct parport_pc_private *priv = p->physport->private_data;
+       outb (s->u.pc.ctr, CONTROL (p));
+       if (priv->ecr)
+               outb (s->u.pc.ecr, ECONTROL (p));
 }
 
-unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask,  unsigned char val)
+#ifdef CONFIG_PARPORT_1284
+static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
+                                       size_t length, int flags)
 {
-       unsigned char old = inb(ECONTROL(p));
-       outb(((old & ~mask) ^ val), ECONTROL(p));
-       return old;
+       size_t got = 0;
+       for (; got < length; got++) {
+               *((char*)buf)++ = inb (EPPDATA(port));
+               if (inb (STATUS(port)) & 0x01) {
+                       clear_epp_timeout (port);
+                       break;
+               }
+       }
+
+       return got;
 }
 
-void parport_pc_change_mode(struct parport *p, int m)
+static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,
+                                        size_t length, int flags)
 {
-       /* FIXME */
+       size_t written = 0;
+       for (; written < length; written++) {
+               outb (*((char*)buf)++, EPPDATA(port));
+               if (inb (STATUS(port)) & 0x01) {
+                       clear_epp_timeout (port);
+                       break;
+               }
+       }
+
+       return written;
 }
 
-void parport_pc_write_fifo(struct parport *p, unsigned char v)
+static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,
+                                       size_t length, int flags)
 {
-       outb (v, CONFIGA(p));
+       size_t got = 0;
+       for (; got < length; got++) {
+               *((char*)buf)++ = inb (EPPADDR (port));
+               if (inb (STATUS (port)) & 0x01) {
+                       clear_epp_timeout (port);
+                       break;
+               }
+       }
+
+       return got;
 }
 
-unsigned char parport_pc_read_fifo(struct parport *p)
+static size_t parport_pc_epp_write_addr (struct parport *port,
+                                        const void *buf, size_t length,
+                                        int flags)
 {
-       return inb (CONFIGA(p));
+       size_t written = 0;
+       for (; written < length; written++) {
+               outb (*((char*)buf)++, EPPADDR (port));
+               if (inb (STATUS (port)) & 0x01) {
+                       clear_epp_timeout (port);
+                       break;
+               }
+       }
+
+       return written;
 }
 
-void parport_pc_disable_irq(struct parport *p)
+static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf,
+                                          size_t length, int flags)
 {
-       parport_pc_frob_control(p, 0x10, 0);
+       size_t got;
+
+       frob_econtrol (port, 0xe0, ECR_EPP << 5);
+       got = parport_pc_epp_read_data (port, buf, length, flags);
+       frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+       return got;
 }
 
-void parport_pc_enable_irq(struct parport *p)
+static size_t parport_pc_ecpepp_write_data (struct parport *port,
+                                           const void *buf, size_t length,
+                                           int flags)
 {
-       parport_pc_frob_control(p, 0x10, 0x10);
+       size_t written;
+
+       frob_econtrol (port, 0xe0, ECR_EPP << 5);
+       written = parport_pc_epp_write_data (port, buf, length, flags);
+       frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+       return written;
 }
 
-void parport_pc_init_state(struct parport_state *s)
+static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf,
+                                          size_t length, int flags)
 {
-       s->u.pc.ctr = 0xc;
-       s->u.pc.ecr = 0x0;
+       size_t got;
+
+       frob_econtrol (port, 0xe0, ECR_EPP << 5);
+       got = parport_pc_epp_read_addr (port, buf, length, flags);
+       frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+       return got;
 }
 
-void parport_pc_save_state(struct parport *p, struct parport_state *s)
+static size_t parport_pc_ecpepp_write_addr (struct parport *port,
+                                           const void *buf, size_t length,
+                                           int flags)
 {
-       s->u.pc.ctr = parport_pc_read_control(p);
-       if (p->modes & PARPORT_MODE_PCECR)
-               s->u.pc.ecr = parport_pc_read_econtrol(p);
+       size_t written;
+
+       frob_econtrol (port, 0xe0, ECR_EPP << 5);
+       written = parport_pc_epp_write_addr (port, buf, length, flags);
+       frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+       return written;
 }
+#endif /* IEEE 1284 support */
 
-void parport_pc_restore_state(struct parport *p, struct parport_state *s)
+#ifdef CONFIG_PARPORT_PC_FIFO
+static size_t parport_pc_fifo_write_block_pio (struct parport *port,
+                                              const void *buf, size_t length)
 {
-       parport_pc_write_control(p, s->u.pc.ctr);
-       if (p->modes & PARPORT_MODE_PCECR)
-               parport_pc_write_econtrol(p, s->u.pc.ecr);
+       int ret = 0;
+       const unsigned char *bufp = buf;
+       size_t left = length;
+       long expire = jiffies + port->physport->cad->timeout;
+       const int fifo = FIFO (port);
+       int poll_for = 8; /* 80 usecs */
+       const struct parport_pc_private *priv = port->physport->private_data;
+       const int fifo_depth = priv->fifo_depth;
+
+       port = port->physport;
+
+       /* We don't want to be interrupted every character. */
+       parport_pc_disable_irq (port);
+       frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+
+       /* Forward mode. */
+       parport_pc_data_forward (port);
+
+       while (left) {
+               unsigned char byte;
+               unsigned char ecrval = inb (ECONTROL (port));
+               int i = 0;
+
+               if (current->need_resched && time_before (jiffies, expire))
+                       /* Can't yield the port. */
+                       schedule ();
+
+               /* Anyone else waiting for the port? */
+               if (port->waithead) {
+                       printk (KERN_DEBUG "Somebody wants the port\n");
+                       break;
+               }
+
+               if (ecrval & 0x02) {
+                       /* FIFO is full. Wait for interrupt. */
+
+                       /* Clear serviceIntr */
+                       outb (ecrval & ~(1<<2), ECONTROL (port));
+               false_alarm:
+                       ret = parport_wait_event (port, HZ);
+                       if (ret < 0) break;
+                       ret = 0;
+                       if (!time_before (jiffies, expire)) {
+                               /* Timed out. */
+                               printk (KERN_DEBUG "Timed out\n");
+                               break;
+                       }
+                       ecrval = inb (ECONTROL (port));
+                       if (!(ecrval & (1<<2))) {
+                               if (current->need_resched &&
+                                   time_before (jiffies, expire))
+                                       schedule ();
+
+                               goto false_alarm;
+                       }
+
+                       continue;
+               }
+
+               /* Can't fail now. */
+               expire = jiffies + port->cad->timeout;
+
+       poll:
+               if (signal_pending (current))
+                       break;
+
+               if (ecrval & 0x01) {
+                       /* FIFO is empty. Blast it full. */
+                       const int n = left < fifo_depth ? left : fifo_depth;
+                       outsb (fifo, bufp, n);
+                       bufp += n;
+                       left -= n;
+
+                       /* Adjust the poll time. */
+                       if (i < (poll_for - 2)) poll_for--;
+                       continue;
+               } else if (i++ < poll_for) {
+                       udelay (10);
+                       ecrval = inb (ECONTROL (port));
+                       goto poll;
+               }
+
+               /* Half-full (call me an optimist) */
+               byte = *bufp++;
+               outb (byte, fifo);
+               left--;
+        }
+
+       return length - left;
 }
 
-size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length)
+static size_t parport_pc_fifo_write_block_dma (struct parport *port,
+                                              const void *buf, size_t length)
 {
-       size_t got = 0;
-       for (; got < length; got++) {
-               *((char*)buf)++ = inb (EPPDATA(p));
-               if (inb (STATUS(p)) & 0x01)
+       int ret = 0;
+       unsigned long dmaflag;
+       size_t left  = length;
+       const struct parport_pc_private *priv = port->physport->private_data;
+
+       port = port->physport;
+
+       /* We don't want to be interrupted every character. */
+       parport_pc_disable_irq (port);
+       frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+
+       /* Forward mode. */
+       parport_pc_data_forward (port);
+
+       while (left) {
+               long expire = jiffies + port->physport->cad->timeout;
+
+               size_t count = left;
+
+               if (count > PAGE_SIZE)
+                       count = PAGE_SIZE;
+
+               memcpy(priv->dma_buf, buf, count);
+
+               dmaflag = claim_dma_lock();
+               disable_dma(port->dma);
+               clear_dma_ff(port->dma);
+               set_dma_mode(port->dma, DMA_MODE_WRITE);
+               set_dma_addr(port->dma, virt_to_bus((volatile char *) priv->dma_buf));
+               set_dma_count(port->dma, count);
+
+               /* Set DMA mode */
+               frob_econtrol (port, 1<<3, 1<<3);
+
+               /* Clear serviceIntr */
+               frob_econtrol (port, 1<<2, 0);
+
+               enable_dma(port->dma);
+               release_dma_lock(dmaflag);
+
+               /* assume DMA will be successful */
+               left -= count;
+               buf  += count;
+
+               /* Wait for interrupt. */
+       false_alarm:
+               ret = parport_wait_event (port, HZ);
+               if (ret < 0) break;
+               ret = 0;
+               if (!time_before (jiffies, expire)) {
+                       /* Timed out. */
+                       printk (KERN_DEBUG "Timed out\n");
+                       break;
+               }
+               /* Is serviceIntr set? */
+               if (!(inb (ECONTROL (port)) & (1<<2))) {
+                       if (current->need_resched)
+                               schedule ();
+
+                       goto false_alarm;
+               }
+
+               dmaflag = claim_dma_lock();
+               disable_dma(port->dma);
+               clear_dma_ff(port->dma);
+               count = get_dma_residue(port->dma);
+               release_dma_lock(dmaflag);
+
+               if (current->need_resched)
+                       /* Can't yield the port. */
+                       schedule ();
+
+               /* Anyone else waiting for the port? */
+               if (port->waithead) {
+                       printk (KERN_DEBUG "Somebody wants the port\n");
                        break;
+               }
+
+               /* update for possible DMA residue ! */
+               buf  -= count;
+               left += count;
        }
-       return got;
+
+       /* Maybe got here through break, so adjust for DMA residue! */
+       dmaflag = claim_dma_lock();
+       disable_dma(port->dma);
+       clear_dma_ff(port->dma);
+       left += get_dma_residue(port->dma);
+       release_dma_lock(dmaflag);
+
+       /* Turn off DMA mode */
+       frob_econtrol (port, 1<<3, 0);
+
+       return length - left;
 }
 
-size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length)
+/* Parallel Port FIFO mode (ECP chipsets) */
+size_t parport_pc_compat_write_block_pio (struct parport *port,
+                                         const void *buf, size_t length,
+                                         int flags)
 {
-       size_t written = 0;
-       for (; written < length; written++) {
-               outb (*((char*)buf)++, EPPDATA(p));
-               if (inb (STATUS(p)) & 0x01)
-                       break;
+       size_t written;
+
+       /* Special case: a timeout of zero means we cannot call schedule(). */
+       if (!port->physport->cad->timeout)
+               return parport_ieee1284_write_compat (port, buf,
+                                                     length, flags);
+
+       /* Set up parallel port FIFO mode.*/
+       change_mode (port, ECR_PPF); /* Parallel port FIFO */
+       parport_pc_data_forward (port);
+       port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+       /* Write the data to the FIFO. */
+       if (port->dma != PARPORT_DMA_NONE)
+               written = parport_pc_fifo_write_block_dma (port, buf, length);
+       else
+               written = parport_pc_fifo_write_block_pio (port, buf, length);
+
+       /* Finish up. */
+       if (change_mode (port, ECR_PS2) == -EBUSY) {
+               const struct parport_pc_private *priv = 
+                       port->physport->private_data;
+
+               printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+
+               /* Prevent further data transfer. */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_STROBE,
+                                     PARPORT_CONTROL_STROBE);
+
+               /* Adjust for the contents of the FIFO. */
+               for (written -= priv->fifo_depth; ; written++) {
+                       if (inb (ECONTROL (port)) & 0x2)
+                               /* Full up. */
+                               break;
+
+                       outb (0, FIFO (port));
+               }
+
+               /* Reset the FIFO. */
+               frob_econtrol (port, 0xe0, 0);
+
+               /* De-assert strobe. */
+               parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
        }
+
+       parport_wait_peripheral (port,
+                                PARPORT_STATUS_BUSY,
+                                PARPORT_STATUS_BUSY);
+       port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
        return written;
 }
 
-int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle)
+/* ECP */
+#ifdef CONFIG_PARPORT_1284
+size_t parport_pc_ecp_write_block_pio (struct parport *port,
+                                      const void *buf, size_t length,
+                                      int flags)
 {
-       return -ENOSYS; /* FIXME */
+       size_t written;
+
+       /* Special case: a timeout of zero means we cannot call schedule(). */
+       if (!port->physport->cad->timeout)
+               return parport_ieee1284_ecp_write_data (port, buf,
+                                                       length, flags);
+
+       /* Switch to forward mode if necessary. */
+       if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
+               /* Event 47: Set nInit high. */
+               parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+
+               /* Event 40: PError goes high. */
+               parport_wait_peripheral (port,
+                                        PARPORT_STATUS_PAPEROUT,
+                                        PARPORT_STATUS_PAPEROUT);
+       }
+
+       /* Set up ECP parallel port mode.*/
+       change_mode (port, ECR_ECP); /* ECP FIFO */
+       parport_pc_data_forward (port);
+       port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+       /* Write the data to the FIFO. */
+       if (port->dma != PARPORT_DMA_NONE)
+               written = parport_pc_fifo_write_block_dma (port, buf, length);
+       else
+               written = parport_pc_fifo_write_block_pio (port, buf, length);
+
+       /* Finish up. */
+       if (change_mode (port, ECR_PS2) == -EBUSY) {
+               const struct parport_pc_private *priv =
+                       port->physport->private_data;
+
+               printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+
+               /* Prevent further data transfer. */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_STROBE,
+                                     PARPORT_CONTROL_STROBE);
+
+               /* Adjust for the contents of the FIFO. */
+               for (written -= priv->fifo_depth; ; written++) {
+                       if (inb (ECONTROL (port)) & 0x2)
+                               /* Full up. */
+                               break;
+
+                       outb (0, FIFO (port));
+               }
+
+               /* Reset the FIFO. */
+               frob_econtrol (port, 0xe0, 0);
+               parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+
+               /* Host transfer recovery. */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_INIT,
+                                     PARPORT_CONTROL_INIT);
+               parport_pc_data_reverse (port);
+               parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+               parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+               parport_wait_peripheral (port,
+                                        PARPORT_STATUS_PAPEROUT,
+                                        PARPORT_STATUS_PAPEROUT);
+       }
+
+       parport_wait_peripheral (port,
+                                PARPORT_STATUS_BUSY, 
+                                PARPORT_STATUS_BUSY);
+       port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+       return written;
 }
 
-int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle)
+size_t parport_pc_ecp_read_block_pio (struct parport *port,
+                                     void *buf, size_t length, int flags)
 {
-       return -ENOSYS; /* FIXME */
+       size_t left = length;
+       size_t fifofull;
+       const int fifo = FIFO(port);
+       const struct parport_pc_private *priv = port->physport->private_data;
+       const int fifo_depth = priv->fifo_depth;
+       char *bufp = buf;
+
+       port = port->physport;
+
+       /* Special case: a timeout of zero means we cannot call schedule(). */
+       if (!port->cad->timeout)
+               return parport_ieee1284_ecp_read_data (port, buf,
+                                                      length, flags);
+
+       fifofull = fifo_depth;
+       if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE)
+               /* If the peripheral is allowed to send RLE compressed
+                * data, it is possible for a byte to expand to 128
+                * bytes in the FIFO. */
+               fifofull = 128;
+
+       /* If the caller wants less than a full FIFO's worth of data,
+        * go through software emulation.  Otherwise we may have to through
+        * away data. */
+       if (length < fifofull)
+               return parport_ieee1284_ecp_read_data (port, buf,
+                                                      length, flags);
+
+       /* Switch to reverse mode if necessary. */
+       if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
+               /* Event 38: Set nAutoFd low */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_AUTOFD,
+                                     PARPORT_CONTROL_AUTOFD);
+               parport_pc_data_reverse (port);
+               udelay (5);
+
+               /* Event 39: Set nInit low to initiate bus reversal */
+               parport_frob_control (port,
+                                     PARPORT_CONTROL_INIT,
+                                     PARPORT_CONTROL_INIT);
+
+               /* Event 40: PError goes low */
+               parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+       }
+
+       /* Set up ECP parallel port mode.*/
+       change_mode (port, ECR_ECP); /* ECP FIFO */
+       parport_pc_data_reverse (port);
+       port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+
+       /* Do the transfer. */
+       while (left > fifofull) {
+               int ret;
+               long int expire = jiffies + port->cad->timeout;
+               unsigned char ecrval = inb (ECONTROL (port));
+
+               if (current->need_resched && time_before (jiffies, expire))
+                       /* Can't yield the port. */
+                       schedule ();
+
+               /* At this point, the FIFO may already be full.
+                * Ideally, we'd be able to tell the port to hold on
+                * for a second while we empty the FIFO, and we'd be
+                * able to ensure that no data is lost.  I'm not sure
+                * that's the case. :-(  It might be that you can play
+                * games with STB, as in the forward case; someone should
+                * look at a datasheet. */
+
+               if (ecrval & 0x01) {
+                       /* FIFO is empty. Wait for interrupt. */
+
+                       /* Anyone else waiting for the port? */
+                       if (port->waithead) {
+                               printk (KERN_DEBUG
+                                       "Somebody wants the port\n");
+                               break;
+                       }
+
+                       /* Clear serviceIntr */
+                       outb (ecrval & ~(1<<2), ECONTROL (port));
+               false_alarm:
+                       ret = parport_wait_event (port, HZ);
+                       if (ret < 0) break;
+                       ret = 0;
+                       if (!time_before (jiffies, expire)) {
+                               /* Timed out. */
+                               printk (KERN_DEBUG "Timed out\n");
+                               break;
+                       }
+                       ecrval = inb (ECONTROL (port));
+                       if (!(ecrval & (1<<2))) {
+                               if (current->need_resched &&
+                                   time_before (jiffies, expire))
+                                       schedule ();
+
+                               goto false_alarm;
+                       }
+
+                       continue;
+               }
+
+               if (ecrval & 0x02) {
+                       /* FIFO is full. */
+                       insb (fifo, bufp, fifo_depth);
+                       bufp += fifo_depth;
+                       left -= fifo_depth;
+                       continue;
+               }
+
+               *bufp++ = inb (fifo);
+               left--;
+       }
+
+       /* Finish up. */
+       if (change_mode (port, ECR_PS2) == -EBUSY) {
+               int lost = get_fifo_residue (port);
+               printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name,
+                       lost);
+       }
+
+       port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+
+       return length - left;
 }
 
+#endif /* IEEE 1284 support */
+
+#endif /* Allowed to use FIFO/DMA */
+
 void parport_pc_inc_use_count(void)
 {
 #ifdef MODULE
@@ -269,6 +930,7 @@ void parport_pc_dec_use_count(void)
 
 static void parport_pc_fill_inode(struct inode *inode, int fill)
 {
+       /* Is this still needed? -tim */
 #ifdef MODULE
        if (fill)
                MOD_INC_USE_COUNT;
@@ -286,46 +948,39 @@ struct parport_operations parport_pc_ops =
        parport_pc_read_control,
        parport_pc_frob_control,
 
-       parport_pc_write_econtrol,
-       parport_pc_read_econtrol,
-       parport_pc_frob_econtrol,
-
-       parport_pc_write_status,
        parport_pc_read_status,
 
-       parport_pc_write_fifo,
-       parport_pc_read_fifo,
-       
-       parport_pc_change_mode,
-       
-       parport_pc_write_epp,
-       parport_pc_read_epp,
-       parport_pc_write_epp_addr,
-       parport_pc_read_epp_addr,
-       parport_pc_check_epp_timeout,
+       parport_pc_enable_irq,
+       parport_pc_disable_irq,
 
-       parport_pc_epp_write_block,
-       parport_pc_epp_read_block,
+       parport_pc_data_forward,
+       parport_pc_data_reverse,
 
-       parport_pc_ecp_write_block,
-       parport_pc_ecp_read_block,
-       
+       parport_pc_interrupt,
        parport_pc_init_state,
        parport_pc_save_state,
        parport_pc_restore_state,
 
-       parport_pc_enable_irq,
-       parport_pc_disable_irq,
-       parport_pc_interrupt,
-
        parport_pc_inc_use_count,
        parport_pc_dec_use_count,
-       parport_pc_fill_inode
+       parport_pc_fill_inode,
+
+       parport_ieee1284_epp_write_data,
+       parport_ieee1284_epp_read_data,
+       parport_ieee1284_epp_write_addr,
+       parport_ieee1284_epp_read_addr,
+
+       parport_ieee1284_ecp_write_data,
+       parport_ieee1284_ecp_read_data,
+       parport_ieee1284_ecp_write_addr,
+
+       parport_ieee1284_write_compat,
+       parport_ieee1284_read_nibble,
+       parport_ieee1284_read_byte,
 };
 
 /* --- Mode detection ------------------------------------- */
 
-
 /*
  * Checks for port existence, all ports support SPP MODE
  */
@@ -339,22 +994,23 @@ static int __init parport_SPP_supported(struct parport *pb)
         * that does not even respond to SPP cycles if an EPP
         * timeout is pending
         */
-       parport_pc_epp_clear_timeout(pb);
+       clear_epp_timeout(pb);
 
        /* Do a simple read-write test to make sure the port exists. */
        w = 0xc;
-       parport_pc_write_control(pb, w);
+       outb (w, CONTROL (pb));
 
-       /* Can we read from the control register?  Some ports don't
-        * allow reads, so read_control just returns a software
-        * copy. Some ports _do_ allow reads, so bypass the software
-        * copy here.  In addition, some bits aren't writable. */
+       /* Is there a control register that we can read from?  Some
+        * ports don't allow reads, so read_control just returns a
+        * software copy. Some ports _do_ allow reads, so bypass the
+        * software copy here.  In addition, some bits aren't
+        * writable. */
        r = inb (CONTROL (pb));
        if ((r & 0xf) == w) {
                w = 0xe;
-               parport_pc_write_control (pb, w);
-               r = inb (CONTROL(pb));
-               parport_pc_write_control (pb, 0xc);
+               outb (w, CONTROL (pb));
+               r = inb (CONTROL (pb));
+               outb (0xc, CONTROL (pb));
                if ((r & 0xf) == w)
                        return PARPORT_MODE_PCSPP;
        }
@@ -379,20 +1035,20 @@ static int __init parport_SPP_supported(struct parport *pb)
        }
 
        if (user_specified)
-               /* Didn't work with 0xaa, but the user is convinced
-                * this is the place. */
+               /* Didn't work, but the user is convinced this is the
+                * place. */
                printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
                        pb->base, w, r);
 
        /* It's possible that we can't read the control register or
-          the data register.  In that case just believe the user. */
+        * the data register.  In that case just believe the user. */
        if (user_specified)
                return PARPORT_MODE_PCSPP;
 
        return 0;
 }
 
-/* Check for ECP
+/* Check for ECR
  *
  * Old style XT ports alias io ports every 0x400, hence accessing ECR
  * on these cards actually accesses the CTR.
@@ -401,81 +1057,226 @@ static int __init parport_SPP_supported(struct parport *pb)
  * regardless of what is written here if the card does NOT support
  * ECP.
  *
- * We will write 0x2c to ECR and 0xcc to CTR since both of these
- * values are "safe" on the CTR since bits 6-7 of CTR are unused.
+ * We first check to see if ECR is the same as CTR.  If not, the low
+ * two bits of ECR aren't writable, so we check by writing ECR and
+ * reading it back to see if it's what we expect.
  */
 static int __init parport_ECR_present(struct parport *pb)
 {
-       unsigned char r;
+       struct parport_pc_private *priv = pb->private_data;
+       unsigned char r = 0xc;
 
-       parport_pc_write_control (pb, 0xc);
-       r = parport_pc_read_control(pb);        
-       if ((parport_pc_read_econtrol(pb) & 0x3) == (r & 0x3)) {
-               parport_pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
+       priv->ecr = 0;
+       outb (r, CONTROL (pb));
+       if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
+               outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
 
-               r = parport_pc_read_control(pb);        
-               if ((parport_pc_read_econtrol(pb) & 0x2) == (r & 0x2))
+               r = inb (CONTROL (pb));
+               if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2))
                        goto no_reg; /* Sure that no ECR register exists */
        }
        
-       if ((parport_pc_read_econtrol(pb) & 0x3 ) != 0x1)
+       if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
                goto no_reg;
 
-       parport_pc_write_econtrol(pb, 0x34);
-       if (parport_pc_read_econtrol(pb) != 0x35)
+       outb (0x34, ECONTROL (pb));
+       if (inb (ECONTROL (pb)) != 0x35)
                goto no_reg;
 
-       parport_pc_write_control(pb, 0xc);
-
-       /* Go to mode 000; SPP, reset FIFO */
-       parport_pc_frob_econtrol (pb, 0xe0, 0x00);
+       priv->ecr = 1;
+       outb (0xc, CONTROL (pb));
        
-       return PARPORT_MODE_PCECR;
+       /* Go to mode 000 */
+       frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+
+       return 1;
 
  no_reg:
-       parport_pc_write_control (pb, 0xc);
-       return 0;
+       outb (0xc, CONTROL (pb));
+       return 0; 
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Detect PS/2 support.
+ *
+ * Bit 5 (0x20) sets the PS/2 data direction; setting this high
+ * allows us to read data from the data lines.  In theory we would get back
+ * 0xff but any peripheral attached to the port may drag some or all of the
+ * lines down to zero.  So if we get back anything that isn't the contents
+ * of the data register we deem PS/2 support to be present. 
+ *
+ * Some SPP ports have "half PS/2" ability - you can't turn off the line
+ * drivers, but an external peripheral with sufficiently beefy drivers of
+ * its own can overpower them and assert its own levels onto the bus, from
+ * where they can then be read back as normal.  Ports with this property
+ * and the right type of device attached are likely to fail the SPP test,
+ * (as they will appear to have stuck bits) and so the fact that they might
+ * be misdetected here is rather academic. 
+ */
+
+static int __init parport_PS2_supported(struct parport *pb)
+{
+       int ok = 0;
+  
+       clear_epp_timeout(pb);
+
+       /* try to tri-state the buffer */
+       parport_pc_data_reverse (pb);
+       
+       parport_pc_write_data(pb, 0x55);
+       if (parport_pc_read_data(pb) != 0x55) ok++;
+
+       parport_pc_write_data(pb, 0xaa);
+       if (parport_pc_read_data(pb) != 0xaa) ok++;
+
+       /* cancel input mode */
+       parport_pc_data_forward (pb);
+
+       if (ok)
+               pb->modes |= PARPORT_MODE_TRISTATE;
+       else {
+               struct parport_pc_private *priv = pb->private_data;
+               priv->ctr_writable &= ~0x20;
+       }
+
+       return ok;
 }
 
 static int __init parport_ECP_supported(struct parport *pb)
 {
        int i;
-       unsigned char oecr;
-       
+       int config;
+       int pword;
+       struct parport_pc_private *priv = pb->private_data;
+
        /* If there is no ECR, we have no hope of supporting ECP. */
-       if (!(pb->modes & PARPORT_MODE_PCECR))
+       if (!priv->ecr)
                return 0;
 
-       oecr = parport_pc_read_econtrol(pb);
+       /* Find out FIFO depth */
+       outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+       outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */
+       for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++)
+               outb (0xaa, FIFO (pb));
+
        /*
         * Using LGS chipset it uses ECR register, but
         * it doesn't support ECP or FIFO MODE
         */
+       if (i == 1024) {
+               outb (ECR_SPP << 5, ECONTROL (pb));
+               return 0;
+       }
+
+       priv->fifo_depth = i;
+       printk (KERN_INFO "0x%lx: FIFO is %d bytes\n", pb->base, i);
+
+       /* Find out writeIntrThreshold */
+       frob_econtrol (pb, 1<<2, 1<<2);
+       frob_econtrol (pb, 1<<2, 0);
+       for (i = 1; i <= priv->fifo_depth; i++) {
+               inb (FIFO (pb));
+               udelay (50);
+               if (inb (ECONTROL (pb)) & (1<<2))
+                       break;
+       }
+
+       if (i <= priv->fifo_depth)
+               printk (KERN_INFO "0x%lx: writeIntrThreshold is %d\n",
+                       pb->base, i);
+       else
+               /* Number of bytes we know we can write if we get an
+                   interrupt. */
+               i = 0;
+
+       priv->writeIntrThreshold = i;
+
+       /* Find out readIntrThreshold */
+       frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */
+       parport_pc_data_reverse (pb);
+       frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
+       frob_econtrol (pb, 1<<2, 1<<2);
+       frob_econtrol (pb, 1<<2, 0);
+       for (i = 1; i <= priv->fifo_depth; i++) {
+               outb (0xaa, FIFO (pb));
+               if (inb (ECONTROL (pb)) & (1<<2))
+                       break;
+       }
+
+       if (i <= priv->fifo_depth)
+               printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n",
+                       pb->base, i);
+       else
+               /* Number of bytes we can read if we get an interrupt. */
+               i = 0;
+
+       priv->readIntrThreshold = i;
+
+       outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+       outb (0xf4, ECONTROL (pb)); /* Configuration mode */
+       config = inb (FIFO (pb));
+       pword = (config >> 4) & 0x7;
+       switch (pword) {
+       case 0:
+               pword = 2;
+               printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+                       pb->base);
+               break;
+       case 2:
+               pword = 4;
+               printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+                       pb->base);
+               break;
+       default:
+               printk (KERN_WARNING "0x%lx: Unknown implementation ID\n",
+                       pb->base);
+               /* Assume 1 */
+       case 1:
+               pword = 1;
+       }
+       priv->pword = pword;
+       printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword);
+
+       config = inb (CONFIGB (pb));
+       printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
+               config & 0x80 ? "Level" : "Pulses");
+
+       if (!(config & 0x40)) {
+               printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base);
+               pb->irq = PARPORT_IRQ_NONE;
+       }
+
+       /* Go back to mode 000 */
+       frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+       pb->modes |= PARPORT_MODE_ECP;
+
+       return 1;
+}
+
+static int __init parport_ECPPS2_supported(struct parport *pb)
+{
+       const struct parport_pc_private *priv = pb->private_data;
+       int result;
+       unsigned char oecr;
+
+       if (!priv->ecr)
+               return 0;
+
+       oecr = inb (ECONTROL (pb));
+       outb (ECR_PS2 << 5, ECONTROL (pb));
        
-       parport_pc_write_econtrol(pb, 0xc0); /* TEST FIFO */
-       for (i=0; i < 1024 && (parport_pc_read_econtrol(pb) & 0x01); i++)
-               parport_pc_write_fifo(pb, 0xaa);
+       result = parport_PS2_supported(pb);
 
-       parport_pc_write_econtrol(pb, oecr);
-       return (i==1024)?0:PARPORT_MODE_PCECP;
+       outb (oecr, ECONTROL (pb));
+       return result;
 }
 
-/* EPP mode detection
- * Theory:
- *     Bit 0 of STR is the EPP timeout bit, this bit is 0
- *     when EPP is possible and is set high when an EPP timeout
- *     occurs (EPP uses the HALT line to stop the CPU while it does
- *     the byte transfer, an EPP timeout occurs if the attached
- *     device fails to respond after 10 micro seconds).
- *
- *     This bit is cleared by either reading it (National Semi)
- *     or writing a 1 to the bit (SMC, UMC, WinBond), others ???
- *     This bit is always high in non EPP modes.
- */
+/* EPP mode detection  */
+
 static int __init parport_EPP_supported(struct parport *pb)
 {
        /* If EPP timeout bit clear then EPP available */
-       if (!parport_pc_epp_clear_timeout(pb))
+       if (!clear_epp_timeout(pb))
                return 0;  /* No way to clear timeout */
 
        /*
@@ -491,17 +1292,15 @@ static int __init parport_EPP_supported(struct parport *pb)
         *      This bit is always high in non EPP modes.
         */
 
-       parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
-       parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
-       parport_pc_epp_clear_timeout(pb);
+       parport_pc_data_reverse (pb);
+       parport_pc_enable_irq (pb);
+       clear_epp_timeout(pb);
        
-       parport_pc_read_epp(pb);
+       inb (EPPDATA (pb));
        udelay(30);  /* Wait for possible EPP timeout */
        
-       if (parport_pc_read_status(pb) & 0x01) {
-               parport_pc_epp_clear_timeout(pb);
-               return PARPORT_MODE_PCEPP;
-       }
+       if (parport_pc_read_status(pb) & 0x01)
+               goto supported;
 
        /*
         * Theory:
@@ -511,112 +1310,82 @@ static int __init parport_EPP_supported(struct parport *pb)
         *     in others (EPP 1.7, ECPEPP?) it is possible to read back
         *     its value.
         */
-       parport_pc_epp_clear_timeout(pb);
+       clear_epp_timeout(pb);
        udelay(30); /* Wait for possible EPP timeout */
 
-       /* Previous test left outputs disabled. */
+       /* Enable outputs. */
+       parport_pc_data_forward (pb);
        outb (0x55, EPPADDR (pb));
 
-       parport_pc_epp_clear_timeout(pb);
+       clear_epp_timeout(pb);
        udelay(30); /* Wait for possible EPP timeout */
 
        /* We must enable the outputs to be able to read the address
            register. */
-       parport_pc_frob_control (pb, 0x20, 0x00);
+       parport_pc_data_forward (pb);
 
        if (inb (EPPADDR (pb)) == 0x55) {
-
-               /* wash ... */
-               parport_pc_frob_control (pb, 0x20, 0x20);
-               outb (0xaa, EPPADDR (pb));
-
-               parport_pc_epp_clear_timeout(pb);
+               clear_epp_timeout(pb);
                udelay(30); /* Wait for possible EPP timeout */
+               outb (0xaa, EPPADDR (pb));
 
-               /* ... and repeat */
-               parport_pc_frob_control (pb, 0x20, 0x00);
-
-               if (inb (EPPADDR (pb)) == 0xaa) {
-                       parport_pc_epp_clear_timeout (pb);
-                       return PARPORT_MODE_PCEPP;
-               }
+               if (inb (EPPADDR (pb)) == 0xaa)
+                       goto supported;
        }
 
        return 0;
+
+ supported:
+       clear_epp_timeout(pb);
+       pb->modes |= PARPORT_MODE_EPP;
+
+       /* Set up access functions to use EPP hardware. */
+       parport_pc_ops.epp_read_data = parport_pc_epp_read_data;
+       parport_pc_ops.epp_write_data = parport_pc_epp_write_data;
+       parport_pc_ops.epp_read_addr = parport_pc_epp_read_addr;
+       parport_pc_ops.epp_write_addr = parport_pc_epp_write_addr;
+
+       return 1;
 }
 
 static int __init parport_ECPEPP_supported(struct parport *pb)
 {
-       int mode;
+       struct parport_pc_private *priv = pb->private_data;
+       int result;
        unsigned char oecr;
 
-       if (!(pb->modes & PARPORT_MODE_PCECR))
+       if (!priv->ecr)
                return 0;
 
-       oecr = parport_pc_read_econtrol(pb);
+       oecr = inb (ECONTROL (pb));
        /* Search for SMC style EPP+ECP mode */
-       parport_pc_write_econtrol(pb, 0x80);
-       
-       mode = parport_EPP_supported(pb);
-
-       parport_pc_write_econtrol(pb, oecr);
+       outb (0x80, ECONTROL (pb));
        
-       return mode?PARPORT_MODE_PCECPEPP:0;
-}
-
-/* Detect PS/2 support.
- *
- * Bit 5 (0x20) sets the PS/2 data direction; setting this high
- * allows us to read data from the data lines.  In theory we would get back
- * 0xff but any peripheral attached to the port may drag some or all of the
- * lines down to zero.  So if we get back anything that isn't the contents
- * of the data register we deem PS/2 support to be present. 
- *
- * Some SPP ports have "half PS/2" ability - you can't turn off the line
- * drivers, but an external peripheral with sufficiently beefy drivers of
- * its own can overpower them and assert its own levels onto the bus, from
- * where they can then be read back as normal.  Ports with this property
- * and the right type of device attached are likely to fail the SPP test,
- * (as they will appear to have stuck bits) and so the fact that they might
- * be misdetected here is rather academic. 
- */
+       result = parport_EPP_supported(pb);
 
-static int __init parport_PS2_supported(struct parport *pb)
-{
-       int ok = 0;
-       unsigned char octr = parport_pc_read_control(pb);
-  
-       parport_pc_epp_clear_timeout(pb);
+       outb (oecr, ECONTROL (pb));
 
-       parport_pc_write_control(pb, octr | 0x20);  /* try to tri-state the buffer */
-       
-       parport_pc_write_data(pb, 0x55);
-       if (parport_pc_read_data(pb) != 0x55) ok++;
-
-       parport_pc_write_data(pb, 0xaa);
-       if (parport_pc_read_data(pb) != 0xaa) ok++;
-       
-       parport_pc_write_control(pb, octr);          /* cancel input mode */
+       if (result) {
+               /* Set up access functions to use ECP+EPP hardware. */
+               parport_pc_ops.epp_read_data = parport_pc_ecpepp_read_data;
+               parport_pc_ops.epp_write_data = parport_pc_ecpepp_write_data;
+               parport_pc_ops.epp_read_addr = parport_pc_ecpepp_read_addr;
+               parport_pc_ops.epp_write_addr = parport_pc_ecpepp_write_addr;
+       }
 
-       return ok?PARPORT_MODE_PCPS2:0;
+       return result;
 }
 
-static int __init parport_ECPPS2_supported(struct parport *pb)
-{
-       int mode;
-       unsigned char oecr;
-
-       if (!(pb->modes & PARPORT_MODE_PCECR))
-               return 0;
+#else /* No IEEE 1284 support */
 
-       oecr = parport_pc_read_econtrol(pb);
-       parport_pc_write_econtrol(pb, 0x20);
-       
-       mode = parport_PS2_supported(pb);
+/* Don't bother probing for modes we know we won't use. */
+static int __init parport_PS2_supported(struct parport *pb) { return 0; }
+static int __init parport_ECP_supported(struct parport *pb) { return 0; }
+static int __init parport_EPP_supported(struct parport *pb) { return 0; }
+static int __init parport_ECPEPP_supported(struct parport *pb) { return 0; }
+static int __init parport_ECPPS2_supported(struct parport *pb) { return 0; }
 
-       parport_pc_write_econtrol(pb, oecr);
-       return mode?PARPORT_MODE_PCECPPS2:0;
-}
+#endif /* No IEEE 1284 support */
 
 /* --- IRQ detection -------------------------------------- */
 
@@ -624,17 +1393,17 @@ static int __init parport_ECPPS2_supported(struct parport *pb)
 static int __init programmable_irq_support(struct parport *pb)
 {
        int irq, intrLine;
-       unsigned char oecr = parport_pc_read_econtrol(pb);
+       unsigned char oecr = inb (ECONTROL (pb));
        static const int lookup[8] = {
                PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
        };
 
-       parport_pc_write_econtrol(pb,0xE0); /* Configuration MODE */
-       
-       intrLine = (parport_pc_read_configb(pb) >> 3) & 0x07;
+       outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */
+
+       intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
        irq = lookup[intrLine];
 
-       parport_pc_write_econtrol(pb, oecr);
+       outb (oecr, ECONTROL (pb));
        return irq;
 }
 
@@ -645,15 +1414,16 @@ static int __init irq_probe_ECP(struct parport *pb)
        sti();
        irqs = probe_irq_on();
                
-       parport_pc_write_econtrol(pb, 0x00);    /* Reset FIFO */
-       parport_pc_write_econtrol(pb, 0xd0);    /* TEST FIFO + nErrIntrEn */
+       outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+       outb ((ECR_TST << 5) | 0x04, ECONTROL (pb));
+       outb (ECR_TST << 5, ECONTROL (pb));
 
-       /* If Full FIFO sure that WriteIntrThresold is generated */
-       for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++) 
-               parport_pc_write_fifo(pb, 0xaa);
+       /* If Full FIFO sure that writeIntrThreshold is generated */
+       for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) 
+               outb (0xaa, FIFO (pb));
                
        pb->irq = probe_irq_off(irqs);
-       parport_pc_write_econtrol(pb, 0x00);
+       outb (ECR_SPP << 5, ECONTROL (pb));
 
        if (pb->irq <= 0)
                pb->irq = PARPORT_IRQ_NONE;
@@ -671,22 +1441,21 @@ static int __init irq_probe_EPP(struct parport *pb)
        return PARPORT_IRQ_NONE;
 #else
        int irqs;
-       unsigned char octr = parport_pc_read_control(pb);
        unsigned char oecr;
 
        if (pb->modes & PARPORT_MODE_PCECR)
-               oecr = parport_pc_read_econtrol(pb);
+               oecr = inb (ECONTROL (pb));
 
        sti();
        irqs = probe_irq_on();
 
        if (pb->modes & PARPORT_MODE_PCECR)
-               parport_pc_frob_econtrol (pb, 0x10, 0x10);
+               frob_econtrol (pb, 0x10, 0x10);
        
-       parport_pc_epp_clear_timeout(pb);
+       clear_epp_timeout(pb);
        parport_pc_frob_control (pb, 0x20, 0x20);
        parport_pc_frob_control (pb, 0x10, 0x10);
-       parport_pc_epp_clear_timeout(pb);
+       clear_epp_timeout(pb);
 
        /* Device isn't expecting an EPP read
         * and generates an IRQ.
@@ -696,56 +1465,20 @@ static int __init irq_probe_EPP(struct parport *pb)
 
        pb->irq = probe_irq_off (irqs);
        if (pb->modes & PARPORT_MODE_PCECR)
-               parport_pc_write_econtrol(pb, oecr);
-       parport_pc_write_control(pb, octr);
+               outb (oecr, ECONTROL (pb));
+       parport_pc_write_control(pb, 0xc);
 
        if (pb->irq <= 0)
                pb->irq = PARPORT_IRQ_NONE;
 
        return pb->irq;
-#endif /* Advanced detection. */
+#endif /* Advanced detection */
 }
 
 static int __init irq_probe_SPP(struct parport *pb)
 {
-#ifndef ADVANCED_DETECT
        /* Don't even try to do this. */
        return PARPORT_IRQ_NONE;
-#else
-       int irqs;
-       unsigned char octr = parport_pc_read_control(pb);
-       unsigned char oecr;
-
-       if (pb->modes & PARPORT_MODE_PCECR)
-               oecr = parport_pc_read_econtrol(pb);
-       probe_irq_off(probe_irq_on());  /* Clear any interrupts */
-       irqs = probe_irq_on();
-
-       if (pb->modes & PARPORT_MODE_PCECR)
-               parport_pc_write_econtrol(pb, 0x10);
-
-       parport_pc_write_data(pb,0x00);
-       parport_pc_write_control(pb,0x00);
-       parport_pc_write_control(pb,0x0c);
-       udelay(5);
-       parport_pc_write_control(pb,0x0d);
-       udelay(5);
-       parport_pc_write_control(pb,0x0c);
-       udelay(25);
-       parport_pc_write_control(pb,0x08);
-       udelay(25);
-       parport_pc_write_control(pb,0x0c);
-       udelay(50);
-
-       pb->irq = probe_irq_off(irqs);
-       if (pb->irq <= 0)
-               pb->irq = PARPORT_IRQ_NONE;     /* No interrupt detected */
-       
-       if (pb->modes & PARPORT_MODE_PCECR)
-               parport_pc_write_econtrol(pb, oecr);
-       parport_pc_write_control(pb, octr);
-       return pb->irq;
-#endif /* Advanced detection. */
 }
 
 /* We will attempt to share interrupt requests since other devices
@@ -757,25 +1490,27 @@ static int __init irq_probe_SPP(struct parport *pb)
  */
 static int __init parport_irq_probe(struct parport *pb)
 {
-       if (pb->modes & PARPORT_MODE_PCECR) {
+       const struct parport_pc_private *priv = pb->private_data;
+
+       if (priv->ecr) {
                pb->irq = programmable_irq_support(pb);
                if (pb->irq != PARPORT_IRQ_NONE)
                        goto out;
        }
 
-       if (pb->modes & PARPORT_MODE_PCECP)
+       if (pb->modes & PARPORT_MODE_ECP)
                pb->irq = irq_probe_ECP(pb);
 
-       if (pb->irq == PARPORT_IRQ_NONE && 
-           (pb->modes & PARPORT_MODE_PCECPEPP))
+       if (pb->irq == PARPORT_IRQ_NONE && priv->ecr &&
+           (pb->modes & PARPORT_MODE_EPP))
                pb->irq = irq_probe_EPP(pb);
 
-       parport_pc_epp_clear_timeout(pb);
+       clear_epp_timeout(pb);
 
-       if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_PCEPP))
+       if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP))
                pb->irq = irq_probe_EPP(pb);
 
-       parport_pc_epp_clear_timeout(pb);
+       clear_epp_timeout(pb);
 
        if (pb->irq == PARPORT_IRQ_NONE)
                pb->irq = irq_probe_SPP(pb);
@@ -784,6 +1519,33 @@ out:
        return pb->irq;
 }
 
+/* --- DMA detection -------------------------------------- */
+
+/* Only if supports ECP mode */
+static int __init programmable_dma_support (struct parport *p)
+{
+       unsigned char oecr = inb (ECONTROL (p));
+       int dma;
+
+       frob_econtrol (p, 0xe0, ECR_CNF << 5);
+       
+       dma = inb (CONFIGB(p)) & 0x03;
+       if (!dma)
+               dma = PARPORT_DMA_NONE;
+
+       outb (oecr, ECONTROL (p));
+       return dma;
+}
+
+static int __init parport_dma_probe (struct parport *p)
+{
+       const struct parport_pc_private *priv = p->private_data;
+       if (priv->ecr)
+               p->dma = programmable_dma_support(p);
+
+       return p->dma;
+}
+
 /* --- Initialisation code -------------------------------- */
 
 static int __init probe_one_port(unsigned long int base,
@@ -801,6 +1563,10 @@ static int __init probe_one_port(unsigned long int base,
                return 0;
        }
        priv->ctr = 0xc;
+       priv->ctr_writable = 0xff;
+       priv->ecr = 0;
+       priv->fifo_depth = 0;
+       priv->dma_buf = 0;
        p->base = base;
        p->base_hi = base_hi;
        p->irq = irq;
@@ -808,39 +1574,40 @@ static int __init probe_one_port(unsigned long int base,
        p->modes = PARPORT_MODE_PCSPP;
        p->ops = &parport_pc_ops;
        p->private_data = priv;
-       if (base_hi && !check_region (base_hi, 3)) {
-               p->modes |= parport_ECR_present (p);
-               p->modes |= parport_ECP_supported (p);
-               p->modes |= parport_ECPPS2_supported (p);
+       p->physport = p;
+       if (base_hi && !check_region(base_hi,3)) {
+               parport_ECR_present(p);
+               parport_ECP_supported(p);
+               parport_ECPPS2_supported(p);
        }
-       if (p->base != 0x3bc) {
+       if (base != 0x3bc) {
                if (!check_region(base+0x3, 5)) {
-                       p->modes |= parport_EPP_supported (p);
-                       p->modes |= parport_ECPEPP_supported (p);
+                       parport_ECPEPP_supported(p);
+                       parport_EPP_supported(p);
                }
        }
-       if (!parport_SPP_supported(p)) {
+       if (!parport_SPP_supported (p)) {
                /* No port. */
                kfree (priv);
                return 0;
        }
 
-       p->modes |= parport_PS2_supported(p);
+       parport_PS2_supported (p);
 
-       if (!(p = parport_register_port (base, PARPORT_IRQ_NONE,
-                                        PARPORT_DMA_NONE, &parport_pc_ops))) {
+               if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
+                                       PARPORT_DMA_NONE, &parport_pc_ops))) {
                kfree (priv);
                return 0;
        }
 
        p->base_hi = base_hi;
        p->modes = tmp.modes;
-       p->size = (p->modes & PARPORT_MODE_PCEPP) ? 8 : 3;
+       p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
        p->private_data = priv;
 
        printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
-       if (p->base_hi && (p->modes & PARPORT_MODE_PCECR))
-               printk (" (0x%lx)", p->base_hi);
+       if (p->base_hi && (p->modes & PARPORT_MODE_ECP))
+               printk(" (0x%lx)", p->base_hi);
        p->irq = irq;
        p->dma = dma;
        if (p->irq == PARPORT_IRQ_AUTO) {
@@ -852,33 +1619,52 @@ static int __init probe_one_port(unsigned long int base,
                probedirq = p->irq;
                p->irq = PARPORT_IRQ_NONE;
        }
-       if (p->irq != PARPORT_IRQ_NONE)
+       if (p->irq != PARPORT_IRQ_NONE) {
                printk(", irq %d", p->irq);
+
+               if (p->dma == PARPORT_DMA_AUTO) {
+                       p->dma = PARPORT_DMA_NONE;
+                       parport_dma_probe(p);
+               }
+       }
        if (p->dma == PARPORT_DMA_AUTO)         
                p->dma = PARPORT_DMA_NONE;
-       if (p->dma != PARPORT_DMA_NONE)
+       if (p->dma != PARPORT_DMA_NONE) 
                printk(", dma %d", p->dma);
+
+#ifdef CONFIG_PARPORT_PC_FIFO
+       if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
+               parport_pc_ops.compat_write_data =
+                       parport_pc_compat_write_block_pio;
+#ifdef CONFIG_PARPORT_1284
+               parport_pc_ops.ecp_write_data =
+                       parport_pc_ecp_write_block_pio;
+#endif /* IEEE 1284 support */
+               if (p->dma != PARPORT_DMA_NONE)
+                       p->modes |= PARPORT_MODE_DMA;
+               printk(", using FIFO");
+       }
+#endif /* Allowed to use FIFO/DMA */
+
        printk(" [");
-#define printmode(x) {if(p->modes&PARPORT_MODE_PC##x){printk("%s%s",f?",":"",#x);f++;}}
+#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
        {
                int f = 0;
-               printmode(SPP);
-               printmode(PS2);
+               printmode(PCSPP);
+               printmode(TRISTATE);
+               printmode(COMPAT)
                printmode(EPP);
                printmode(ECP);
-               printmode(ECPEPP);
-               printmode(ECPPS2);
+               printmode(DMA);
        }
 #undef printmode
        printk("]\n");
-#ifdef CONFIG_PROC_FS
        if (probedirq != PARPORT_IRQ_NONE) 
-               printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq);
-#endif
+               printk("%s: irq %d detected\n", p->name, probedirq);
        parport_proc_register(p);
 
        request_region (p->base, p->size, p->name);
-       if (p->modes & PARPORT_MODE_PCECR)
+       if (p->modes & PARPORT_MODE_ECP)
                request_region (p->base_hi, 3, p->name);
 
        if (p->irq != PARPORT_IRQ_NONE) {
@@ -897,25 +1683,37 @@ static int __init probe_one_port(unsigned long int base,
                                        "resorting to PIO operation\n",
                                        p->name, p->dma);
                                p->dma = PARPORT_DMA_NONE;
+                       } else {
+                               priv->dma_buf = (char *) __get_dma_pages(GFP_KERNEL, 1);
+                               if (! priv->dma_buf) {
+                                       printk (KERN_WARNING "%s: "
+                                               "cannot get buffer for DMA, "
+                                               "resorting to PIO operation\n",
+                                               p->name);
+                                       free_dma(p->dma);
+                                       p->dma = PARPORT_DMA_NONE;
+                               }
                        }
                }
        }
 
-       /* Done probing.  Now put the port into a sensible start-up state. */
-       if (p->modes & PARPORT_MODE_PCECR)
+       /* Done probing.  Now put the port into a sensible start-up state.
+        * SELECT | INIT also puts IEEE1284-compliant devices into
+        * compatibility mode. */
+       if (p->modes & PARPORT_MODE_ECP)
                /*
                 * Put the ECP detected port in PS2 mode.
                 */
-               parport_pc_write_econtrol(p, 0x24);
+               outb (0x24, ECONTROL (p));
+
        parport_pc_write_data(p, 0);
-       parport_pc_write_control(p, 0x8);
+       parport_pc_write_control(p, PARPORT_CONTROL_SELECT);
        udelay (50);
-       parport_pc_write_control(p, 0xc);
+       parport_pc_write_control(p,
+                                PARPORT_CONTROL_SELECT
+                                | PARPORT_CONTROL_INIT);
        udelay (50);
 
-       if (parport_probe_hook)
-               (*parport_probe_hook)(p);
-
        /* Now that we've told the sharing engine about the port, and
           found out its characteristics, let the high-level drivers
           know about it. */
@@ -953,11 +1751,8 @@ static int __init parport_pc_init_pci (int irq, int dma)
 #define PCI_DEVICE_ID_LAVA_PARALLEL     0x8000
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A   0x8001 /* The Lava Dual Parallel is */
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_B   0x8002 /* two PCI devices on a card */
-#endif /* IDs not defined */
+#endif
 
-       int count = 0;
-#ifdef CONFIG_PCI
-       int i;
        struct {
                unsigned int vendor;
                unsigned int device;
@@ -1014,6 +1809,9 @@ static int __init parport_pc_init_pci (int irq, int dma)
                { 0, }
        };
 
+       int count = 0;
+       int i;
+
        if (!pci_present ())
                return 0;
 
@@ -1036,7 +1834,6 @@ static int __init parport_pc_init_pci (int irq, int dma)
                        }
                }
        }
-#endif /* CONFIG_PCI */
 
        return count;
 }
@@ -1070,17 +1867,9 @@ static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PAR
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
 static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
 static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
-
-MODULE_PARM_DESC(io, "base address");
 MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-
-MODULE_PARM_DESC(io_hi, "base address for ECR");
 MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-
-MODULE_PARM_DESC(irq, "irq line to use (or 'auto' or 'none')");
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-
-MODULE_PARM_DESC(dma, "dma channel to use (or 'auto' or 'none')");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 
 int init_module(void)
@@ -1120,15 +1909,18 @@ void cleanup_module(void)
        struct parport *p = parport_enumerate(), *tmp;
        while (p) {
                tmp = p->next;
-               if (p->modes & PARPORT_MODE_PCSPP) {
+               if (p->modes & PARPORT_MODE_PCSPP) { 
+                       struct parport_pc_private *priv = p->private_data;
                        if (p->dma != PARPORT_DMA_NONE)
-                               free_dma (p->dma);
+                               free_dma(p->dma);
                        if (p->irq != PARPORT_IRQ_NONE)
-                               free_irq (p->irq, p);
-                       release_region (p->base, p->size);
-                       if (p->modes & PARPORT_MODE_PCECP)
-                               release_region (p->base_hi, 3);
+                               free_irq(p->irq, p);
+                       release_region(p->base, p->size);
+                       if (p->modes & PARPORT_MODE_ECP)
+                               release_region(p->base_hi, 3);
                        parport_proc_unregister(p);
+                       if (priv->dma_buf)
+                               free_page((unsigned long) priv->dma_buf);
                        kfree (p->private_data);
                        parport_unregister_port(p);
                }
diff --git a/drivers/misc/parport_probe.c b/drivers/misc/parport_probe.c
new file mode 100644 (file)
index 0000000..a5b1524
--- /dev/null
@@ -0,0 +1,212 @@
+/* $Id: parport_probe.c,v 1.3 1997/10/19 18:18:46 phil Exp $
+ * Parallel port device probing code
+ *
+ * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
+ *             Philip Blundell <Philip.Blundell@pobox.com>
+ */
+
+#include <linux/parport.h>
+#include <linux/ctype.h>
+#include <asm/uaccess.h>
+
+static struct {
+       char *token;
+       char *descr;
+} classes[] = {
+       { "",            "Legacy device" },
+       { "PRINTER",     "Printer" },
+       { "MODEM",       "Modem" },
+       { "NET",         "Network device" },
+       { "HDC",         "Hard disk" },
+       { "PCMCIA",      "PCMCIA" },
+       { "MEDIA",       "Multimedia device" },
+       { "FDC",         "Floppy disk" },
+       { "PORTS",       "Ports" },
+       { "SCANNER",     "Scanner" },
+       { "DIGICAM",     "Digital camera" },
+       { "",            "Unknown device" },
+       { "",            "Unspecified" },
+       { "SCSIADAPTER", "SCSI adapter" },
+       { NULL,          NULL }
+};
+
+static void pretty_print(struct parport *port, int device)
+{
+       struct parport_device_info *info = &port->probe_info[device + 1];
+
+       printk(KERN_INFO "%s", port->name);
+
+       if (device >= 0)
+               printk (" (addr %d)", device);
+
+       printk (": %s", classes[info->class].descr);
+       if (info->class)
+               printk(", %s %s", info->mfr, info->model);
+
+       printk("\n");
+}
+
+static char *strdup(char *str)
+{
+       int n = strlen(str)+1;
+       char *s = kmalloc(n, GFP_KERNEL);
+       if (!s) return NULL;
+       return strcpy(s, str);
+}
+
+static void parse_data(struct parport *port, int device, char *str)
+{
+       char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
+       char *p = txt, *q;
+       int guessed_class = PARPORT_CLASS_UNSPEC;
+       struct parport_device_info *info = &port->probe_info[device + 1];
+
+       if (!txt) {
+               printk("%s probe: memory squeeze\n", port->name);
+               return;
+       }
+       strcpy(txt, str);
+       while (p) {
+               char *sep;
+               q = strchr(p, ';');
+               if (q) *q = 0;
+               sep = strchr(p, ':');
+               if (sep) {
+                       char *u = p;
+                       *(sep++) = 0;
+                       while (*u) {
+                               *u = toupper(*u);
+                               u++;
+                       }
+                       if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
+                               if (info->mfr)
+                                       kfree (info->mfr);
+                               info->mfr = strdup(sep);
+                       } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
+                               if (info->model)
+                                       kfree (info->model);
+                               info->model = strdup(sep);
+                       } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
+                               int i;
+                               if (info->class_name)
+                                       kfree (info->class_name);
+                               info->class_name = strdup(sep);
+                               for (u = sep; *u; u++)
+                                       *u = toupper(*u);
+                               for (i = 0; classes[i].token; i++) {
+                                       if (!strcmp(classes[i].token, sep)) {
+                                               info->class = i;
+                                               goto rock_on;
+                                       }
+                               }
+                               printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
+                               info->class = PARPORT_CLASS_OTHER;
+                       } else if (!strcmp(p, "CMD") ||
+                                  !strcmp(p, "COMMAND SET")) {
+                               if (info->cmdset)
+                                       kfree (info->cmdset);
+                               info->cmdset = strdup(sep);
+                               /* if it speaks printer language, it's
+                                  probably a printer */
+                               if (strstr(sep, "PJL") || strstr(sep, "PCL"))
+                                       guessed_class = PARPORT_CLASS_PRINTER;
+                       } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
+                               if (info->description)
+                                       kfree (info->description);
+                               info->description = strdup(sep);
+                       }
+               }
+       rock_on:
+               if (q) p = q+1; else p=NULL;
+       }
+
+       /* If the device didn't tell us its class, maybe we have managed to
+          guess one from the things it did say. */
+       if (info->class == PARPORT_CLASS_UNSPEC)
+               info->class = guessed_class;
+
+       pretty_print (port, device);
+
+       kfree(txt);
+}
+
+/* Get Std 1284 Device ID. */
+ssize_t parport_device_id (int devnum, char *buffer, size_t len)
+{
+       ssize_t retval = -ENXIO;
+       struct pardevice *dev = parport_open (devnum, "Device ID probe",
+                                             NULL, NULL, NULL, 0, NULL);
+       if (!dev)
+               return -ENXIO;
+
+       parport_claim_or_block (dev);
+
+       /* Negotiate to compatibility mode, and then to device ID mode.
+        * (This is in case we are already in device ID mode.) */
+       parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
+       retval = parport_negotiate (dev->port,
+                                   IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID);
+
+       if (!retval) {
+               int idlen;
+               unsigned char length[2];
+               mm_segment_t oldfs = get_fs ();
+               set_fs (get_ds ());
+
+               /* First two bytes are MSB,LSB of inclusive length. */
+               retval = parport_read (dev->port, length, 2);
+
+               if (retval != 2) goto restore_fs;
+
+               idlen = (length[0] << 8) + length[1] - 2;
+               if (idlen < len)
+                       len = idlen;
+               retval = parport_read (dev->port, buffer, len);
+
+               if (retval != len) {
+                       printk (KERN_DEBUG "%s: only read %d of %d ID bytes\n",
+                               dev->port->name, retval, len);
+                       goto restore_fs;
+               }
+
+               /* Some printer manufacturers mistakenly believe that
+                   the length field is supposed to be _exclusive_. */
+               /* In addition, there are broken devices out there
+                   that don't even finish off with a semi-colon. */
+               if (idlen == len && buffer[len - 1] != ';') {
+                       ssize_t diff;
+                       diff = parport_read (dev->port, buffer + len, 2);
+                       retval += diff;
+
+                       if (diff)
+                               printk (KERN_DEBUG
+                                       "%s: device reported incorrect "
+                                       "length field (%d, should be %d)\n",
+                                       dev->port->name, idlen, retval);
+                       else {
+                               /* One semi-colon short of a device ID. */
+                               buffer[len++] = ';';
+                               buffer[len] = '\0';
+                               printk (KERN_DEBUG "%s: faking semi-colon\n",
+                                       dev->port->name);
+
+                               /* If we get here, I don't think we
+                                   need to worry about the possible
+                                   standard violation of having read
+                                   more than we were told to.  The
+                                   device is non-compliant anyhow. */
+                       }
+               }
+
+       restore_fs:
+               set_fs (oldfs);
+               parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
+       }
+       parport_release (dev);
+
+       if (retval > 0)
+               parse_data (dev->port, dev->daisy, buffer);
+
+       parport_close (dev);
+       return retval;
+}
index f3dc63c460bebb1969ec505258057e5f197d4491..0c7be433c3c223a5abeedce76a8f1fc115be1d7f 100644 (file)
@@ -62,7 +62,7 @@ static int do_active_device(ctl_table *table, int write, struct file *filp,
        return copy_to_user(result, buffer, len) ? -EFAULT : 0;
 }
 
-#if 0 && defined (CONFIG_PARPORT_1284)
+#ifdef CONFIG_PARPORT_1284
 static int do_autoprobe(ctl_table *table, int write, struct file *filp,
                        void *result, size_t *lenp)
 {
@@ -146,9 +146,11 @@ static int do_hardware(ctl_table *table, int write, struct file *filp,
 #define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
                int f = 0;
                printmode(PCSPP);
-               printmode(PCPS2);
-               printmode(PCEPP);
-               printmode(PCECP);
+               printmode(TRISTATE);
+               printmode(COMPAT);
+               printmode(EPP);
+               printmode(ECP);
+               printmode(DMA);
 #undef printmode
        }
        buffer[len++] = '\n';
@@ -190,7 +192,7 @@ static const struct parport_sysctl_table parport_sysctl_template = {
                  NULL, 0, 0444, NULL,
                  &do_hardware },
                PARPORT_DEVICES_ROOT_DIR,
-#if 0 && defined(CONFIG_PARPORT_1284)
+#ifdef CONFIG_PARPORT_1284
                { DEV_PARPORT_AUTOPROBE, "autoprobe",
                  NULL, 0, 0444, NULL,
                  &do_autoprobe },
@@ -292,17 +294,11 @@ int parport_proc_register(struct parport *port)
        for (i = 0; i < 8; i++)
                t->vars[i].extra1 = port;
 
-#if 0 /* Wait for IEEE 1284 support */
        t->vars[0].data = &port->spintime;
-#endif
        t->vars[2].child = t->device_dir;
        
        for (i = 0; i < 5; i++)
-#if 0
                t->vars[3 + i].extra2 = &port->probe_info[i];
-#else
-               t->vars[3 + i].extra2 = &port->probe_info;
-#endif
 
        t->port_dir[0].procname = port->name;
        t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
@@ -348,7 +344,7 @@ int parport_device_proc_register(struct pardevice *device)
        t->port_dir[0].child = t->devices_root_dir;
        t->devices_root_dir[0].child = t->device_dir;
 
-#if 0 && defined(CONFIG_PARPORT_1284)
+#ifdef CONFIG_PARPORT_1284
 
        t->device_dir[0].ctl_name =
                parport_device_num(port->number, port->muxport,
index 4138df28a9276a5af40a0aa8835bca747b8cc3cc..0ca126a41c64dc64feda496a3105653d2013cab8 100644 (file)
@@ -40,9 +40,7 @@
 #define PARPORT_DEFAULT_TIMESLICE      (HZ/5)
 
 unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE;
-
-/* This doesn't do anything yet. */
-int parport_default_spintime;
+int parport_default_spintime =  DEFAULT_SPIN_TIME;
 
 static struct parport *portlist = NULL, *portlist_tail = NULL;
 spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;
@@ -50,7 +48,7 @@ spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;
 static struct parport_driver *driver_chain = NULL;
 spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED;
 
-static void call_driver_chain (int attach, struct parport *port)
+static void call_driver_chain(int attach, struct parport *port)
 {
        struct parport_driver *drv;
 
@@ -96,17 +94,12 @@ void parport_unregister_driver (struct parport_driver *arg)
        }
 }
 
-void (*parport_probe_hook)(struct parport *port) = NULL;
-
 /* Return a list of all the ports we know about. */
 struct parport *parport_enumerate(void)
 {
 #ifdef CONFIG_KMOD
        if (portlist == NULL) {
                request_module("parport_lowlevel");
-#ifdef CONFIG_PNP_PARPORT_MODULE
-               request_module("parport_probe");
-#endif /* CONFIG_PNP_PARPORT_MODULE */
        }
 #endif /* CONFIG_KMOD */
        return portlist;
@@ -117,16 +110,9 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
 {
        struct parport *tmp;
        int portnum;
+       int device;
        char *name;
 
-       /* Check for a previously registered port.
-          NOTE: we will ignore irq and dma if we find a previously
-          registered device.  */
-       for (tmp = portlist; tmp; tmp = tmp->next) {
-               if (tmp->base == base)
-                       return tmp;
-       }
-
        tmp = kmalloc(sizeof(struct parport), GFP_KERNEL);
        if (!tmp) {
                printk(KERN_WARNING "parport: memory squeeze\n");
@@ -154,16 +140,22 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
        tmp->base = base;
        tmp->irq = irq;
        tmp->dma = dma;
+       tmp->muxport = tmp->daisy = tmp->muxsel = -1;
        tmp->modes = 0;
        tmp->next = NULL;
        tmp->devices = tmp->cad = NULL;
        tmp->flags = 0;
        tmp->ops = ops;
-       tmp->number = portnum;
-       memset (&tmp->probe_info, 0, sizeof (struct parport_device_info));
+       tmp->portnum = tmp->number = portnum;
+       tmp->physport = tmp;
+       memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info));
        tmp->cad_lock = RW_LOCK_UNLOCKED;
        spin_lock_init(&tmp->waitlist_lock);
        spin_lock_init(&tmp->pardevice_lock);
+       tmp->ieee1284.mode = IEEE1284_MODE_COMPAT;
+       tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+       init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */
+       tmp->spintime = parport_default_spintime;
 
        name = kmalloc(15, GFP_KERNEL);
        if (!name) {
@@ -188,7 +180,10 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
                portlist = tmp;
        spin_unlock(&parportlist_lock);
 
-       tmp->probe_info.class = PARPORT_CLASS_LEGACY;  /* assume the worst */
+       for (device = 0; device < 5; device++)
+               /* assume the worst */
+               tmp->probe_info[device].class = PARPORT_CLASS_LEGACY;
+
        tmp->waithead = tmp->waittail = NULL;
 
        return tmp;
@@ -196,6 +191,11 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
 
 void parport_announce_port (struct parport *port)
 {
+#ifdef CONFIG_PARPORT_1284
+       /* Analyse the IEEE1284.3 topology of the port. */
+       parport_daisy_init (port);
+#endif
+
        /* Let drivers know that a new port has arrived. */
        call_driver_chain (1, port);
 }
@@ -203,10 +203,16 @@ void parport_announce_port (struct parport *port)
 void parport_unregister_port(struct parport *port)
 {
        struct parport *p;
+       int d;
 
        /* Spread the word. */
        call_driver_chain (0, port);
 
+#ifdef CONFIG_PARPORT_1284
+       /* Forget the IEEE1284.3 topology of the port. */
+       parport_daisy_fini (port);
+#endif
+
        spin_lock(&parportlist_lock);
        if (portlist == port) {
                if ((portlist = port->next) == NULL)
@@ -222,16 +228,20 @@ void parport_unregister_port(struct parport *port)
                             "%s not found in port list!\n", port->name);
        }
        spin_unlock(&parportlist_lock);
-       if (port->probe_info.class_name)
-               kfree (port->probe_info.class_name);
-       if (port->probe_info.mfr)
-               kfree (port->probe_info.mfr);
-       if (port->probe_info.model)
-               kfree (port->probe_info.model);
-       if (port->probe_info.cmdset)
-               kfree (port->probe_info.cmdset);
-       if (port->probe_info.description)
-               kfree (port->probe_info.description);
+
+       for (d = 0; d < 5; d++) {
+               if (port->probe_info[d].class_name)
+                       kfree (port->probe_info[d].class_name);
+               if (port->probe_info[d].mfr)
+                       kfree (port->probe_info[d].mfr);
+               if (port->probe_info[d].model)
+                       kfree (port->probe_info[d].model);
+               if (port->probe_info[d].cmdset)
+                       kfree (port->probe_info[d].cmdset);
+               if (port->probe_info[d].description)
+                       kfree (port->probe_info[d].description);
+       }
+
        kfree(port->name);
        kfree(port);
 }
@@ -243,7 +253,7 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
 {
        struct pardevice *tmp;
 
-       if (port->flags & PARPORT_FLAG_EXCL) {
+       if (port->physport->flags & PARPORT_FLAG_EXCL) {
                /* An exclusive device is registered. */
                printk (KERN_DEBUG "%s: no more devices allowed\n",
                        port->name);
@@ -272,13 +282,14 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
 
        tmp->name = name;
        tmp->port = port;
+       tmp->daisy = -1;
        tmp->preempt = pf;
        tmp->wakeup = kf;
        tmp->private = handle;
        tmp->flags = flags;
        tmp->irq_func = irq_func;
-       port->ops->init_state(tmp->state);
        tmp->waiting = 0;
+       tmp->timeout = 5 * HZ;
 
        /* Chain this onto the list */
        tmp->prev = NULL;
@@ -286,11 +297,11 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
         * This function must not run from an irq handler so we don' t need
         * to clear irq on the local CPU. -arca
         */
-       spin_lock(&port->pardevice_lock);
+       spin_lock(&port->physport->pardevice_lock);
 
        if (flags & PARPORT_DEV_EXCL) {
-               if (port->devices) {
-                       spin_unlock (&port->pardevice_lock);
+               if (port->physport->devices) {
+                       spin_unlock (&port->physport->pardevice_lock);
                        kfree (tmp->state);
                        kfree (tmp);
                        printk (KERN_DEBUG
@@ -301,11 +312,11 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
                port->flags |= PARPORT_FLAG_EXCL;
        }
 
-       tmp->next = port->devices;
-       if (port->devices)
-               port->devices->prev = tmp;
-       port->devices = tmp;
-       spin_unlock(&port->pardevice_lock);
+       tmp->next = port->physport->devices;
+       if (port->physport->devices)
+               port->physport->devices->prev = tmp;
+       port->physport->devices = tmp;
+       spin_unlock(&port->physport->pardevice_lock);
 
        inc_parport_count();
        port->ops->inc_use_count();
@@ -314,6 +325,12 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
        tmp->timeslice = parport_default_timeslice;
        tmp->waitnext = tmp->waitprev = NULL;
 
+       /*
+        * This has to be run as last thing since init_state may need other
+        * pardevice fields. -arca
+        */
+       port->ops->init_state(tmp, tmp->state);
+       parport_device_proc_register(tmp);
        return tmp;
 }
 
@@ -328,7 +345,9 @@ void parport_unregister_device(struct pardevice *dev)
        }
 #endif
 
-       port = dev->port;
+       parport_device_proc_unregister(dev);
+
+       port = dev->port->physport;
 
        if (port->cad == dev) {
                printk(KERN_DEBUG "%s: %s forgot to release port\n",
@@ -354,19 +373,17 @@ void parport_unregister_device(struct pardevice *dev)
 
        dec_parport_count();
        port->ops->dec_use_count();
-
-       return;
 }
 
 int parport_claim(struct pardevice *dev)
 {
        struct pardevice *oldcad;
-       struct parport *port = dev->port;
+       struct parport *port = dev->port->physport;
        unsigned long flags;
 
        if (port->cad == dev) {
                printk(KERN_INFO "%s: %s already owner\n",
-                          dev->port->name,dev->name);
+                      dev->port->name,dev->name);
                return 0;
        }
 
@@ -407,24 +424,27 @@ try_again:
                dev->waitprev = dev->waitnext = NULL;
        }
 
-       if (oldcad && port->irq != PARPORT_IRQ_NONE && !oldcad->irq_func)
-               /*
-                * If there was an irq pending it should hopefully happen
-                * before return from enable_irq(). -arca
-                */
-               enable_irq(port->irq);
-
-       /*
-        * Avoid running irq handlers if the pardevice doesn' t use it. -arca
-        */
-       if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func)
-               disable_irq(port->irq);
-
        /* Now we do the change of devices */
        write_lock_irqsave(&port->cad_lock, flags);
        port->cad = dev;
        write_unlock_irqrestore(&port->cad_lock, flags);
 
+#ifdef CONFIG_PARPORT_1284
+       /* If it's a mux port, select it. */
+       if (dev->port->muxport >= 0) {
+               /* FIXME */
+               port->muxsel = dev->port->muxport;
+       }
+
+       /* If it's a daisy chain device, select it. */
+       if (dev->daisy >= 0) {
+               /* This could be lazier. */
+               if (!parport_daisy_select (port, dev->daisy,
+                                          IEEE1284_MODE_COMPAT))
+                       port->daisy = dev->daisy;
+       }
+#endif /* IEEE1284.3 support */
+
        /* Restore control registers */
        port->ops->restore_state(port, dev->state);
        dev->time = jiffies;
@@ -487,8 +507,11 @@ int parport_claim_or_block(struct pardevice *dev)
                }
                restore_flags(flags);
 #ifdef PARPORT_DEBUG_SHARING
-               if (dev->port->cad != dev)
-                       printk(KERN_DEBUG "%s: exiting parport_claim_or_block but %s owns port!\n", dev->name, dev->port->cad?dev->port->cad->name:"nobody");
+               if (dev->port->physport->cad != dev)
+                       printk(KERN_DEBUG "%s: exiting parport_claim_or_block "
+                              "but %s owns port!\n", dev->name,
+                              dev->port->physport->cad ?
+                              dev->port->physport->cad->name:"nobody");
 #endif
        }
        dev->waiting = 0;
@@ -497,7 +520,7 @@ int parport_claim_or_block(struct pardevice *dev)
 
 void parport_release(struct pardevice *dev)
 {
-       struct parport *port = dev->port;
+       struct parport *port = dev->port->physport;
        struct pardevice *pd;
        unsigned long flags;
 
@@ -507,17 +530,25 @@ void parport_release(struct pardevice *dev)
                       "when not owner\n", port->name, dev->name);
                return;
        }
+
+#ifdef CONFIG_PARPORT_1284
+       /* If this is on a mux port, deselect it. */
+       if (dev->port->muxport >= 0) {
+               /* FIXME */
+               port->muxsel = -1;
+       }
+
+       /* If this is a daisy device, deselect it. */
+       if (dev->daisy >= 0) {
+               parport_daisy_deselect_all (port);
+               port->daisy = -1;
+       }
+#endif
+
        write_lock_irqsave(&port->cad_lock, flags);
        port->cad = NULL;
        write_unlock_irqrestore(&port->cad_lock, flags);
 
-       /*
-        * Reenable irq and so discard the eventually pending irq while
-        * cad is NULL. -arca
-        */
-       if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func)
-               enable_irq(port->irq);
-
        /* Save control registers */
        port->ops->save_state(port, dev->state);
 
index f8279fd67dcb4fb29c5732a03e289d75f2a394a6..0aa5aa426b34186bd7d9192a96ea414e415c0bef 100644 (file)
@@ -1,16 +1,3 @@
 #
 # Plug and Play configuration
 #
-
-mainmenu_option next_comment
-comment 'Plug and Play support'
-bool 'Plug and Play support' CONFIG_PNP
-
-if [ "$CONFIG_PNP" = "y" ]; then
-  if [ "$CONFIG_PARPORT" != "n" ]; then
-    dep_tristate '  Auto-probe for parallel devices' CONFIG_PNP_PARPORT $CONFIG_PARPORT
-  fi
-fi
-
-endmenu
index 565062f7e91a6bcafe7a960c32dc9f644e10c6c7..a801f19925c441ceb7eef34ba67e0680de11dd29 100644 (file)
@@ -7,10 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now inherited from the
 # parent makes..
-#
-# Note 3! Plug and Play is the Borg.  We have assimilated some other
-# drivers in the `char', `net' and `scsi' directories, but left them
-# there to allay suspicion.
 
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
@@ -22,12 +18,4 @@ LX_OBJS  :=
 MI_OBJS  :=
 MIX_OBJS :=
 
-ifeq ($(CONFIG_PNP_PARPORT),y)
-  LX_OBJS += parport_probe.o
-else
-  ifeq ($(CONFIG_PNP_PARPORT),m)
-    MX_OBJS += parport_probe.o
-  endif
-endif
-
 include $(TOPDIR)/Rules.make
diff --git a/drivers/pnp/parport_probe.c b/drivers/pnp/parport_probe.c
deleted file mode 100644 (file)
index 8ae4993..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/* $Id: parport_probe.c,v 1.3 1997/10/19 18:18:46 phil Exp $ 
- * Parallel port device probing code
- * 
- * Authors:    Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
- *             Philip Blundell <Philip.Blundell@pobox.com>
- */
-
-#include <linux/tasks.h>
-#include <linux/parport.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/ctype.h>
-#include <linux/module.h>
-
-#include <linux/lp.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#undef DEBUG_PROBE
-
-static inline int read_nibble(struct parport *port) 
-{
-       unsigned char i;
-       i = parport_read_status(port)>>3;
-       i &= ~8;
-       if ((i & 0x10) == 0) i |= 8;
-       return (i & 0x0f);
-}
-
-static void read_terminate(struct parport *port) {
-       parport_write_control(port, (parport_read_control(port) & ~2) | 8);
-       /* SelectIN high, AutoFeed low */
-       if (parport_wait_peripheral(port, 0x80, 0)) 
-               /* timeout, SelectIN high, Autofeed low */
-               return;
-       parport_write_control(port, parport_read_control(port) | 2);
-       /* AutoFeed high */
-       parport_wait_peripheral(port, 0x80, 0x80);
-       /* no timeout possible, Autofeed low, SelectIN high */
-       parport_write_control(port, (parport_read_control(port) & ~2) | 8);
-}
-
-static long read_polled(struct parport *port, char *buf, 
-                          unsigned long length)
-{
-       int i;
-       char *temp=buf;
-       unsigned int count = 0;
-       unsigned char z=0;
-       unsigned char Byte=0;
-       unsigned long igiveupat=jiffies+5*HZ;
-
-       for (i=0; time_before(jiffies, igiveupat); i++) {
-              /* if(current->need_resched) schedule(); */
-               parport_write_control(port, parport_read_control(port) | 2); /* AutoFeed high */
-               if (parport_wait_peripheral(port, 0x40, 0)) {
-#ifdef DEBUG_PROBE
-                       /* Some peripherals just time out when they've sent
-                          all their data.  */
-                       printk("%s: read1 timeout.\n", port->name);
-#endif
-                       parport_write_control(port, parport_read_control(port) & ~2);
-                       break;
-               }
-               z = read_nibble(port);
-               parport_write_control(port, parport_read_control(port) & ~2); /* AutoFeed low */
-               if (parport_wait_peripheral(port, 0x40, 0x40)) {
-                       printk("%s: read2 timeout.\n", port->name);
-                       break;
-               }
-               if ((i & 1) != 0) {
-                       Byte |= (z<<4);
-                       if (temp) 
-                               *(temp++) = Byte; 
-                       if (++count == length)
-                               temp = NULL;
-                       /* Does the error line indicate end of data? */
-                       if ((parport_read_status(port) & LP_PERRORP) == 
-                           LP_PERRORP) 
-                               break;
-               } else 
-                       Byte=z;
-       }
-       read_terminate(port);
-       return count; 
-}
-
-int parport_probe(struct parport *port, char *buffer, int len)
-{
-       struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, 0, &dev);
-
-       int result = 0;
-
-       if (!dev) {
-               printk("%s: unable to register for probe.\n", port->name);
-               return -EINVAL;
-       }
-
-       parport_claim_or_block(dev);
-
-       switch (parport_ieee1284_nibble_mode_ok(port, 4)) {
-       case 2:
-               current->state=TASK_INTERRUPTIBLE;
-               /* HACK: wait 10ms because printer seems to ack wrong */
-               schedule_timeout((HZ+99)/100);  
-               result = read_polled(port, buffer, len);
-               break;
-       default:
-               result = -EIO;
-               break;
-       }
-
-       parport_release(dev);
-       parport_unregister_device(dev);
-
-       return result;
-}
-
-static struct {
-       char *token;
-       char *descr;
-} classes[] = {
-       { "",        "Legacy device" },
-       { "PRINTER", "Printer" }, 
-       { "MODEM",   "Modem" },
-       { "NET",     "Network device" },
-       { "HDC",     "Hard disk" },
-       { "PCMCIA",  "PCMCIA" },
-       { "MEDIA",   "Multimedia device" },
-       { "FDC",     "Floppy disk" },
-       { "PORTS",   "Ports" },
-       { "SCANNER", "Scanner" },
-       { "DIGICAM", "Digital camera" },
-       { "",        "Unknown device" },
-       { "",        "Unspecified" }, 
-       { NULL,      NULL }
-};
-
-static char *strdup(char *str)
-{
-       int n = strlen(str)+1;
-       char *s = kmalloc(n, GFP_KERNEL);
-       if (!s) return NULL;
-       return strcpy(s, str);
-}
-
-static void parse_data(struct parport *port, char *str)
-{
-       char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
-       char *p = txt, *q; 
-       int guessed_class = PARPORT_CLASS_UNSPEC;
-
-       if (!txt) {
-               printk("%s probe: memory squeeze\n", port->name);
-               return;
-       }
-       strcpy(txt, str);
-       while (p) {
-               char *sep; 
-               q = strchr(p, ';');
-               if (q) *q = 0;
-               sep = strchr(p, ':');
-               if (sep) {
-                       char *u = p;
-                       *(sep++) = 0;
-                       while (*u) {
-                               *u = toupper(*u);
-                               u++;
-                       }
-                       if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
-                               if (port->probe_info.mfr)
-                                       kfree (port->probe_info.mfr);
-                               port->probe_info.mfr = strdup(sep);
-                       } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
-                               if (port->probe_info.model)
-                                       kfree (port->probe_info.model);
-                               port->probe_info.model = strdup(sep);
-                       } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
-                               int i;
-                               if (port->probe_info.class_name)
-                                       kfree (port->probe_info.class_name);
-                               port->probe_info.class_name = strdup(sep);
-                               for (u = sep; *u; u++)
-                                       *u = toupper(*u);
-                               for (i = 0; classes[i].token; i++) {
-                                       if (!strcmp(classes[i].token, sep)) {
-                                               port->probe_info.class = i;
-                                               goto rock_on;
-                                       }
-                               }
-                               printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
-                               port->probe_info.class = PARPORT_CLASS_OTHER;
-                       } else if (!strcmp(p, "CMD") || !strcmp(p, "COMMAND SET")) {
-                               if (port->probe_info.cmdset)
-                                       kfree (port->probe_info.cmdset);
-                               port->probe_info.cmdset = strdup(sep);
-                               /* if it speaks printer language, it's
-                                  probably a printer */
-                               if (strstr(sep, "PJL") || strstr(sep, "PCL"))
-                                       guessed_class = PARPORT_CLASS_PRINTER;
-                       } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
-                               if (port->probe_info.description)
-                                       kfree (port->probe_info.description);
-                               port->probe_info.description = strdup(sep);
-                       }
-               }
-       rock_on:
-               if (q) p = q+1; else p=NULL;
-       }
-
-       /* If the device didn't tell us its class, maybe we have managed to
-          guess one from the things it did say. */
-       if (port->probe_info.class == PARPORT_CLASS_UNSPEC)
-               port->probe_info.class = guessed_class;
-
-       kfree(txt);
-}
-
-static void pretty_print(struct parport *port)
-{
-       printk(KERN_INFO "%s: %s", port->name,
-              classes[port->probe_info.class].descr);
-       if (port->probe_info.class) {
-               printk(", %s %s", port->probe_info.mfr, 
-                      port->probe_info.model);
-       }
-       printk("\n");
-}
-
-void parport_probe_one(struct parport *port)
-{
-       char *buffer = kmalloc(2048, GFP_KERNEL);
-       int r;
-
-       MOD_INC_USE_COUNT;
-       port->probe_info.model = strdup ("Unknown device");
-       port->probe_info.mfr = strdup ("Unknown vendor");
-       port->probe_info.description = port->probe_info.cmdset = NULL;
-       port->probe_info.class = PARPORT_CLASS_UNSPEC;
-       port->probe_info.class_name = NULL;
-
-       if (!buffer) {
-               printk(KERN_ERR "%s probe: Memory squeeze.\n", port->name);
-               return;
-       }
-
-       r = parport_probe(port, buffer, 2047);
-
-       if (r < 0) {
-               printk(KERN_INFO "%s: no IEEE-1284 device present.\n",
-                      port->name);
-               port->probe_info.class = PARPORT_CLASS_LEGACY;
-       } else if (r == 0) {
-               printk(KERN_INFO "%s: no ID data returned by device.\n",
-                      port->name);
-       } else {
-               buffer[r] = 0; 
-#ifdef DEBUG_PROBE
-               printk("%s id: %s\n", port->name, buffer+2);
-#endif
-               parse_data(port, buffer+2); 
-               pretty_print(port);
-       }
-       kfree(buffer);
-       MOD_DEC_USE_COUNT;
-}
-
-#if MODULE
-int init_module(void)
-{
-       struct parport *p;
-       for (p = parport_enumerate(); p; p = p->next) 
-               parport_probe_one(p);
-       parport_probe_hook = &parport_probe_one;
-       return 0;
-}
-
-void cleanup_module(void)
-{
-       parport_probe_hook = NULL;
-}
-#endif
index 82c7e61e06e9c2fb17359f96a2c4573f356b17a6..f2b0df9c5e9c36d31e30bc49d6df4d92049e2670 100644 (file)
@@ -1672,7 +1672,6 @@ static void sab82532_wait_until_sent(struct tty_struct *tty, int timeout)
 #endif
        while (info->xmit_cnt || !info->all_sent) {
                current->state = TASK_INTERRUPTIBLE;
-               current->counter = 0;
                schedule_timeout(char_time);
                if (signal_pending(current))
                        break;
index b80b93e92f1735ef11a9bf173833269fe9c741e9..7aacd3291728e9b6e4949f6e0153e4477d1bc0f6 100644 (file)
@@ -1836,7 +1836,6 @@ su_wait_until_sent(struct tty_struct *tty, int timeout)
                printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
                current->state = TASK_INTERRUPTIBLE;
-               current->counter = 0;   /* make us low-priority */
                schedule_timeout(char_time);
                if (signal_pending(current))
                        break;
index 5904c881cf47b5379d48131685a1ceb729614f09..715a15acf5d4c920aa3a37205f3313ec416a922c 100644 (file)
@@ -158,14 +158,14 @@ int ppa_detect(Scsi_Host_Template * host)
         */
        ppa_hosts[i].mode = PPA_NIBBLE;
 
-       if (modes & PARPORT_MODE_PCPS2)
+       if (modes & PARPORT_MODE_TRISTATE)
            ppa_hosts[i].mode = PPA_PS2;
 
-       if (modes & PARPORT_MODE_PCECPPS2) {
+       if (modes & PARPORT_MODE_ECP) {
            w_ecr(ppb, 0x20);
            ppa_hosts[i].mode = PPA_PS2;
        }
-       if (modes & PARPORT_MODE_PCECPEPP)
+       if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP))
            w_ecr(ppb, 0x80);
 
        /* Done configuration */
index c1b2bb04fa64efafc2dd3cf1d8c68e3489b927b9..de0ecf1f2beeb225036cecd16b8a4542d16caeb8 100644 (file)
@@ -262,8 +262,7 @@ static struct vm_operations_struct graphics_mmap = {
        NULL,                   /* no special mmap-advise */
        sgi_graphics_nopage,    /* our magic no-page fault handler */
        NULL,                   /* no special mmap-wppage */
-       NULL,                   /* no special mmap-swapout */
-       NULL                    /* no special mmap-swapin */
+       NULL                    /* no special mmap-swapout */
 };
        
 int
index 6b93fdd2850838f22ce37031f11067fbf28caf2c..59ec035cb551077ceda52ce658bb0f7b26fafdc7 100644 (file)
@@ -302,8 +302,7 @@ static struct vm_operations_struct qcntl_mmap = {
        NULL,                   /* no special mmap-advise */
        shmiq_nopage,           /* our magic no-page fault handler */
        NULL,                   /* no special mmap-wppage */
-       NULL,                   /* no special mmap-swapout */
-       NULL                    /* no special mmap-swapin */
+       NULL                    /* no special mmap-swapout */
 };
 
 static int
index ce5a9e8a7b11bc33efabf4694ac45a9fe44ec0fa..e1166797d9c5d2fa6d7b9bc401c836e640c6c42f 100644 (file)
@@ -29,7 +29,7 @@ of hardware, support, time and development (this is from the original
 THANKS file in Inaky's driver):
 
         The following corporations have helped us in the development
-of Linux USB / UUSBD:
+        of Linux USB / UUSBD:
 
         - USAR Systems provided us with one of their excellent USB
           Evaluation Kits. It allows us to test the Linux-USB driver
index 17294cabaf0adf123af3ed16e68357df5946b2bc..534d0fed0bf34292e5c679e77d0c7fb2ee6c2386 100644 (file)
@@ -192,9 +192,11 @@ endif
 
 ifeq ($(CONFIG_FB_TGA),y)
 L_OBJS += tgafb.o
+CONFIG_FBGEN_BUILTIN = y
 else
   ifeq ($(CONFIG_FB_TGA),m)
   M_OBJS += tgafb.o
+  CONFIG_FBGEN_MODULE = y
   endif
 endif
 
index e9d5a32fc285a95aca5a891f6ec4e054d7035ee6..24e7ad742b10f255bef61c0389be126c7f24498e 100644 (file)
@@ -74,6 +74,7 @@ extern void imsttfb_init(void);
 extern void imsttfb_setup(char *options, int *ints);
 extern void dnfb_init(void);
 extern void tgafb_init(void);
+extern void tgafb_setup(char *options, int *ints);
 extern void virgefb_init(void);
 extern void virgefb_setup(char *options, int *ints);
 extern void resolver_video_setup(char *options, int *ints);
@@ -158,7 +159,7 @@ static struct {
        { "s3trio", s3triofb_init, s3triofb_setup },
 #endif 
 #ifdef CONFIG_FB_TGA
-       { "tga", tgafb_init, NULL },
+       { "tga", tgafb_init, tgafb_setup },
 #endif
 #ifdef CONFIG_FB_VIRGE
        { "virge", virgefb_init, virgefb_setup },
index fe3bc4068623914d0927f74cbcbd5c2ce3ace32c..59902a57ac1d092c08f23df8f1583523ce6b1c59 100644 (file)
@@ -1,27 +1,29 @@
 /*
  *  linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device
  *
- *     Copyright (C) 1997 Geert Uytterhoeven
+ *     Copyright (C) 1999 Martin Lucina, Tom Zerucha
+ *  
+ *  $Id: tgafb.c,v 1.12 1999/07/01 13:39:23 mato Exp $
  *
- *  This driver is partly based on the original TGA console driver
+ *  This driver is partly based on the original TGA framebuffer device, which 
+ *  was partly based on the original TGA console driver, which are
  *
- *     Copyright (C) 1995  Jay Estabrook
+ *     Copyright (C) 1997 Geert Uytterhoeven
+ *     Copyright (C) 1995 Jay Estabrook
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License. See the file COPYING in the main directory of this archive for
  *  more details.
  */
 
-
 /* KNOWN PROBLEMS/TO DO ===================================================== *
  *
  *     - How to set a single color register on 24-plane cards?
  *
- *     - Hardware cursor (useful for other graphics boards too)
- *
- *     - Support for more resolutions
+ *     - Hardware cursor/other text acceleration methods
  *
  *     - Some redraws can stall kernel for several seconds
+ *       [This should now be solved by the fast memmove() patch in 2.3.6]
  *
  * KNOWN PROBLEMS/TO DO ==================================================== */
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb32.h>
+#include "tgafb.h"
 
 
-/* TGA hardware description (minimal) */
-/*
- * Offsets within Memory Space
- */
-#define        TGA_ROM_OFFSET                  0x0000000
-#define        TGA_REGS_OFFSET                 0x0100000
-#define        TGA_8PLANE_FB_OFFSET            0x0200000
-#define        TGA_24PLANE_FB_OFFSET           0x0804000
-#define        TGA_24PLUSZ_FB_OFFSET           0x1004000
-
-#define        TGA_PLANEMASK_REG               0x0028
-#define        TGA_MODE_REG                    0x0030
-#define        TGA_RASTEROP_REG                0x0034
-#define        TGA_DEEP_REG                    0x0050
-#define        TGA_PIXELMASK_REG               0x005c
-#define        TGA_CURSOR_BASE_REG             0x0060
-#define        TGA_HORIZ_REG                   0x0064
-#define        TGA_VERT_REG                    0x0068
-#define        TGA_BASE_ADDR_REG               0x006c
-#define        TGA_VALID_REG                   0x0070
-#define        TGA_CURSOR_XY_REG               0x0074
-#define        TGA_INTR_STAT_REG               0x007c
-#define        TGA_RAMDAC_SETUP_REG            0x00c0
-#define        TGA_BLOCK_COLOR0_REG            0x0140
-#define        TGA_BLOCK_COLOR1_REG            0x0144
-#define        TGA_CLOCK_REG                   0x01e8
-#define        TGA_RAMDAC_REG                  0x01f0
-#define        TGA_CMD_STAT_REG                0x01f8
-
-/*
- * useful defines for managing the BT485 on the 8-plane TGA
- */
-#define        BT485_READ_BIT                  0x01
-#define        BT485_WRITE_BIT                 0x00
-
-#define        BT485_ADDR_PAL_WRITE            0x00
-#define        BT485_DATA_PAL                  0x02
-#define        BT485_PIXEL_MASK                0x04
-#define        BT485_ADDR_PAL_READ             0x06
-#define        BT485_ADDR_CUR_WRITE            0x08
-#define        BT485_DATA_CUR                  0x0a
-#define        BT485_CMD_0                     0x0c
-#define        BT485_ADDR_CUR_READ             0x0e
-#define        BT485_CMD_1                     0x10
-#define        BT485_CMD_2                     0x12
-#define        BT485_STATUS                    0x14
-#define        BT485_CMD_3                     0x14
-#define        BT485_CUR_RAM                   0x16
-#define        BT485_CUR_LOW_X                 0x18
-#define        BT485_CUR_HIGH_X                0x1a
-#define        BT485_CUR_LOW_Y                 0x1c
-#define        BT485_CUR_HIGH_Y                0x1e
-
-/*
- * useful defines for managing the BT463 on the 24-plane TGAs
- */
-#define        BT463_ADDR_LO           0x0
-#define        BT463_ADDR_HI           0x1
-#define        BT463_REG_ACC           0x2
-#define        BT463_PALETTE           0x3
+    /*
+     *  Global declarations
+     */
 
-#define        BT463_CUR_CLR_0         0x0100
-#define        BT463_CUR_CLR_1         0x0101
+static struct tgafb_info fb_info;
+static struct tgafb_par current_par;
+static int current_par_valid = 0;
+static struct display disp;
 
-#define        BT463_CMD_REG_0         0x0201
-#define        BT463_CMD_REG_1         0x0202
-#define        BT463_CMD_REG_2         0x0203
+static char __initdata default_fontname[40] = { 0 };
+static struct fb_var_screeninfo default_var;
+static int default_var_valid = 0;
 
-#define        BT463_READ_MASK_0       0x0205
-#define        BT463_READ_MASK_1       0x0206
-#define        BT463_READ_MASK_2       0x0207
-#define        BT463_READ_MASK_3       0x0208
+static int currcon = 0;
 
-#define        BT463_BLINK_MASK_0      0x0209
-#define        BT463_BLINK_MASK_1      0x020a
-#define        BT463_BLINK_MASK_2      0x020b
-#define        BT463_BLINK_MASK_3      0x020c
+#define arraysize(x)   (sizeof(x)/sizeof(*(x)))
 
-#define        BT463_WINDOW_TYPE_BASE  0x0300
+static struct { u_char red, green, blue, pad; } palette[256];
+#ifdef FBCON_HAS_CFB32
+static u32 fbcon_cfb32_cmap[16];
+#endif
 
 
-int tga_type;
-unsigned int tga_mem_base;
-unsigned long tga_fb_base;
-unsigned long tga_regs_base;
+    /*
+     *  Hardware presets
+     */
 
-static unsigned int fb_offset_presets[4] __initdata = {
+static unsigned int fb_offset_presets[4] = {
        TGA_8PLANE_FB_OFFSET,
        TGA_24PLANE_FB_OFFSET,
        0xffffffff,
        TGA_24PLUSZ_FB_OFFSET
 };
 
-static unsigned int deep_presets[4] __initdata = {
+static unsigned int deep_presets[4] = {
   0x00014000,
   0x0001440d,
   0xffffffff,
   0x0001441d
 };
 
-static unsigned int rasterop_presets[4] __initdata = {
+static unsigned int rasterop_presets[4] = {
   0x00000003,
   0x00000303,
   0xffffffff,
   0x00000303
 };
 
-static unsigned int mode_presets[4] __initdata = {
+static unsigned int mode_presets[4] = {
   0x00002000,
   0x00002300,
   0xffffffff,
   0x00002300
 };
 
-static unsigned int base_addr_presets[4] __initdata = {
+static unsigned int base_addr_presets[4] = {
   0x00000000,
   0x00000001,
   0xffffffff,
   0x00000001
 };
 
-#define TGA_WRITE_REG(v,r) \
-       { writel((v), tga_regs_base+(r)); mb(); }
-
-#define TGA_READ_REG(r) readl(tga_regs_base+(r))
-
-#define BT485_WRITE(v,r) \
-         TGA_WRITE_REG((r),TGA_RAMDAC_SETUP_REG);              \
-         TGA_WRITE_REG(((v)&0xff)|((r)<<8),TGA_RAMDAC_REG);
-
-#define BT463_LOAD_ADDR(a) \
-       TGA_WRITE_REG(BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); \
-       TGA_WRITE_REG((BT463_ADDR_LO<<10)|((a)&0xff), TGA_RAMDAC_REG); \
-       TGA_WRITE_REG(BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); \
-       TGA_WRITE_REG((BT463_ADDR_HI<<10)|(((a)>>8)&0xff), TGA_RAMDAC_REG);
-
-#define BT463_WRITE(m,a,v) \
-       BT463_LOAD_ADDR((a)); \
-       TGA_WRITE_REG(((m)<<2),TGA_RAMDAC_SETUP_REG); \
-       TGA_WRITE_REG(((m)<<10)|((v)&0xff),TGA_RAMDAC_REG);
-
-
-unsigned char PLLbits[7] __initdata = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
-
-const unsigned long bt485_cursor_source[64] __initdata = {
-#if 1
-  0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
-  0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
-  0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
-  0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000,
-#else
-  0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
-  0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
-  0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
-  0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
-#endif
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+const unsigned int bt463_cursor_source[4] = {
+  0xffff0000, 0x00000000, 0x00000000, 0x00000000
 };
 
-const unsigned int bt463_cursor_source[256] __initdata = {
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0xffff0000, 0x00000000, 0x00000000, 0x00000000,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-};
 
+    /*
+     *  Predefined video modes
+     *  This is a subset of the standard VESA modes, recalculated from XFree86.
+     *
+     *  XXX Should we store these in terms of the encoded par structs? Even better,
+     *      fbcon should provide a general mechanism for doing something like this.
+     */
 
-#define arraysize(x)   (sizeof(x)/sizeof(*(x)))
+static struct fb_videomode tgafb_predefined[] __initdata = {
+    { "640x480-60", {
+       640, 480, 640, 480, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "800x600-56", {
+       800, 600, 800, 600, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 27777, 128, 24, 22, 1, 72, 2,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "640x480-72", {
+       640, 480, 640, 480, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 31746, 144, 40, 30, 8, 40, 3,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "800x600-60", {
+       800, 600, 800, 600, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4,
+       FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "800x600-72", {
+       800, 600, 800, 600, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 20000, 64, 56, 23, 37, 120, 6,
+       FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1024x768-60", {
+       1024, 768, 1024, 768, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 15384, 168, 8, 29, 3, 144, 6,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1152x864-60", {
+       1152, 864, 1152, 864, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 11123, 208, 64, 16, 4, 256, 8,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1024x768-70", {
+       1024, 768, 1024, 768, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 13333, 144, 24, 29, 3, 136, 6,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1024x768-76", {
+       1024, 768, 1024, 768, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 11764, 208, 8, 36, 16, 120, 3,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1152x864-70", {
+       1152, 864, 1152, 864, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 10869, 106, 56, 20, 1, 160, 10,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1280x1024-61", {
+       1280, 1024, 1280, 1024, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 9090, 200, 48, 26, 1, 184, 3,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1024x768-85", {
+       1024, 768, 1024, 768, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 10111, 192, 32, 34, 14, 160, 6,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1280x1024-70", {
+       1280, 1024, 1280, 1024, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 7905, 224, 32, 28, 8, 160, 8,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1152x864-84", {
+       1152, 864, 1152, 864, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 7407, 184, 312, 32, 0, 128, 12,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1280x1024-76", {
+       1280, 1024, 1280, 1024, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 7407, 248, 32, 34, 3, 104, 3,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "1280x1024-85", {
+       1280, 1024, 1280, 1024, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 6349, 224, 64, 44, 1, 160, 3,
+       0,
+       FB_VMODE_NONINTERLACED
+    }},
+
+    /* These are modes used by the two fixed-frequency monitors I have at home. 
+     * You may or may not find these useful.
+     */
 
-static int currcon = 0;
-static struct display disp;
-static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
-#ifdef FBCON_HAS_CFB32
-static u32 fbcon_cfb32_cmap[16];
-#endif
+    { "WYSE1", {                       /* 1280x1024 @ 72 Hz, 130 Mhz clock */
+       1280, 1024, 1280, 1024, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 7692, 192, 32, 47, 0, 192, 5,
+       FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+       FB_VMODE_NONINTERLACED
+    }},
+    { "IBM3", {                                /* 1280x1024 @ 70 Hz, 120 Mhz clock */
+       1280, 1024, 1280, 1024, 0, 0, 0, 0,
+       {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+       0, 0, -1, -1, FB_ACCELF_TEXT, 8333, 192, 32, 47, 0, 192, 5,
+       0,
+       FB_VMODE_NONINTERLACED
+    }}
+};
 
-static struct fb_fix_screeninfo fb_fix = { { "DEC TGA ", } };
-static struct fb_var_screeninfo fb_var = { 0, };
+#define NUM_TOTAL_MODES    arraysize(tgafb_predefined)
 
 
     /*
      *  Interface used by the world
      */
 
+static void tgafb_detect(void);
+static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
+                       struct fb_info_gen *info);
+static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
+                       struct fb_info_gen *info);
+static int tgafb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
+                       struct fb_info_gen *info);
+static void tgafb_get_par(void *fb_par, struct fb_info_gen *info);
+static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info);
+static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, 
+               u_int *transp, struct fb_info *info);
+static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 
+               u_int transp, struct fb_info *info);
+static int tgafb_pan_display(const struct fb_var_screeninfo *var,
+               struct fb_info_gen *info);
+static int tgafb_blank(int blank, struct fb_info_gen *info);
+static void tgafb_set_disp(const void *fb_par, struct display *disp, 
+               struct fb_info_gen *info);
+
 static int tgafb_open(struct fb_info *info, int user);
 static int tgafb_release(struct fb_info *info, int user);
-static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con,
-                        struct fb_info *info);
-static int tgafb_get_var(struct fb_var_screeninfo *var, int con,
-                        struct fb_info *info);
-static int tgafb_set_var(struct fb_var_screeninfo *var, int con,
-                        struct fb_info *info);
-static int tgafb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info);
-static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-                         struct fb_info *info);
-static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-                         struct fb_info *info);
-static int tgafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info);
-
-
-    /*
-     *  Interface to the low level console driver
-     */
-
+void tgafb_setup(char *options, int *ints);
 void tgafb_init(void);
-static int tgafbcon_switch(int con, struct fb_info *info);
-static int tgafbcon_updatevar(int con, struct fb_info *info);
-static void tgafbcon_blank(int blank, struct fb_info *info);
-
+void tgafb_cleanup(struct fb_info *info);
 
-    /*
-     *  Internal routines
-     */
-
-static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                          u_int *transp, struct fb_info *info);
-static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                          u_int transp, struct fb_info *info);
+static void tgafb_set_pll(int f);
 #if 1
-static void tga_update_palette(void);
+static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info);
+static void tgafb_update_palette(void);
 #endif
-static void do_install_cmap(int con, struct fb_info *info);
-
-
-static struct fb_ops tgafb_ops = {
-    tgafb_open, tgafb_release, tgafb_get_fix, tgafb_get_var, tgafb_set_var,
-    tgafb_get_cmap, tgafb_set_cmap, tgafb_pan_display, tgafb_ioctl
-};
 
 
     /*
-     *  Open/Release the frame buffer device
+     *  Chipset specific functions
      */
 
-static int tgafb_open(struct fb_info *info, int user)
-{
-    /*                                                                     
-     *  Nothing, only a usage count for the moment                          
-     */                                                                    
 
-    MOD_INC_USE_COUNT;
-    return(0);                              
-}
-        
-static int tgafb_release(struct fb_info *info, int user)
+static void tgafb_detect(void)
 {
-    MOD_DEC_USE_COUNT;
-    return(0);                                                    
+    return;
 }
 
 
-    /*
-     *  Get the Fixed Part of the Display
-     */
-
-static int tgafb_get_fix(struct fb_fix_screeninfo *fix, int con,
-                        struct fb_info *info)
+static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
+       struct fb_info_gen *info)
 {
-    memcpy(fix, &fb_fix, sizeof(fb_fix));
-    return 0;
-}
+    struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
+    strcpy(fix->id, fb_info.gen.info.modename);
 
-    /*
-     *  Get the User Defined Part of the Display
-     */
+    fix->type = FB_TYPE_PACKED_PIXELS;
+    fix->type_aux = 0;
+    if (fb_info.tga_type == 0) /* 8-plane */
+       fix->visual = FB_VISUAL_PSEUDOCOLOR;
+    else /* 24-plane or 24plusZ */
+       fix->visual = FB_VISUAL_TRUECOLOR;
+
+    fix->line_length = par->xres * (par->bits_per_pixel >> 3);
+    fix->smem_start = (char *)__pa(fb_info.tga_fb_base + dense_mem(fb_info.tga_fb_base));
+    fix->smem_len = fix->line_length * par->yres;
+    fix->mmio_start = (char *)__pa(fb_info.tga_regs_base);
+    fix->mmio_len = 0x1000;            /* Is this sufficient? */
+    fix->xpanstep = fix->ypanstep = fix->ywrapstep = 0;
+    fix->accel = FB_ACCEL_DEC_TGA;
 
-static int tgafb_get_var(struct fb_var_screeninfo *var, int con,
-                        struct fb_info *info)
-{
-    memcpy(var, &fb_var, sizeof(fb_var));
     return 0;
 }
 
 
-    /*
-     *  Set the User Defined Part of the Display
-     */
-
-static int tgafb_set_var(struct fb_var_screeninfo *var, int con,
-                        struct fb_info *info)
+static int tgafb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
+       struct fb_info_gen *info)
 {
-    struct display *display;
-    int oldbpp = -1, err;
-
-    if (con >= 0)
-       display = &fb_display[con];
-    else
-       display = &disp;        /* used during initialization */
-
-    if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
-       var->xres_virtual > fb_var.xres_virtual ||
-       var->yres_virtual > fb_var.yres_virtual ||
-       var->bits_per_pixel > fb_var.bits_per_pixel ||
-       var->nonstd ||
-       (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
-       return -EINVAL;
-    memcpy(var, &fb_var, sizeof(fb_var));
+    struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
-    if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-       oldbpp = display->var.bits_per_pixel;
-       display->var = *var;
-    }
-    if (oldbpp != var->bits_per_pixel) {
-       if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-           return err;
-       do_install_cmap(con, info);
+    /* round up some */
+    if (fb_info.tga_type == 0) {
+       if (var->bits_per_pixel > 8) {
+           return -EINVAL;
+       }
+       par->bits_per_pixel = 8;
+    } else {
+       if (var->bits_per_pixel > 32) {
+           return -EINVAL;
+       }
+       par->bits_per_pixel = 32;
     }
-    return 0;
-}
-
 
-    /*
-     *  Pan or Wrap the Display
-     *
-     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-     */
-
-static int tgafb_pan_display(struct fb_var_screeninfo *var, int con,
-                            struct fb_info *info)
-{
-    if (var->xoffset || var->yoffset)
+    /* check the values for sanity */
+    if (var->xres_virtual != var->xres ||
+       var->yres_virtual != var->yres ||
+       var->nonstd || (1000000000/var->pixclock) > TGA_PLL_MAX_FREQ ||
+       (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED
+#if 0  
+       || !fbmon_valid_timings(var->pixclock, var->htotal, var->vtotal, info))
+#else
+       )
+#endif
        return -EINVAL;
-    else
-       return 0;
-}
 
-    /*
-     *  Get the Colormap
-     */
+    /* encode video timings */
+    par->htimings = ((var->xres/4) & TGA_HORIZ_ACT_LSB) | 
+       (((var->xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB);
+    par->vtimings = (var->yres & TGA_VERT_ACTIVE);
+    par->htimings |= ((var->right_margin/4) << 9) & TGA_HORIZ_FP;
+    par->vtimings |= (var->lower_margin << 11) & TGA_VERT_FP;
+    par->htimings |= ((var->hsync_len/4) << 14) & TGA_HORIZ_SYNC;
+    par->vtimings |= (var->vsync_len << 16) & TGA_VERT_SYNC;
+    par->htimings |= ((var->left_margin/4) << 21) & TGA_HORIZ_BP;
+    par->vtimings |= (var->upper_margin << 22) & TGA_VERT_BP;
+
+    if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+       par->htimings |= TGA_HORIZ_POLARITY;
+    if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+       par->vtimings |= TGA_VERT_POLARITY;
+    /* what about sync on green? */
+
+    /* store other useful values in par */
+    par->xres = var->xres; 
+    par->yres = var->yres;
+    par->pll_freq = 1000000000/var->pixclock;
+    par->bits_per_pixel = var->bits_per_pixel;
 
-static int tgafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-                         struct fb_info *info)
-{
-    if (con == currcon) /* current console? */
-       return fb_get_cmap(cmap, kspc, tgafb_getcolreg, info);
-    else if (fb_display[con].cmap.len) /* non default colormap? */
-       fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-    else
-       fb_copy_cmap(fb_default_cmap(256), cmap, kspc ? 0 : 2);
     return 0;
 }
 
-    /*
-     *  Set the Colormap
-     */
 
-static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-                         struct fb_info *info)
+static int tgafb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
+       struct fb_info_gen *info)
 {
-    int err;
-
-    if (!fb_display[con].cmap.len) {   /* no colormap allocated? */
-       if ((err = fb_alloc_cmap(&fb_display[con].cmap, 256, 0)))
-           return err;
+    struct tgafb_par *par = (struct tgafb_par *)fb_par;
+
+    /* decode video timings */
+    var->xres = ((par->htimings & TGA_HORIZ_ACT_LSB) | ((par->htimings & TGA_HORIZ_ACT_MSB) >> 19)) * 4;
+    var->yres = (par->vtimings & TGA_VERT_ACTIVE);
+    var->right_margin = ((par->htimings & TGA_HORIZ_FP) >> 9) * 4;
+    var->lower_margin = ((par->vtimings & TGA_VERT_FP) >> 11);
+    var->hsync_len = ((par->htimings & TGA_HORIZ_SYNC) >> 14) * 4;
+    var->vsync_len = ((par->vtimings & TGA_VERT_SYNC) >> 16);
+    var->left_margin = ((par->htimings & TGA_HORIZ_BP) >> 21) * 4;
+    var->upper_margin = ((par->vtimings & TGA_VERT_BP) >> 22);
+
+    if (par->htimings & TGA_HORIZ_POLARITY) 
+       var->sync |= FB_SYNC_HOR_HIGH_ACT;
+    if (par->vtimings & TGA_VERT_POLARITY)
+       var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+    var->xres_virtual = var->xres;
+    var->yres_virtual = var->yres;
+    var->xoffset = var->yoffset = 0;
+
+    /* depth-related */
+    if (fb_info.tga_type == 0) {
+       var->red.offset = 0;
+       var->green.offset = 0;
+       var->blue.offset = 0;
+    } else {
+       /* XXX: is this correct? */
+       var->red.offset = 16;
+       var->green.offset = 8;
+       var->blue.offset = 0;
     }
-    if (con == currcon) {              /* current console? */
-       err = fb_set_cmap(cmap, kspc, tgafb_setcolreg, info);
-#if 1
-       if (tga_type != 0)
-               tga_update_palette();
-#endif
-       return err;
-    } else
-       fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+    var->bits_per_pixel = par->bits_per_pixel;
+    var->grayscale = 0;
+    var->red.length = var->green.length = var->blue.length = 8;
+    var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+    var->transp.offset = var->transp.length = var->transp.msb_right = 0;
+
+    /* others */
+    var->xoffset = var->yoffset = 0;
+    var->pixclock = 1000000000/par->pll_freq;
+    var->nonstd = 0;
+    var->activate = 0;
+    var->height = var->width = -1;
+    var->accel_flags = 0;
+
     return 0;
 }
 
 
-static int tgafb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                      u_long arg, int con, struct fb_info *info)
+static void tgafb_get_par(void *fb_par, struct fb_info_gen *info)
 {
-    return -EINVAL;
-}
+    struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
+    if (current_par_valid)
+       *par = current_par;
+    else {
+       if (fb_info.tga_type == 0)
+           default_var.bits_per_pixel = 8;
+       else
+           default_var.bits_per_pixel = 32;
 
-    /*
-     *  Initialisation
-     */
+       tgafb_decode_var(&default_var, par, info);
+    }
+}
 
-__initfunc(void tgafb_init(void))
+
+static void tgafb_set_par(const void *fb_par, struct fb_info_gen *info)
 {
     int i, j, temp;
-    unsigned char *cbp;
-    struct pci_dev *pdev;
-
-    pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL);
-    if (!pdev)
-       return;
-    tga_mem_base = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
-#ifdef DEBUG
-    printk("tgafb_init: mem_base 0x%x\n", tga_mem_base);
-#endif /* DEBUG */
+    struct tgafb_par *par = (struct tgafb_par *)fb_par;
 
-    tga_type = (readl((unsigned long)tga_mem_base) >> 12) & 0x0f;
-    switch (tga_type) {
-       case 0:
-           strcat(fb_fix.id, "8plane");
-           break;
-       case 1:
-           strcat(fb_fix.id, "24plane");
-           break;
-       case 3:
-           strcat(fb_fix.id, "24plusZ");
-           break;
-       default:
-           printk("TGA type (0x%x) unrecognized!\n", tga_type);
+#if 0
+    /* XXX this will break console switching with X11, maybe I need to test KD_GRAPHICS? */
+    /* if current_par is valid, check to see if we need to change anything */
+    if (current_par_valid) {
+       if (!memcmp(par, &current_par, sizeof current_par)) {
            return;
+       }
     }
-
-    tga_regs_base = ((unsigned long)tga_mem_base + TGA_REGS_OFFSET);
-    tga_fb_base = ((unsigned long)tga_mem_base + fb_offset_presets[tga_type]);
+#endif
+    current_par = *par;
+    current_par_valid = 1;
 
     /* first, disable video timing */
     TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */
-
+    
     /* write the DEEP register */
     while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */
       continue;
 
     mb();
-    TGA_WRITE_REG(deep_presets[tga_type], TGA_DEEP_REG);
+    TGA_WRITE_REG(deep_presets[fb_info.tga_type], TGA_DEEP_REG);
     while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */
        continue;
     mb();
 
     /* write some more registers */
-    TGA_WRITE_REG(rasterop_presets[tga_type], TGA_RASTEROP_REG);
-    TGA_WRITE_REG(mode_presets[tga_type], TGA_MODE_REG);
-    TGA_WRITE_REG(base_addr_presets[tga_type], TGA_BASE_ADDR_REG);
-
-    /* write the PLL for 640x480 @ 60Hz */
-    for (i = 0; i <= 6; i++) {
-       for (j = 0; j <= 7; j++) {
-           temp = (PLLbits[i] >> (7-j)) & 1;
-           if (i == 6 && j == 7)
-               temp |= 2;
-           TGA_WRITE_REG(temp, TGA_CLOCK_REG);
-       }
-    }
+    TGA_WRITE_REG(rasterop_presets[fb_info.tga_type], TGA_RASTEROP_REG);
+    TGA_WRITE_REG(mode_presets[fb_info.tga_type], TGA_MODE_REG);
+    TGA_WRITE_REG(base_addr_presets[fb_info.tga_type], TGA_BASE_ADDR_REG);
+
+    /* calculate & write the PLL */
+    tgafb_set_pll(par->pll_freq);
 
     /* write some more registers */
     TGA_WRITE_REG(0xffffffff, TGA_PLANEMASK_REG);
@@ -523,21 +507,19 @@ __initfunc(void tgafb_init(void))
     TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR0_REG);
     TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR1_REG);
 
-    /* init video timing regs for 640x480 @ 60 Hz */
-    TGA_WRITE_REG(0x018608a0, TGA_HORIZ_REG);
-    TGA_WRITE_REG(0x084251e0, TGA_VERT_REG);
-
-    if (tga_type == 0) { /* 8-plane */
+    /* init video timing regs */
+    TGA_WRITE_REG(par->htimings, TGA_HORIZ_REG);
+    TGA_WRITE_REG(par->vtimings, TGA_VERT_REG);
 
-       fb_var.bits_per_pixel = 8;
-       fb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
+    /* initalise RAMDAC */
+    if (fb_info.tga_type == 0) { /* 8-plane */
 
        /* init BT485 RAMDAC registers */
        BT485_WRITE(0xa2, BT485_CMD_0);
        BT485_WRITE(0x01, BT485_ADDR_PAL_WRITE);
        BT485_WRITE(0x14, BT485_CMD_3); /* cursor 64x64 */
        BT485_WRITE(0x40, BT485_CMD_1);
-       BT485_WRITE(0x22, BT485_CMD_2); /* WIN cursor type */
+       BT485_WRITE(0x20, BT485_CMD_2); /* cursor off, for now */
        BT485_WRITE(0xff, BT485_PIXEL_MASK);
 
        /* fill palette registers */
@@ -560,6 +542,7 @@ __initfunc(void tgafb_init(void))
            TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
        }         
 
+#if 0
        /* initialize RAMDAC cursor colors */
        BT485_WRITE(0, BT485_ADDR_CUR_WRITE);
 
@@ -581,19 +564,39 @@ __initfunc(void tgafb_init(void))
 
        /* initialize RAMDAC cursor RAM */
        BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE);
-       cbp = (unsigned char *)bt485_cursor_source;
-       for (i = 0; i < 512; i++) {
-           BT485_WRITE(*cbp++, BT485_CUR_RAM);
-       }
+
+       for (i = 0; i < tga_font_height_padded; i++)
+           for (j = 7; j >= 0; j--) {
+#if 0
+               /* note that this is for a top-right alignment
+                * - top left is commented out */
+               if( j > /*<*/ ((tga_font_width - 1) >> 3) ) {
+                   BT485_WRITE(0, BT485_CUR_RAM);
+               }
+               else if( j == ((tga_font_width - 1) >> 3) ) {
+                   BT485_WRITE((0xff >> /*<<*/
+                               (7 - ((tga_font_width - 1)&7))) , BT485_CUR_RAM);
+               }
+               else {
+                   BT485_WRITE(0xff, BT485_CUR_RAM);
+               }
+#else
+               BT485_WRITE(0, BT485_CUR_RAM);
+#endif
+           }
+       for (i = tga_font_height_padded; i < 64; i++)
+           for (j = 0; j < 8; j++) {
+               BT485_WRITE(0, BT485_CUR_RAM);
+           }
+       /* mask? */
+
        for (i = 0; i < 512; i++) {
            BT485_WRITE(0xff, BT485_CUR_RAM);
        }
+#endif
 
     } else { /* 24-plane or 24plusZ */
 
-       fb_var.bits_per_pixel = 32;
-       fb_fix.visual = FB_VISUAL_TRUECOLOR;
-
        TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */
 
        /*
@@ -652,6 +655,7 @@ __initfunc(void tgafb_init(void))
            TGA_WRITE_REG(0x80|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
        }
 
+#if 0
        /*
         * init cursor colors
         */
@@ -679,135 +683,204 @@ __initfunc(void tgafb_init(void))
        temp = tga_fb_base - 1024; /* this assumes video starts at base
                                     and base is beyond memory start*/
 
-       for (i = 0; i < 256; i++) {
-           writel(bt463_cursor_source[i], temp + i*4);
-       }
+       for (i = 0; i < tga_font_height_padded*4; i++)
+           writel(bt463_cursor_source[i&3], temp + i*4);
+       for (i = tga_font_height_padded*4; i < 256; i++)
+           writel(0, temp + i*4);
        TGA_WRITE_REG(temp & 0x000fffff, TGA_CURSOR_BASE_REG);
+#endif
     }
 
     /* finally, enable video scan
-       (and pray for the monitor... :-) */
+       (and pray for the monitor... :-) */
     TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */
+}
 
-    fb_var.xres = fb_var.xres_virtual = 640;
-    fb_var.yres = fb_var.yres_virtual = 480;
-    fb_fix.line_length = 80*fb_var.bits_per_pixel;
-    fb_fix.smem_start = (char *)__pa(tga_fb_base + dense_mem(tga_fb_base));
-    fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
-    fb_fix.type = FB_TYPE_PACKED_PIXELS;
-    fb_fix.type_aux = 0;
-    fb_fix.mmio_start = (char *)__pa(tga_regs_base);
-    fb_fix.mmio_len = 0x1000;          /* Is this sufficient? */
-    fb_fix.accel = FB_ACCEL_DEC_TGA;
-
-    fb_var.xoffset = fb_var.yoffset = 0;
-    fb_var.grayscale = 0;
-    if (tga_type == 0) { /* 8-plane */
-       fb_var.red.offset = 0;
-       fb_var.green.offset = 0;
-       fb_var.blue.offset = 0;
-    } else { /* 24-plane or 24plusZ */
-       /* XXX: is this correct?? */
-       fb_var.red.offset = 16;
-       fb_var.green.offset = 8;
-       fb_var.blue.offset = 0;
+
+#define DIFFCHECK(x) { if( m <= 0x3f ) { \
+      int delta = f - (TGA_PLL_BASE_FREQ * (x)) / (r << shift); \
+      if (delta < 0) delta = -delta; \
+      if (delta < min_diff) min_diff = delta, vm = m, va = a, vr = r; } }
+
+static void tgafb_set_pll(int f)
+{
+    int                 n, shift, base, min_diff, target;
+    int                 r,a,m,vm = 34, va = 1, vr = 30;
+
+    for( r = 0 ; r < 12 ; r++ )
+       TGA_WRITE_REG(!r, TGA_CLOCK_REG);
+
+    if (f > TGA_PLL_MAX_FREQ)
+       f = TGA_PLL_MAX_FREQ;
+
+    if (f >= TGA_PLL_MAX_FREQ / 2)
+       shift = 0;
+    else if (f >= TGA_PLL_MAX_FREQ / 4)
+       shift = 1;
+    else
+       shift = 2;
+
+    TGA_WRITE_REG(shift & 1, TGA_CLOCK_REG);
+    TGA_WRITE_REG(shift >> 1, TGA_CLOCK_REG);
+
+    for( r = 0 ; r < 10 ; r++ ) {
+       TGA_WRITE_REG(0, TGA_CLOCK_REG);
     }
-    fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
-    fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
-    fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
-    fb_var.nonstd = 0;
-    fb_var.activate = 0;
-    fb_var.height = fb_var.width = -1;
-    fb_var.accel_flags = 0;
-    fb_var.pixclock = 39722;
-    fb_var.left_margin = 40;
-    fb_var.right_margin = 24;
-    fb_var.upper_margin = 32;
-    fb_var.lower_margin = 11;
-    fb_var.hsync_len = 96;
-    fb_var.vsync_len = 2;
-    fb_var.sync = 0;
-    fb_var.vmode = FB_VMODE_NONINTERLACED;
-
-    disp.var = fb_var;
-    disp.cmap.start = 0;
-    disp.cmap.len = 0;
-    disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
-    disp.screen_base = (char *)tga_fb_base + dense_mem(tga_fb_base);
-    disp.visual = fb_fix.visual;
-    disp.type = fb_fix.type;
-    disp.type_aux = fb_fix.type_aux;
-    disp.ypanstep = 0;
-    disp.ywrapstep = 0;
-    disp.line_length = fb_fix.line_length;
-    disp.can_soft_blank = 1;
-    disp.inverse = 0;
-    switch (tga_type) {
-#ifdef FBCON_HAS_CFB8
-       case 0: /* 8-plane */
-           disp.dispsw = &fbcon_cfb8;
-           break;
-#endif
-#ifdef FBCON_HAS_CFB32
-       case 1: /* 24-plane */
-       case 3: /* 24plusZ */
-           disp.dispsw = &fbcon_cfb32;
-           disp.dispsw_data = &fbcon_cfb32_cmap;
-           break;
-#endif
-       default:
-           disp.dispsw = &fbcon_dummy;
+
+    if (f <= 120000) {
+       TGA_WRITE_REG(0, TGA_CLOCK_REG);
+       TGA_WRITE_REG(0, TGA_CLOCK_REG);
     }
-    disp.scrollmode = SCROLL_YREDRAW;
-
-    strcpy(fb_info.modename, fb_fix.id);
-    fb_info.node = -1;
-    fb_info.fbops = &tgafb_ops;
-    fb_info.disp = &disp;
-    fb_info.fontname[0] = '\0';
-    fb_info.changevar = NULL;
-    fb_info.switch_con = &tgafbcon_switch;
-    fb_info.updatevar = &tgafbcon_updatevar;
-    fb_info.blank = &tgafbcon_blank;
-    fb_info.flags = FBINFO_FLAG_DEFAULT;
-
-    tgafb_set_var(&fb_var, -1, &fb_info);
-
-    if (register_framebuffer(&fb_info) < 0)
-       return;
+    else if (f <= 200000) {
+       TGA_WRITE_REG(1, TGA_CLOCK_REG);
+       TGA_WRITE_REG(0, TGA_CLOCK_REG);
+    }
+    else {
+       TGA_WRITE_REG(0, TGA_CLOCK_REG);
+       TGA_WRITE_REG(1, TGA_CLOCK_REG);
+    }
+
+    TGA_WRITE_REG(1, TGA_CLOCK_REG);
+    TGA_WRITE_REG(0, TGA_CLOCK_REG);
+    TGA_WRITE_REG(0, TGA_CLOCK_REG);
+    TGA_WRITE_REG(1, TGA_CLOCK_REG);
+    TGA_WRITE_REG(0, TGA_CLOCK_REG);
+    TGA_WRITE_REG(1, TGA_CLOCK_REG);
+
+    target = (f << shift) / TGA_PLL_BASE_FREQ;
+    min_diff = TGA_PLL_MAX_FREQ;
+
+    r = 7 / target;
+    if (!r)
+       r = 1;
+
+    base = target * r;
+    while (base < 449) {
+       for (n = base < 7 ? 7 : base ; n < base + target && n < 449; n++) {
+       m = ((n + 3) / 7) - 1;
+       a = 0;
+       DIFFCHECK((m + 1) * 7);
+       m++;
+       DIFFCHECK((m + 1) * 7);
+       m = (n / 6) - 1;
+       if( (a = n % 6))
+           DIFFCHECK( n );
+       }
+       r++;
+       base += target;
+    }
+
+    vr--;
 
-    printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
-          fb_fix.id);
+    for( r=0; r<8 ; r++) {
+       TGA_WRITE_REG((vm >> r) & 1, TGA_CLOCK_REG);
+    }
+    for( r=0; r<8 ; r++) {
+       TGA_WRITE_REG((va >> r) & 1, TGA_CLOCK_REG);
+    }
+    for( r=0; r<7 ; r++) {
+       TGA_WRITE_REG((vr >> r) & 1, TGA_CLOCK_REG);
+    }
+    TGA_WRITE_REG(((vr >> 7) & 1)|2, TGA_CLOCK_REG);
 }
 
 
-static int tgafbcon_switch(int con, struct fb_info *info)
+static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+                         u_int *transp, struct fb_info *info)
 {
-    /* Do we have to save the colormap? */
-    if (fb_display[currcon].cmap.len)
-       fb_get_cmap(&fb_display[currcon].cmap, 1, tgafb_getcolreg, info);
+    if (regno > 255)
+       return 1;
+    *red = (palette[regno].red<<8) | palette[regno].red;
+    *green = (palette[regno].green<<8) | palette[regno].green;
+    *blue = (palette[regno].blue<<8) | palette[regno].blue;
+    *transp = 0;
+    return 0;
+}
+
+
+static int tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                         u_int transp, struct fb_info *info)
+{
+    if (regno > 255)
+       return 1;
+    red >>= 8;
+    green >>= 8;
+    blue >>= 8;
+    palette[regno].red = red;
+    palette[regno].green = green;
+    palette[regno].blue = blue;
+
+#ifdef FBCON_HAS_CFB32
+    if (regno < 16 && fb_info.tga_type != 0)
+       fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+#endif
+
+    if (fb_info.tga_type == 0) { /* 8-plane */
+        BT485_WRITE(regno, BT485_ADDR_PAL_WRITE);
+        TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
+        TGA_WRITE_REG(red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+        TGA_WRITE_REG(green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+        TGA_WRITE_REG(blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+    }                                                    
+    /* How to set a single color register on 24-plane cards?? */
 
-    currcon = con;
-    /* Install new colormap */
-    do_install_cmap(con, info);
     return 0;
 }
 
+#if 1
     /*
-     *  Update the `var' structure (called by fbcon.c)
+     * FIXME: since I don't know how to set a single arbitrary color register
+     *  on 24-plane cards, all color palette registers have to be updated
      */
 
-static int tgafbcon_updatevar(int con, struct fb_info *info)
+static int tgafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *info)
 {
-    /* Nothing */
+    int err;
+
+    if (!fb_display[con].cmap.len) {   /* no colormap allocated? */
+       if ((err = fb_alloc_cmap(&fb_display[con].cmap, 256, 0)))
+           return err;
+    }
+    if (con == currcon) {              /* current console? */
+       err = fb_set_cmap(cmap, kspc, tgafb_setcolreg, info);
+#if 1
+       if (fb_info.tga_type != 0)
+               tgafb_update_palette();
+#endif
+       return err;
+    } else
+       fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
     return 0;
 }
 
-    /*
-     *  Blank and unblank the display.
-     */
+static void tgafb_update_palette(void)
+{
+    int i;
+
+    BT463_LOAD_ADDR(0x0000);
+    TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG);
+
+    for (i = 0; i < 256; i++) {
+        TGA_WRITE_REG(palette[i].red|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
+        TGA_WRITE_REG(palette[i].green|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
+        TGA_WRITE_REG(palette[i].blue|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
+    }
+}
+#endif
+
+
+static int tgafb_pan_display(const struct fb_var_screeninfo *var, 
+                                    struct fb_info_gen *info)
+{
+    if (var->xoffset || var->yoffset)
+       return -EINVAL;
+    else
+       return 0;
+}
 
-static void tgafbcon_blank(int blank, struct fb_info *info)
+
+static int tgafb_blank(int blank, struct fb_info_gen *info)
 {
     static int tga_vesa_blanked = 0;
     u32 vhcr, vvcr;
@@ -854,158 +927,187 @@ static void tgafbcon_blank(int blank, struct fb_info *info)
     }
 
     restore_flags(flags);
-}
-
-    /*
-     *  Read a single color register and split it into
-     *  colors/transparent. Return != 0 for invalid regno.
-     */
-
-static int tgafb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info)
-{
-    if (regno > 255)
-       return 1;
-    *red = (palette[regno].red<<8) | palette[regno].red;
-    *green = (palette[regno].green<<8) | palette[regno].green;
-    *blue = (palette[regno].blue<<8) | palette[regno].blue;
-    *transp = 0;
     return 0;
 }
 
 
-    /*
-     *  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 tgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp, struct fb_info *info)
+static void tgafb_set_disp(const void *fb_par, struct display *disp,
+       struct fb_info_gen *info)
 {
-    if (regno > 255)
-       return 1;
-    red >>= 8;
-    green >>= 8;
-    blue >>= 8;
-    palette[regno].red = red;
-    palette[regno].green = green;
-    palette[regno].blue = blue;
-
+    disp->screen_base = (char *)fb_info.tga_fb_base + dense_mem(fb_info.tga_fb_base);
+    switch (fb_info.tga_type) {
+#ifdef FBCON_HAS_CFB8
+       case 0: /* 8-plane */
+           disp->dispsw = &fbcon_cfb8;
+            break;
+#endif
 #ifdef FBCON_HAS_CFB32
-    if (regno < 16 && tga_type != 0)
-       fbcon_cfb32_cmap[regno] = (red << 16) | (green << 8) | blue;
+        case 1: /* 24-plane */
+        case 3: /* 24plusZ */
+            disp->dispsw = &fbcon_cfb32;
+            disp->dispsw_data = &fbcon_cfb32_cmap;
+            break;
 #endif
+        default:
+            disp->dispsw = &fbcon_dummy;
+    }
 
-    if (tga_type == 0) { /* 8-plane */
-        BT485_WRITE(regno, BT485_ADDR_PAL_WRITE);
-        TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
-        TGA_WRITE_REG(red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
-        TGA_WRITE_REG(green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
-        TGA_WRITE_REG(blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
-    }                                                    
-    /* How to set a single color register on 24-plane cards?? */
-
-    return 0;
+    disp->scrollmode = SCROLL_YREDRAW;
 }
 
 
-#if 1
+struct fbgen_hwswitch tgafb_hwswitch = {
+    tgafb_detect, tgafb_encode_fix, tgafb_decode_var, tgafb_encode_var, tgafb_get_par,
+    tgafb_set_par, tgafb_getcolreg, tgafb_setcolreg, tgafb_pan_display, tgafb_blank, 
+    tgafb_set_disp
+};
+
+
     /*
-     * FIXME: since I don't know how to set a single arbitrary color register
-     *  on 24-plane cards, all color palette registers have to be updated
+     *  Hardware Independent functions
      */
 
-static void tga_update_palette(void)
-{
-    int i;
 
-    BT463_LOAD_ADDR(0x0000);
-    TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG);
+    /* 
+     *  Frame buffer operations
+     */
 
-    for (i = 0; i < 256; i++) {
-        TGA_WRITE_REG(palette[i].red|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
-        TGA_WRITE_REG(palette[i].green|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
-        TGA_WRITE_REG(palette[i].blue|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
-    }
+static int tgafb_open(struct fb_info *info, int user)
+{
+    MOD_INC_USE_COUNT;
+    return(0);                              
 }
-#endif
+      
 
-static void do_install_cmap(int con, struct fb_info *info)
+static int tgafb_release(struct fb_info *info, int user)
 {
-    if (con != currcon)
-       return;
-    if (fb_display[con].cmap.len)
-       fb_set_cmap(&fb_display[con].cmap, 1, tgafb_setcolreg, info);
-    else
-       fb_set_cmap(fb_default_cmap(256), 1, tgafb_setcolreg, info);
-#if 1
-    if (tga_type != 0)
-        tga_update_palette();
-#endif
+    MOD_DEC_USE_COUNT;
+    return(0);                                                    
 }
 
-#if 0  /* No cursor stuff yet */
 
-/*
- * Hide the cursor from view, during blanking, usually...
- */
-void
-hide_cursor(void)
-{
-       unsigned long flags;
-       save_flags(flags); cli();
+static struct fb_ops tgafb_ops = {
+    tgafb_open, tgafb_release, fbgen_get_fix, fbgen_get_var, fbgen_set_var,
+    fbgen_get_cmap, tgafb_set_cmap, fbgen_pan_display, fbgen_ioctl
+};
 
-       if (tga_type == 0) {
-         BT485_WRITE(0x20, BT485_CMD_2);
-       } else {
-         TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */
-       }
 
-       restore_flags(flags);
+    /*
+     *  Setup
+     */
+
+__initfunc(void tgafb_setup(char *options, int *ints)) {
+    char *this_opt;
+    int i;
+    
+    if (options && *options)
+       for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+                   if (!*this_opt) continue;
+        
+           if (!strncmp(this_opt, "font:", 5))
+               strncpy(default_fontname, this_opt+5, sizeof default_fontname);
+           else if (!strncmp(this_opt, "mode:", 5)) {
+               for (i = 0; i < NUM_TOTAL_MODES; i++) {
+                   if (!strcmp(this_opt+5, tgafb_predefined[i].name))
+                       default_var = tgafb_predefined[i].var;
+                       default_var_valid = 1;
+               }
+           } else {
+               printk(KERN_ERR "tgafb: unknown parameter %s\n", this_opt);
+           }
+       }
 }
 
-void
-set_cursor(int currcons)
+
+    /*
+     *  Initialisation
+     */
+
+__initfunc(void tgafb_init(void))
 {
-  unsigned int idx, xt, yt, row, col;
-  unsigned long flags;
+    struct pci_dev *pdev;
 
-  if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
-    return;
+    pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL);
+    if (!pdev)
+       return;
+    fb_info.tga_mem_base = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
+#ifdef DEBUG
+    printk("tgafb_init: mem_base 0x%x\n", fb_info.tga_mem_base);
+#endif /* DEBUG */
 
-  save_flags(flags); cli();
+    fb_info.tga_type = (readl((unsigned long)fb_info.tga_mem_base) >> 12) & 0x0f;
+    fb_info.tga_regs_base = ((unsigned long)fb_info.tga_mem_base + TGA_REGS_OFFSET);
+    fb_info.tga_fb_base = ((unsigned long)fb_info.tga_mem_base + fb_offset_presets[fb_info.tga_type]);
 
-  if (deccm) {
-    idx = (pos - video_mem_base) >> 1;
-    col = idx % 80;
-    row = (idx - col) / 80;
+    /* XXX Why the fuck is it called modename if it identifies the board? */
+    strcpy (fb_info.gen.info.modename,"DEC 21030 TGA "); 
+    switch (fb_info.tga_type) 
+    { 
+       case 0: /* 8-plane */
+           strcat (fb_info.gen.info.modename, "8-plane");
+           break;
 
-    if (tga_type == 0) { /* 8-plane */
+       case 1:
+           strcat (fb_info.gen.info.modename, "24-plane");
+           break;
 
-      xt = col * TGA_F_WIDTH + 64;
-      yt = row * TGA_F_HEIGHT_PADDED + 64;
+       case 3:
+           strcat (fb_info.gen.info.modename, "24plusZ");
+           break;
+    }
 
-      /* make sure it's enabled */
-      BT485_WRITE(0x22, BT485_CMD_2); /* WIN cursor type */
+    fb_info.gen.info.node = -1;
+    fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
+    fb_info.gen.info.fbops = &tgafb_ops;
+    fb_info.gen.info.disp = &disp;
+    fb_info.gen.info.changevar = NULL;
+    fb_info.gen.info.switch_con = &fbgen_switch;
+    fb_info.gen.info.updatevar = &fbgen_update_var;
+    fb_info.gen.info.blank = &fbgen_blank;
+    strcpy(fb_info.gen.info.fontname, default_fontname);
+    fb_info.gen.parsize = sizeof (struct tgafb_par);
+    fb_info.gen.fbhw = &tgafb_hwswitch;
+    fb_info.gen.fbhw->detect();
+
+    /* This should give a reasonable default video mode */
+    if (!default_var_valid)
+       default_var = tgafb_predefined[0].var;
+    fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+    disp.var.activate = FB_ACTIVATE_NOW;
+    fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+    fbgen_set_disp(-1, &fb_info.gen);
+    fbgen_install_cmap(0, &fb_info.gen);
+    if (register_framebuffer(&fb_info.gen.info) < 0)
+       return;
+    printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node),
+       fb_info.gen.info.modename);
+}
 
-      BT485_WRITE(xt, BT485_CUR_LOW_X);
-      BT485_WRITE((xt >> 8), BT485_CUR_HIGH_X);
-      BT485_WRITE(yt, BT485_CUR_LOW_Y);
-      BT485_WRITE((yt >> 8), BT485_CUR_HIGH_Y);
 
-    } else {
+    /*
+     *  Cleanup
+     */
 
-      xt = col * TGA_F_WIDTH + 144;
-      yt = row * TGA_F_HEIGHT_PADDED + 35;
+void tgafb_cleanup(struct fb_info *info)
+{
+    unregister_framebuffer(info);
+}
 
-      TGA_WRITE_REG(0x05, TGA_VALID_REG); /* SCANNING and CURSOR */
-      TGA_WRITE_REG(xt | (yt << 12), TGA_CURSOR_XY_REG);
-    }
 
-  } else
-    hide_cursor();
-  restore_flags(flags);
+    /*
+     *  Modularisation
+     */
+
+#ifdef MODULE
+int init_module(void)
+{
+    tgafb_init();
+    return 0;
 }
 
-#endif
+void cleanup_module(void)
+{
+    tgafb_cleanup(void);
+}
+#endif /* MODULE */
+
diff --git a/drivers/video/tgafb.h b/drivers/video/tgafb.h
new file mode 100644 (file)
index 0000000..bba8f20
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *  linux/drivers/video/tgafb.h -- DEC 21030 TGA frame buffer device
+ *
+ *     Copyright (C) 1999 Martin Lucina, Tom Zerucha
+ *  
+ *  $Id: tgafb.h,v 1.4 1999/05/15 08:44:31 mato Exp $
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#ifndef TGAFB_H
+#define TGAFB_H
+
+    /*
+     * TGA hardware description (minimal)
+     */
+
+
+    /*
+     * Offsets within Memory Space
+     */
+
+#define        TGA_ROM_OFFSET                  0x0000000
+#define        TGA_REGS_OFFSET                 0x0100000
+#define        TGA_8PLANE_FB_OFFSET            0x0200000
+#define        TGA_24PLANE_FB_OFFSET           0x0804000
+#define        TGA_24PLUSZ_FB_OFFSET           0x1004000
+
+#define        TGA_PLANEMASK_REG               0x0028
+#define        TGA_MODE_REG                    0x0030
+#define        TGA_RASTEROP_REG                0x0034
+#define        TGA_PIXELSHIFT_REG              0x0038
+#define        TGA_DEEP_REG                    0x0050
+#define        TGA_PIXELMASK_REG               0x005c
+#define        TGA_CURSOR_BASE_REG             0x0060
+#define        TGA_HORIZ_REG                   0x0064
+#define        TGA_VERT_REG                    0x0068
+#define        TGA_BASE_ADDR_REG               0x006c
+#define        TGA_VALID_REG                   0x0070
+#define        TGA_CURSOR_XY_REG               0x0074
+#define        TGA_INTR_STAT_REG               0x007c
+#define        TGA_RAMDAC_SETUP_REG            0x00c0
+#define        TGA_BLOCK_COLOR0_REG            0x0140
+#define        TGA_BLOCK_COLOR1_REG            0x0144
+#define        TGA_CLOCK_REG                   0x01e8
+#define        TGA_RAMDAC_REG                  0x01f0
+#define        TGA_CMD_STAT_REG                0x01f8
+
+
+    /* 
+     * useful defines for managing the video timing registers
+     */
+
+#define TGA_HORIZ_ODD                  0x80000000
+#define TGA_HORIZ_POLARITY             0x40000000
+#define TGA_HORIZ_ACT_MSB              0x30000000
+#define TGA_HORIZ_BP                   0x0fe00000
+#define TGA_HORIZ_SYNC                 0x001fc000
+#define TGA_HORIZ_FP                   0x00007c00
+#define TGA_HORIZ_ACT_LSB              0x000001ff
+
+#define TGA_VERT_SE                    0x80000000
+#define TGA_VERT_POLARITY              0x40000000
+#define TGA_VERT_RESERVED              0x30000000
+#define TGA_VERT_BP                    0x0fc00000
+#define TGA_VERT_SYNC                  0x003f0000
+#define TGA_VERT_FP                    0x0000f800
+#define TGA_VERT_ACTIVE                        0x000007ff
+
+
+    /*
+     * useful defines for managing the ICS1562 PLL clock
+     */
+
+#define TGA_PLL_BASE_FREQ              14318           /* .18 */
+#define TGA_PLL_MAX_FREQ               230000
+
+
+    /*
+     * useful defines for managing the BT485 on the 8-plane TGA
+     */
+
+#define        BT485_READ_BIT                  0x01
+#define        BT485_WRITE_BIT                 0x00
+
+#define        BT485_ADDR_PAL_WRITE            0x00
+#define        BT485_DATA_PAL                  0x02
+#define        BT485_PIXEL_MASK                0x04
+#define        BT485_ADDR_PAL_READ             0x06
+#define        BT485_ADDR_CUR_WRITE            0x08
+#define        BT485_DATA_CUR                  0x0a
+#define        BT485_CMD_0                     0x0c
+#define        BT485_ADDR_CUR_READ             0x0e
+#define        BT485_CMD_1                     0x10
+#define        BT485_CMD_2                     0x12
+#define        BT485_STATUS                    0x14
+#define        BT485_CMD_3                     0x14
+#define        BT485_CUR_RAM                   0x16
+#define        BT485_CUR_LOW_X                 0x18
+#define        BT485_CUR_HIGH_X                0x1a
+#define        BT485_CUR_LOW_Y                 0x1c
+#define        BT485_CUR_HIGH_Y                0x1e
+
+
+    /*
+     * useful defines for managing the BT463 on the 24-plane TGAs
+     */
+
+#define        BT463_ADDR_LO           0x0
+#define        BT463_ADDR_HI           0x1
+#define        BT463_REG_ACC           0x2
+#define        BT463_PALETTE           0x3
+
+#define        BT463_CUR_CLR_0         0x0100
+#define        BT463_CUR_CLR_1         0x0101
+
+#define        BT463_CMD_REG_0         0x0201
+#define        BT463_CMD_REG_1         0x0202
+#define        BT463_CMD_REG_2         0x0203
+
+#define        BT463_READ_MASK_0       0x0205
+#define        BT463_READ_MASK_1       0x0206
+#define        BT463_READ_MASK_2       0x0207
+#define        BT463_READ_MASK_3       0x0208
+
+#define        BT463_BLINK_MASK_0      0x0209
+#define        BT463_BLINK_MASK_1      0x020a
+#define        BT463_BLINK_MASK_2      0x020b
+#define        BT463_BLINK_MASK_3      0x020c
+
+#define        BT463_WINDOW_TYPE_BASE  0x0300
+
+
+    /*
+     * Macros for reading/writing TGA and RAMDAC registers
+     */
+
+#define TGA_WRITE_REG(v,r) \
+       { writel((v), fb_info.tga_regs_base+(r)); mb(); }
+
+#define TGA_READ_REG(r) readl(fb_info.tga_regs_base+(r))
+
+#define BT485_WRITE(v,r) \
+         TGA_WRITE_REG((r),TGA_RAMDAC_SETUP_REG);              \
+         TGA_WRITE_REG(((v)&0xff)|((r)<<8),TGA_RAMDAC_REG);
+
+#define BT463_LOAD_ADDR(a) \
+       TGA_WRITE_REG(BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); \
+       TGA_WRITE_REG((BT463_ADDR_LO<<10)|((a)&0xff), TGA_RAMDAC_REG); \
+       TGA_WRITE_REG(BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); \
+       TGA_WRITE_REG((BT463_ADDR_HI<<10)|(((a)>>8)&0xff), TGA_RAMDAC_REG);
+
+#define BT463_WRITE(m,a,v) \
+       BT463_LOAD_ADDR((a)); \
+       TGA_WRITE_REG(((m)<<2),TGA_RAMDAC_SETUP_REG); \
+       TGA_WRITE_REG(((m)<<10)|((v)&0xff),TGA_RAMDAC_REG);
+
+
+    /*
+     *  This structure describes the board.
+     */
+
+struct tgafb_info {
+    /* Use the generic framebuffer ops */
+    struct fb_info_gen gen;
+
+    /* Device dependent information */
+    int tga_type;                                      /* TGA type: {8plane, 24plane, 24plusZ} */
+    unsigned int tga_mem_base;
+    unsigned long tga_fb_base;
+    unsigned long tga_regs_base;
+    struct fb_var_screeninfo default_var;              /* default video mode */
+};
+
+
+    /*
+     *  This structure uniquely defines a video mode.
+     */
+
+struct tgafb_par {
+    int xres, yres;                                    /* resolution in pixels */
+    unsigned int htimings;                             /* horizontal timing register */
+    unsigned int vtimings;                             /* vertical timing register */
+    unsigned int pll_freq;                             /* pixclock in mhz */
+    unsigned int bits_per_pixel;                       /* bits per pixel */
+};
+
+#endif /* TGAFB_H */
index 4723c68024e4f74b1454d54e3ac00777c6cc3dc9..52c1f7aabffd11bb5b1a98c517f8dbc61aeaef3f 100644 (file)
@@ -461,7 +461,8 @@ beyond_if:
                return retval;
        }
 
-       current->mm->start_stack = create_aout_tables(bprm->p, bprm);
+       current->mm->start_stack =
+               (unsigned long) create_aout_tables((char *) bprm->p, bprm);
 #ifdef __alpha__
        regs->gp = ex.a_gpvalue;
 #endif
index 108b385eaa4e4409badefe4a5ba9e769839bd719..0ddd121ab7463bda70d2f3c2f199fd96205234b7 100644 (file)
@@ -1597,7 +1597,7 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
                bh = bh->b_this_page;
        } while (bh != head);
        if (rw == READ)
-               ++current->maj_flt;
+               ++current->mm->maj_flt;
        if ((rw == READ) && nr) {
                if (Page_Uptodate(page))
                        BUG();
@@ -1663,7 +1663,7 @@ int block_read_full_page(struct file * file, struct page * page)
                nr++;
        } while (iblock++, (bh = bh->b_this_page) != head);
 
-       ++current->maj_flt;
+       ++current->mm->maj_flt;
        if (nr) {
                if (Page_Uptodate(page))
                        BUG();
index ec21b0c4e23a20d674178d6ac46b82aad0b56910..4d54fd354f8f5e3471f22a2b87e9d4edbf78996e 100644 (file)
@@ -27,28 +27,35 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
        case EXT2_IOC_GETFLAGS:
                flags = inode->u.ext2_i.i_flags & EXT2_FL_USER_VISIBLE;
                return put_user(inode->u.ext2_i.i_flags, (int *) arg);
-       case EXT2_IOC_SETFLAGS:
+       case EXT2_IOC_SETFLAGS: {
+               unsigned int oldflags;
+
+               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;
-               flags = flags & EXT2_FL_USER_MODIFIABLE;
+
+               oldflags = inode->u.ext2_i.i_flags;
+
                /*
                 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
-                * the super user when the security level is zero.
+                * the relevant capability.
+                *
+                * This test looks nicer. Thanks to Pauline Middelink
                 */
-               if ((flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) ^
-                   (inode->u.ext2_i.i_flags &
-                    (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
-                       /* This test looks nicer. Thanks to Pauline Middelink */
+               if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) {
                        if (!capable(CAP_LINUX_IMMUTABLE))
                                return -EPERM;
-               } else
-                       if ((current->fsuid != inode->i_uid) && 
-                           !capable(CAP_FOWNER))
-                               return -EPERM;
-               if (IS_RDONLY(inode))
-                       return -EROFS;
-               inode->u.ext2_i.i_flags = (inode->u.ext2_i.i_flags &
-                                          ~EXT2_FL_USER_MODIFIABLE) | flags;
+               }
+
+               flags = flags & EXT2_FL_USER_MODIFIABLE;
+               flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE;
+               inode->u.ext2_i.i_flags = flags;
+
                if (flags & EXT2_SYNC_FL)
                        inode->i_flags |= MS_SYNCHRONOUS;
                else
@@ -68,6 +75,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                inode->i_ctime = CURRENT_TIME;
                mark_inode_dirty(inode);
                return 0;
+       }
        case EXT2_IOC_GETVERSION:
                return put_user(inode->i_generation, (int *) arg);
        case EXT2_IOC_SETVERSION:
index 0494ad013605323f46fc82ae26ac7d4a94bde5ec..80ec56b549c5785558e6dcfa73733b2a7a2c40a0 100644 (file)
@@ -87,8 +87,7 @@ struct vm_operations_struct fat_file_mmap = {
        NULL,                   /* advise */
        fat_file_mmap_nopage,   /* nopage */
        NULL,                   /* wppage */
-       NULL,                   /* swapout */
-       NULL,                   /* swapin */
+       NULL                    /* swapout */
 };
 
 /*
index 728985c34b67ccb0782e8567d799d73ae1a8c872..8a280dbb1170afb8108fa03d10218fddf2a81c55 100644 (file)
@@ -546,47 +546,23 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
        return (cfl);
 }
 
-int locks_verify_locked(struct inode *inode)
-{
-       /* Candidates for mandatory locking have the setgid bit set
-        * but no group execute bit -  an otherwise meaningless combination.
-        */
-       if (IS_MANDLOCK(inode) &&
-           (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-               return (locks_mandatory_locked(inode));
-       return (0);
-}
-
-int locks_verify_area(int read_write, struct inode *inode, struct file *filp,
-                     loff_t offset, size_t count)
-{
-       /* Candidates for mandatory locking have the setgid bit set
-        * but no group execute bit -  an otherwise meaningless combination.
-        */
-       if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
-               int retval;
-               lock_kernel();
-               retval = locks_mandatory_area(read_write, inode, filp, offset, count);
-               unlock_kernel();
-               return retval;
-       }
-       return 0;
-}
-
 int locks_mandatory_locked(struct inode *inode)
 {
        fl_owner_t owner = current->files;
        struct file_lock *fl;
 
-       /* Search the lock list for this inode for any POSIX locks.
+       /*
+        * Search the lock list for this inode for any POSIX locks.
         */
+       lock_kernel();
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (!(fl->fl_flags & FL_POSIX))
                        continue;
                if (fl->fl_owner != owner)
-                       return (-EAGAIN);
+                       break;
        }
-       return (0);
+       unlock_kernel();
+       return fl ? -EAGAIN : 0;
 }
 
 int locks_mandatory_area(int read_write, struct inode *inode,
@@ -595,6 +571,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
 {
        struct file_lock *fl;
        struct file_lock tfl;
+       int error;
 
        memset(&tfl, 0, sizeof(tfl));
 
@@ -607,31 +584,39 @@ int locks_mandatory_area(int read_write, struct inode *inode,
        tfl.fl_start = offset;
        tfl.fl_end = offset + count - 1;
 
+       error = 0;
+       lock_kernel();
+
 repeat:
        /* Search the lock list for this inode for locks that conflict with
         * the proposed read/write.
         */
-       for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
+       for (fl = inode->i_flock; ; fl = fl->fl_next) {
+               error = 0;
+               if (!fl)
+                       break;
                if (!(fl->fl_flags & FL_POSIX))
                        continue;
                /* Block for writes against a "read" lock,
                 * and both reads and writes against a "write" lock.
                 */
                if (posix_locks_conflict(fl, &tfl)) {
+                       error = -EAGAIN;
                        if (filp && (filp->f_flags & O_NONBLOCK))
-                               return (-EAGAIN);
+                               break;
+                       error = -ERESTARTSYS;
                        if (signal_pending(current))
-                               return (-ERESTARTSYS);
+                               break;
+                       error = -EDEADLK;
                        if (posix_locks_deadlock(&tfl, fl))
-                               return (-EDEADLK);
+                               break;
 
                        locks_insert_block(fl, &tfl);
                        interruptible_sleep_on(&tfl.fl_wait);
                        locks_delete_block(fl, &tfl);
 
-                       if (signal_pending(current))
-                               return (-ERESTARTSYS);
-                       /* If we've been sleeping someone might have
+                       /*
+                        * If we've been sleeping someone might have
                         * changed the permissions behind our back.
                         */
                        if ((inode->i_mode & (S_ISGID | S_IXGRP)) != S_ISGID)
@@ -639,7 +624,8 @@ repeat:
                        goto repeat;
                }
        }
-       return (0);
+       unlock_kernel();
+       return error;
 }
 
 /* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
index c9254f4f67a75c46cb245403af03b12b62ac5eee..776e9366b0040aec427b1cfcd431ca91c2112c42 100644 (file)
@@ -98,8 +98,7 @@ struct vm_operations_struct ncp_file_mmap =
        NULL,                   /* advise */
        ncp_file_mmap_nopage,   /* nopage */
        NULL,                   /* wppage */
-       NULL,                   /* swapout */
-       NULL,                   /* swapin */
+       NULL                    /* swapout */
 };
 
 
index 66108f9a79f015473c47698112aeacf6222a1c1b..49d0d005877609a8635284d312485534ceb617dc 100644 (file)
@@ -906,10 +906,10 @@ static int get_stat(int pid, char * buffer)
                tsk->tty ? kdev_t_to_nr(tsk->tty->device) : 0,
                tty_pgrp,
                tsk->flags,
-               tsk->min_flt,
-               tsk->cmin_flt,
-               tsk->maj_flt,
-               tsk->cmaj_flt,
+               tsk->mm ? tsk->mm->min_flt : 0,
+               tsk->mm ? tsk->mm->cmin_flt : 0,
+               tsk->mm ? tsk->mm->maj_flt : 0,
+               tsk->mm ? tsk->mm->cmaj_flt : 0,
                tsk->times.tms_utime,
                tsk->times.tms_stime,
                tsk->times.tms_cutime,
@@ -936,8 +936,8 @@ static int get_stat(int pid, char * buffer)
                sigign      .sig[0] & 0x7fffffffUL,
                sigcatch    .sig[0] & 0x7fffffffUL,
                wchan,
-               tsk->nswap,
-               tsk->cnswap,
+               tsk->mm ? tsk->mm->nswap : 0,
+               tsk->mm ? tsk->mm->cnswap : 0,
                tsk->exit_signal,
                tsk->processor);
 }
index 4d599c77b50d4448461c89154d84bb115f6d8636..b095df35361937de43278f0d5aa4ac1141f7fafb 100644 (file)
@@ -289,10 +289,10 @@ int mem_mmap(struct file * file, struct vm_area_struct * vma)
                        return -ENOMEM;
 
                if (!pte_present(*src_table))
-                       handle_mm_fault(tsk, src_vma, stmp, 1);
+                       handle_mm_fault(tsk->mm, src_vma, stmp, 1);
 
                if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
-                       handle_mm_fault(tsk, src_vma, stmp, 1);
+                       handle_mm_fault(tsk->mm, src_vma, stmp, 1);
 
                set_pte(src_table, pte_mkdirty(*src_table));
                set_pte(dest_table, *src_table);
index 12937adcfe193b0979c9513071b2b8380f8a908e..b6a1f8ef65cfd088d7cd866cfe8aba0f20c4d942 100644 (file)
@@ -467,7 +467,8 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
        }
        if (!(sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE)) {
                printk("You didn't specify the type of your ufs filesystem\n\n"
-               "       mount -t ufs -o ufstype=sun|sunx86|44bsd|old|nextstep|netxstep-cd|openstep ...\n\n"
+               "mount -t ufs -o ufstype="
+               "sun|sunx86|44bsd|old|nextstep|netxstep-cd|openstep ...\n\n"
                ">>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
                "default is ufstype=old\n");
                ufs_set_opt (sb->u.ufs_sb.s_mount_opt, UFSTYPE_OLD);
index a630c9e5b12810ade80eb202769517129214976d..5e2c8d63274ede4784e112c6a064b5a9ff011251 100644 (file)
@@ -19,7 +19,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
 #include <asm/head.h>       /* for KERNBASE */
 #include <asm/btfixup.h>
 
index 29157189572d1a1e5c969ff4d793dd735f6012b4..7d60fee3170d0d26964dfc75148d3870ce1c5f42 100644 (file)
@@ -418,6 +418,9 @@ struct file {
        void                    *private_data;
 };
 
+#define get_file(x)    atomic_inc(&(x)->f_count)
+#define file_count(x)  atomic_read(&(x)->f_count)
+
 extern int init_private_file(struct file *, struct dentry *, int);
 
 #define FL_POSIX       1
@@ -664,29 +667,27 @@ extern int unregister_filesystem(struct file_system_type *);
 extern int locks_mandatory_locked(struct inode *);
 extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
 
-extern inline int locks_verify_locked(struct inode *inode)
+/*
+ * Candidates for mandatory locking have the setgid bit set
+ * but no group execute bit -  an otherwise meaningless combination.
+ */
+#define MANDATORY_LOCK(inode) \
+       (IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+
+static inline int locks_verify_locked(struct inode *inode)
 {
-       /* Candidates for mandatory locking have the setgid bit set
-        * but no group execute bit -  an otherwise meaningless combination.
-        */
-       if (IS_MANDLOCK(inode) &&
-           (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-               return (locks_mandatory_locked(inode));
-       return (0);
+       if (MANDATORY_LOCK(inode))
+               return locks_mandatory_locked(inode);
+       return 0;
 }
 
 extern inline int locks_verify_area(int read_write, struct inode *inode,
                                    struct file *filp, loff_t offset,
                                    size_t count)
 {
-       /* Candidates for mandatory locking have the setgid bit set
-        * but no group execute bit -  an otherwise meaningless combination.
-        */
-       if (IS_MANDLOCK(inode) &&
-           (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-               return (locks_mandatory_area(read_write, inode, filp, offset,
-                                            count));
-       return (0);
+       if (inode->i_flock && MANDATORY_LOCK(inode))
+               return locks_mandatory_area(read_write, inode, filp, offset, count);
+       return 0;
 }
 
 
index 0ef994528a2b03d6a2205986890ca74c510e7108..d6daa0f2d9cc83a58928036f8256b7ad968e7373 100644 (file)
@@ -696,6 +696,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
 int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
 
 void ide_delay_50ms (void);
+int ide_config_drive_speed (ide_drive_t *drive, byte speed);
 
 /*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
index c0a3ba3094586b468ccf1beceaf8a5cea26b26e7..52e501eea29d7f50614fc3e3dc0bb1eb083c36b3 100644 (file)
@@ -398,9 +398,6 @@ typedef struct {
 
 #ifdef __KERNEL__
 
-#ifndef STANDALONE
-#include <linux/config.h>
-#endif
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
index 83e4d7739203abd6f2a8f4e021722e4bdb95f7d6..bd03fdc8d148d336fc8dc87b41ead23479a8008a 100644 (file)
 #define LP_ABORT 0x0040
 #define LP_CAREFUL 0x0080 /* obsoleted -arca */
 #define LP_ABORTOPEN 0x0100
-#define        LP_TRUST_IRQ 0x0200
+
+#define LP_TRUST_IRQ_  0x0200 /* obsolete */
+#define LP_NO_REVERSE  0x0400 /* No reverse mode available. */
+#define LP_DATA_AVAIL  0x0800 /* Data is available. */
+#define LP_HAVE_PORT_BIT   12 /* (0x1000) Port is claimed. */
+#define LP_PORT_BUSY   (1<<13) /* Reading or writing. */
 
 /* timeout for each character.  This is relative to bus cycles -- it
  * is the count in a busy loop.  THIS IS THE VALUE TO CHANGE if you
@@ -72,7 +77,6 @@
 #define LPGETSTATS  0x060d  /* get statistics (struct lp_stats) */
 #endif
 #define LPGETFLAGS  0x060e  /* get status flags */
-#define LPTRUSTIRQ  0x060f  /* set/unset the LP_TRUST_IRQ flag */
 
 /* timeout for printk'ing a timeout, in jiffies (100ths of a second).
    This is also used for re-checking error conditions if LP_ABORT is
 #ifdef LP_STATS
 #define LP_STAT(minor) lp_table[(minor)].stats         /* statistics area */
 #endif
-#define LP_BUFFER_SIZE 256
+#define LP_BUFFER_SIZE PAGE_SIZE
 
 #define LP_BASE(x)     lp_table[(x)].dev->port->base
 
@@ -125,10 +129,10 @@ struct lp_struct {
        unsigned int runchars;
        struct lp_stats stats;
 #endif
-       wait_queue_head_t wait_q;
+       wait_queue_head_t waitq;
        unsigned int last_error;
-       volatile unsigned int irq_detected:1;
-       volatile unsigned int irq_missed:1;
+       struct semaphore port_mutex;
+       wait_queue_head_t dataq;
 };
 
 /*
@@ -174,9 +178,6 @@ struct lp_struct {
  */
 #define LP_DELAY       50
 
-#define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE)
-#define LP_PREEMPTED(minor) (lp_table[(minor)].dev->port->waithead != NULL)
-
 /*
  * function prototypes
  */
index 1d2bf41473dba4f821f2a2f1940434b4d60be6cc..5429bb3f9409757dc44038501f9f4cdb85b660e5 100644 (file)
@@ -106,7 +106,6 @@ struct vm_operations_struct {
        unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
                unsigned long page);
        int (*swapout)(struct vm_area_struct *, struct page *);
-       pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
 };
 
 /*
@@ -315,7 +314,7 @@ extern int remap_page_range(unsigned long from, unsigned long to, unsigned long
 extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
 
 extern void vmtruncate(struct inode * inode, unsigned long offset);
-extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
+extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern void make_pages_present(unsigned long addr, unsigned long end);
 
 extern int pgt_cache_water[2];
@@ -407,7 +406,7 @@ static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * m
        return vma;
 }
 
-extern struct vm_area_struct *find_extend_vma(struct task_struct *tsk, unsigned long addr);
+extern struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr);
 
 #define buffer_under_min()     ((atomic_read(&buffermem) >> PAGE_SHIFT) * 100 < \
                                buffer_mem.min_percent * num_physpages)
index d95c5a856009a7db546f4816320f7f773491752b..c07cbaccf51aacda3d189ea4fe139c0d026e7490 100644 (file)
@@ -20,8 +20,6 @@
 #define PARPORT_CONTROL_AUTOFD    0x2
 #define PARPORT_CONTROL_INIT      0x4
 #define PARPORT_CONTROL_SELECT    0x8
-#define PARPORT_CONTROL_INTEN     0x10
-#define PARPORT_CONTROL_DIRECTION 0x20
 
 #define PARPORT_STATUS_ERROR      0x8
 #define PARPORT_STATUS_SELECT     0x10
@@ -43,21 +41,34 @@ typedef enum {
        PARPORT_CLASS_SCANNER,
        PARPORT_CLASS_DIGCAM,
        PARPORT_CLASS_OTHER,            /* Anything else */
-       PARPORT_CLASS_UNSPEC            /* No CLS field in ID */
+       PARPORT_CLASS_UNSPEC,           /* No CLS field in ID */
+       PARPORT_CLASS_SCSIADAPTER
 } parport_device_class;
 
-/* The "modes" entry in parport is a bit field representing the following
- * modes.
- * Note that PARPORT_MODE_PCECPEPP is for the SMC EPP+ECP mode which is NOT
- * 100% compatible with EPP.
- */
-#define PARPORT_MODE_PCSPP             0x0001
-#define PARPORT_MODE_PCPS2             0x0002
-#define PARPORT_MODE_PCEPP             0x0004
-#define PARPORT_MODE_PCECP             0x0008
-#define PARPORT_MODE_PCECPEPP          0x0010
-#define PARPORT_MODE_PCECR             0x0020  /* ECR Register Exists */
-#define PARPORT_MODE_PCECPPS2          0x0040
+/* The "modes" entry in parport is a bit field representing the
+   capabilities of the hardware. */
+#define PARPORT_MODE_PCSPP     (1<<0) /* IBM PC registers available. */
+#define PARPORT_MODE_TRISTATE  (1<<1) /* Can tristate. */
+#define PARPORT_MODE_EPP       (1<<2) /* Hardware EPP. */
+#define PARPORT_MODE_ECP       (1<<3) /* Hardware ECP. */
+#define PARPORT_MODE_COMPAT    (1<<4) /* Hardware 'printer protocol'. */
+#define PARPORT_MODE_DMA       (1<<5) /* Hardware can DMA. */
+
+/* IEEE1284 modes: 
+   Nibble mode, byte mode, ECP, ECPRLE and EPP are their own
+   'extensibility request' values.  Others are special.
+   'Real' ECP modes must have the IEEE1284_MODE_ECP bit set.  */
+#define IEEE1284_MODE_NIBBLE             0
+#define IEEE1284_MODE_BYTE              (1<<0)
+#define IEEE1284_MODE_COMPAT            (1<<8)
+#define IEEE1284_MODE_BECP              (1<<9) /* Bounded ECP mode */
+#define IEEE1284_MODE_ECP               (1<<4)
+#define IEEE1284_MODE_ECPRLE            (IEEE1284_MODE_ECP | (1<<5))
+#define IEEE1284_MODE_ECPSWE            (1<<10) /* Software-emulated */
+#define IEEE1284_MODE_EPP               (1<<6)
+#define IEEE1284_MODE_EPPSL             (1<<11) /* EPP 1.7 */
+#define IEEE1284_MODE_EPPSWE            (1<<12) /* Software-emulated */
+#define IEEE1284_DEVICEID               (1<<2)  /* This is a flag */
 
 /* The rest is for the kernel only */
 #ifdef __KERNEL__
@@ -65,6 +76,7 @@ typedef enum {
 #include <asm/system.h>
 #include <asm/ptrace.h>
 #include <asm/spinlock.h>
+#include <asm/semaphore.h>
 #include <linux/proc_fs.h>
 #include <linux/config.h>
 
@@ -72,59 +84,92 @@ typedef enum {
 
 /* Define this later. */
 struct parport;
+struct pardevice;
 
 struct pc_parport_state {
        unsigned int ctr;
        unsigned int ecr;
 };
 
+struct ax_parport_state {
+       unsigned int ctr;
+       unsigned int ecr;
+       unsigned int dcsr;
+};
+
+/* used by both parport_amiga and parport_mfc3 */
+struct amiga_parport_state {
+       unsigned char data;     /* ciaa.prb */
+       unsigned char datadir;  /* ciaa.ddrb */
+       unsigned char status;   /* ciab.pra & 7 */
+       unsigned char statusdir;/* ciab.ddrb & 7 */
+};
+
 struct parport_state {
        union {
                struct pc_parport_state pc;
                /* ARC has no state. */
-               /* AX uses same state information as PC */
+               struct ax_parport_state ax;
+               struct amiga_parport_state amiga;
+               /* Atari has not state. */
                void *misc; 
        } u;
 };
 
 struct parport_operations {
+       /* IBM PC-style virtual registers. */
        void (*write_data)(struct parport *, unsigned char);
        unsigned char (*read_data)(struct parport *);
+
        void (*write_control)(struct parport *, unsigned char);
        unsigned char (*read_control)(struct parport *);
-       unsigned char (*frob_control)(struct parport *, unsigned char mask, unsigned char val);
-       void (*write_econtrol)(struct parport *, unsigned char);
-       unsigned char (*read_econtrol)(struct parport *);
-       unsigned char (*frob_econtrol)(struct parport *, unsigned char mask, unsigned char val);
-       void (*write_status)(struct parport *, unsigned char);
+       unsigned char (*frob_control)(struct parport *, unsigned char mask,
+                                     unsigned char val);
+
        unsigned char (*read_status)(struct parport *);
-       void (*write_fifo)(struct parport *, unsigned char);
-       unsigned char (*read_fifo)(struct parport *);
 
-       void (*change_mode)(struct parport *, int);
+       /* IRQs. */
+       void (*enable_irq)(struct parport *);
+       void (*disable_irq)(struct parport *);
 
-       void (*epp_write_data)(struct parport *, unsigned char);
-       unsigned char (*epp_read_data)(struct parport *);
-       void (*epp_write_addr)(struct parport *, unsigned char);
-       unsigned char (*epp_read_addr)(struct parport *);
-       int (*epp_check_timeout)(struct parport *);
-       size_t (*epp_write_block)(struct parport *, void *, size_t);
-       size_t (*epp_read_block)(struct parport *, void *, size_t);
+       /* Data direction. */
+       void (*data_forward) (struct parport *);
+       void (*data_reverse) (struct parport *);
 
-       int (*ecp_write_block)(struct parport *, void *, size_t, void (*fn)(struct parport *, void *, size_t), void *);
-       int (*ecp_read_block)(struct parport *, void *, size_t, void (*fn)(struct parport *, void *, size_t), void *);
+       /* For core parport code. */
+       void (*interrupt)(int, void *, struct pt_regs *); /* ? */
 
-       void (*init_state)(struct parport_state *);
+       void (*init_state)(struct pardevice *, struct parport_state *);
        void (*save_state)(struct parport *, struct parport_state *);
        void (*restore_state)(struct parport *, struct parport_state *);
 
-       void (*enable_irq)(struct parport *);
-       void (*disable_irq)(struct parport *);
-       void (*interrupt)(int, void *, struct pt_regs *);
-
        void (*inc_use_count)(void);
        void (*dec_use_count)(void);
-       void (*fill_inode)(struct inode *inode, int fill);
+       void (*fill_inode)(struct inode *inode, int fill); /* ? */
+
+       /* Block read/write */
+       size_t (*epp_write_data) (struct parport *port, const void *buf,
+                                 size_t len, int flags);
+       size_t (*epp_read_data) (struct parport *port, void *buf, size_t len,
+                                int flags);
+       size_t (*epp_write_addr) (struct parport *port, const void *buf,
+                                 size_t len, int flags);
+       size_t (*epp_read_addr) (struct parport *port, void *buf, size_t len,
+                                int flags);
+
+       size_t (*ecp_write_data) (struct parport *port, const void *buf,
+                                 size_t len, int flags);
+       size_t (*ecp_read_data) (struct parport *port, void *buf, size_t len,
+                                int flags);
+       size_t (*ecp_write_addr) (struct parport *port, const void *buf,
+                                 size_t len, int flags);
+
+       size_t (*compat_write_data) (struct parport *port, const void *buf,
+                                    size_t len, int flags);
+       size_t (*nibble_read_data) (struct parport *port, void *buf,
+                                   size_t len, int flags);
+       size_t (*byte_read_data) (struct parport *port, void *buf,
+                                 size_t len, int flags);
 };
 
 struct parport_device_info {
@@ -152,6 +197,7 @@ struct parport_device_info {
 struct pardevice {
        const char *name;
        struct parport *port;
+       int daisy;
        int (*preempt)(void *);
        void (*wakeup)(void *);
        void *private;
@@ -163,34 +209,66 @@ struct pardevice {
        wait_queue_head_t wait_q;
        unsigned long int time;
        unsigned long int timeslice;
+       volatile long int timeout;
        unsigned int waiting;
        struct pardevice *waitprev;
        struct pardevice *waitnext;
-        void * sysctl_table;
+       void * sysctl_table;
 };
 
-/* Directory information for the /proc interface */
-struct parport_dir {
-       struct proc_dir_entry *entry;    /* Directory /proc/parport/X     */
-       struct proc_dir_entry *irq;     /*              .../irq           */
-       struct proc_dir_entry *devices;  /*             .../devices       */
-       struct proc_dir_entry *hardware; /*             .../hardware      */
-       struct proc_dir_entry *probe;    /*             .../autoprobe     */
-       char name[4];
+/* IEEE1284 information */
+
+/* IEEE1284 phases */
+enum ieee1284_phase {
+       IEEE1284_PH_FWD_DATA,
+       IEEE1284_PH_FWD_IDLE,
+       IEEE1284_PH_TERMINATE,
+       IEEE1284_PH_NEGOTIATION,
+       IEEE1284_PH_HBUSY_DNA,
+       IEEE1284_PH_REV_IDLE,
+       IEEE1284_PH_HBUSY_DAVAIL,
+       IEEE1284_PH_REV_DATA,
+       IEEE1284_PH_ECP_SETUP,
+       IEEE1284_PH_ECP_FWD_TO_REV,
+       IEEE1284_PH_ECP_REV_TO_FWD
+};
+struct ieee1284_info {
+       int mode;
+       volatile enum ieee1284_phase phase;
+       struct semaphore irq;
 };
 
 /* A parallel port */
 struct parport {
        unsigned long base;     /* base address */
-       unsigned long base_hi;  /* base address (ECR) */
+       unsigned long base_hi;  /* base address (hi - ECR) */
        unsigned int size;      /* IO extent */
        const char *name;
+       unsigned int modes;
        int irq;                /* interrupt (or -1 for none) */
        int dma;
-       unsigned int modes;
+       int muxport;            /* which muxport (if any) this is */
+       int portnum;            /* which physical parallel port (not mux) */
+
+       struct parport *physport;
+                               /* If this is a non-default mux
+                                  parport, i.e. we're a clone of a real
+                                  physical port, this is a pointer to that
+                                  port. The locking is only done in the
+                                  real port.  For a clone port, the
+                                  following structure members are
+                                  meaningless: devices, cad, muxsel,
+                                  waithead, waittail, flags, pdir,
+                                  ieee1284, *_lock.
+
+                                  It this is a default mux parport, or
+                                  there is no mux involved, this points to
+                                  ourself. */
 
        struct pardevice *devices;
        struct pardevice *cad;  /* port owner */
+       int daisy;              /* currently selected daisy addr */
+       int muxsel;             /* currently selected mux port */
 
        struct pardevice *waithead;
        struct pardevice *waittail;
@@ -198,8 +276,9 @@ struct parport {
        struct parport *next;
        unsigned int flags;
 
-       struct parport_dir pdir;
-       struct parport_device_info probe_info; 
+       void *sysctl_table;
+       struct parport_device_info probe_info[5]; /* 0-3 + non-IEEE1284.3 */
+       struct ieee1284_info ieee1284;
 
        struct parport_operations *ops;
        void *private_data;     /* for lowlevel driver */
@@ -208,9 +287,12 @@ struct parport {
        spinlock_t pardevice_lock;
        spinlock_t waitlist_lock;
        rwlock_t cad_lock;
-        void * sysctl_table;
+
+       int spintime;
 };
 
+#define DEFAULT_SPIN_TIME 500 /* us */
+
 struct parport_driver {
        const char *name;
        void (*attach) (struct parport *);
@@ -218,11 +300,10 @@ struct parport_driver {
        struct parport_driver *next;
 };
 
-/* parport_register_port registers a new parallel port at the given address (if
- * one does not already exist) and returns a pointer to it.  This entails
- * claiming the I/O region, IRQ and DMA.
- * NULL is returned if initialisation fails. 
- */
+/* parport_register_port registers a new parallel port at the given
+   address (if one does not already exist) and returns a pointer to it.
+   This entails claiming the I/O region, IRQ and DMA.  NULL is returned
+   if initialisation fails. */
 struct parport *parport_register_port(unsigned long base, int irq, int dma,
                                      struct parport_operations *ops);
 
@@ -236,12 +317,12 @@ void parport_announce_port (struct parport *port);
 /* Unregister a port. */
 extern void parport_unregister_port(struct parport *port);
 
-/* parport_in_use returns nonzero if there are devices attached to a port. */
+/* parport_in_use returns nonzero if there are devices attached to a
+   port. */
 #define parport_in_use(x)  ((x)->devices != NULL)
 
-/* parport_enumerate returns a pointer to the linked list of all the ports
- * in this machine.
- */
+/* parport_enumerate returns a pointer to the linked list of all the
+   ports in this machine. */
 struct parport *parport_enumerate(void);
 
 /* Register a new high-level driver. */
@@ -250,13 +331,12 @@ extern int parport_register_driver (struct parport_driver *);
 /* Unregister a high-level driver. */
 extern void parport_unregister_driver (struct parport_driver *);
 
-/* parport_register_device declares that a device is connected to a port, and 
- * tells the kernel all it needs to know.  
- * pf is the preemption function (may be NULL for no callback)
- * kf is the wake-up function (may be NULL for no callback)
- * irq_func is the interrupt handler (may be NULL for no interrupts)
- * handle is a user pointer that gets handed to callback functions. 
- */
+/* parport_register_device declares that a device is connected to a
+   port, and tells the kernel all it needs to know.  pf is the
+   preemption function (may be NULL for no callback) kf is the wake-up
+   function (may be NULL for no callback) irq_func is the interrupt
+   handler (may be NULL for no interrupts) handle is a user pointer
+   that gets handed to callback functions.  */
 struct pardevice *parport_register_device(struct parport *port, 
                          const char *name,
                          int (*pf)(void *), void (*kf)(void *),
@@ -266,30 +346,29 @@ struct pardevice *parport_register_device(struct parport *port,
 /* parport_unregister unlinks a device from the chain. */
 extern void parport_unregister_device(struct pardevice *dev);
 
-/* parport_claim tries to gain ownership of the port for a particular driver.
- * This may fail (return non-zero) if another driver is busy.  If this
- * driver has registered an interrupt handler, it will be enabled. 
- */
+/* parport_claim tries to gain ownership of the port for a particular
+   driver.  This may fail (return non-zero) if another driver is busy.
+   If this driver has registered an interrupt handler, it will be
  enabled.  */
 extern int parport_claim(struct pardevice *dev);
 
-/* parport_claim_or_block is the same, but sleeps if the port cannot be 
-   claimed.  Return value is 1 if it slept, 0 normally and -errno on error.  */
+/* parport_claim_or_block is the same, but sleeps if the port cannot
+   be claimed.  Return value is 1 if it slept, 0 normally and -errno
+   on error.  */
 extern int parport_claim_or_block(struct pardevice *dev);
 
-/* parport_release reverses a previous parport_claim.  This can never fail, 
- * though the effects are undefined (except that they are bad) if you didn't
- * previously own the port.  Once you have released the port you should make
- * sure that neither your code nor the hardware on the port tries to initiate
- * any communication without first re-claiming the port.
- * If you mess with the port state (enabling ECP for example) you should
- * clean up before releasing the port. 
- */
+/* parport_release reverses a previous parport_claim.  This can never
+   fail, though the effects are undefined (except that they are bad)
+   if you didn't previously own the port.  Once you have released the
+   port you should make sure that neither your code nor the hardware
+   on the port tries to initiate any communication without first
+   re-claiming the port.  If you mess with the port state (enabling
+   ECP for example) you should clean up before releasing the port. */
 
 extern void parport_release(struct pardevice *dev);
 
 /* parport_yield relinquishes the port if it would be helpful to other
- * drivers.  The return value is the same as for parport_claim.
- */
+   drivers.  The return value is the same as for parport_claim.  */
 extern __inline__ int parport_yield(struct pardevice *dev)
 {
        unsigned long int timeslip = (jiffies - dev->time);
@@ -300,8 +379,7 @@ extern __inline__ int parport_yield(struct pardevice *dev)
 }
 
 /* parport_yield_blocking is the same but uses parport_claim_or_block
- * instead of parport_claim.
- */
+   instead of parport_claim.  */
 extern __inline__ int parport_yield_blocking(struct pardevice *dev)
 {
        unsigned long int timeslip = (jiffies - dev->time);
@@ -311,37 +389,87 @@ extern __inline__ int parport_yield_blocking(struct pardevice *dev)
        return parport_claim_or_block(dev);
 }
 
-/*
- * Lowlevel drivers _can_ call this support function to handle irqs.
- */
-extern __inline__ void parport_generic_irq(int irq, struct parport *port,
-                                          struct pt_regs *regs)
-{
-       read_lock(&port->cad_lock);
-       if (!port->cad)
-               goto out_unlock;
-       if (port->cad->irq_func)
-               port->cad->irq_func(irq, port->cad->private, regs);
-       else
-               printk(KERN_ERR "%s: irq%d happened with irq_func NULL "
-                      "with %s as cad!\n", port->name, irq, port->cad->name);
- out_unlock:
-       read_unlock(&port->cad_lock);
-}
-
 /* Flags used to identify what a device does. */
 #define PARPORT_DEV_TRAN               0       /* WARNING !! DEPRECATED !! */
 #define PARPORT_DEV_LURK               (1<<0)  /* WARNING !! DEPRECATED !! */
 #define PARPORT_DEV_EXCL               (1<<1)  /* Need exclusive access. */
 
-#define PARPORT_FLAG_COMA_             (1<<0)  /* No longer used. */
 #define PARPORT_FLAG_EXCL              (1<<1)  /* EXCL driver registered. */
 
 extern int parport_parse_irqs(int, const char *[], int irqval[]);
-extern int parport_parse_dmas(int, const char *[], int irqval[]);
-extern int parport_ieee1284_nibble_mode_ok(struct parport *, unsigned char);
-extern int parport_wait_peripheral(struct parport *, unsigned char, unsigned
-                                  char);
+extern int parport_parse_dmas(int, const char *[], int dmaval[]);
+
+/* IEEE1284 functions */
+extern void parport_ieee1284_interrupt (int, void *, struct pt_regs *);
+extern int parport_negotiate (struct parport *, int mode);
+extern ssize_t parport_write (struct parport *, const void *buf, size_t len);
+extern ssize_t parport_read (struct parport *, void *buf, size_t len);
+extern long parport_set_timeout (struct pardevice *, long inactivity);
+extern int parport_wait_event (struct parport *, long timeout);
+extern int parport_wait_peripheral (struct parport *port,
+                                   unsigned char mask,
+                                   unsigned char val);
+
+/* For architectural drivers */
+extern void parport_ieee1284_wakeup (struct parport *port);
+extern size_t parport_ieee1284_write_compat (struct parport *,
+                                            const void *, size_t, int);
+extern size_t parport_ieee1284_read_nibble (struct parport *,
+                                           void *, size_t, int);
+extern size_t parport_ieee1284_read_byte (struct parport *,
+                                         void *, size_t, int);
+extern size_t parport_ieee1284_ecp_read_data (struct parport *,
+                                             void *, size_t, int);
+extern size_t parport_ieee1284_ecp_write_data (struct parport *,
+                                              const void *, size_t, int);
+extern size_t parport_ieee1284_ecp_write_addr (struct parport *,
+                                              const void *, size_t, int);
+extern size_t parport_ieee1284_epp_write_data (struct parport *,
+                                              const void *, size_t, int);
+extern size_t parport_ieee1284_epp_read_data (struct parport *,
+                                             void *, size_t, int);
+extern size_t parport_ieee1284_epp_write_addr (struct parport *,
+                                              const void *, size_t, int);
+extern size_t parport_ieee1284_epp_read_addr (struct parport *,
+                                             void *, size_t, int);
+
+/* IEEE1284.3 functions */
+extern int parport_daisy_init (struct parport *port);
+extern void parport_daisy_fini (struct parport *port);
+extern struct pardevice *parport_open (int devnum, const char *name,
+                                      int (*pf) (void *),
+                                      void (*kf) (void *),
+                                      void (*irqf) (int, void *,
+                                                    struct pt_regs *),
+                                      int flags, void *handle);
+extern void parport_close (struct pardevice *dev);
+extern ssize_t parport_device_id (int devnum, char *buffer, size_t len);
+extern int parport_device_num (int parport, int mux, int daisy);
+extern int parport_device_coords (int devnum, int *parport, int *mux,
+                                 int *daisy);
+extern void parport_daisy_deselect_all (struct parport *port);
+extern int parport_daisy_select (struct parport *port, int daisy, int mode);
+
+/* For finding devices based on their device ID.  Example usage:
+   int devnum = -1;
+   while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, devnum)) != -1) {
+       struct pardevice *dev = parport_open (devnum, ...);
+       ...
+   }
+*/
+extern int parport_find_device (const char *mfg, const char *mdl, int from);
+extern int parport_find_class (parport_device_class cls, int from);
+
+/* Lowlevel drivers _can_ call this support function to handle irqs.  */
+extern __inline__ void parport_generic_irq(int irq, struct parport *port,
+                                          struct pt_regs *regs)
+{
+       parport_ieee1284_interrupt (irq, port, regs);
+       read_lock(&port->cad_lock);
+       if (port->cad && port->cad->irq_func)
+               port->cad->irq_func(irq, port->cad->private, regs);
+       read_unlock(&port->cad_lock);
+}
 
 /* Prototypes from parport_procfs */
 extern int parport_proc_register(struct parport *pp);
@@ -354,12 +482,8 @@ extern int parport_default_proc_unregister(void);
 extern void dec_parport_count(void);
 extern void inc_parport_count(void);
 
-extern int parport_probe(struct parport *port, char *buffer, int len);
-extern void parport_probe_one(struct parport *port);
-extern void (*parport_probe_hook)(struct parport *port);
-
 /* If PC hardware is the only type supported, we can optimise a bit.  */
-#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
+#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
 #undef PARPORT_NEED_GENERIC_OPS
 #include <linux/parport_pc.h>
 #define parport_write_data(p,x)            parport_pc_write_data(p,x)
@@ -367,21 +491,11 @@ extern void (*parport_probe_hook)(struct parport *port);
 #define parport_write_control(p,x)         parport_pc_write_control(p,x)
 #define parport_read_control(p)            parport_pc_read_control(p)
 #define parport_frob_control(p,m,v)        parport_pc_frob_control(p,m,v)
-#define parport_write_econtrol(p,x)        parport_pc_write_econtrol(p,x)
-#define parport_read_econtrol(p)           parport_pc_read_econtrol(p)
-#define parport_frob_econtrol(p,m,v)       parport_pc_frob_econtrol(p,m,v)
-#define parport_write_status(p,v)          parport_pc_write_status(p,v)
 #define parport_read_status(p)             parport_pc_read_status(p)
-#define parport_write_fifo(p,v)            parport_pc_write_fifo(p,v)
-#define parport_read_fifo(p)               parport_pc_read_fifo(p)
-#define parport_change_mode(p,m)           parport_pc_change_mode(p,m)
-#define parport_release_resources(p)       parport_pc_release_resources(p)
-#define parport_claim_resources(p)         parport_pc_claim_resources(p)
-#define parport_epp_write_data(p,x)        parport_pc_write_epp(p,x)
-#define parport_epp_read_data(p)           parport_pc_read_epp(p)
-#define parport_epp_write_addr(p,x)        parport_pc_write_epp_addr(p,x)
-#define parport_epp_read_addr(p)           parport_pc_read_epp_addr(p)
-#define parport_epp_check_timeout(p)       parport_pc_check_epp_timeout(p)
+#define parport_enable_irq(p)              parport_pc_enable_irq(p)
+#define parport_disable_irq(p)             parport_pc_disable_irq(p)
+#define parport_data_forward(p)            parport_pc_data_forward(p)
+#define parport_data_reverse(p)            parport_pc_data_reverse(p)
 #endif
 
 #ifdef PARPORT_NEED_GENERIC_OPS
@@ -391,21 +505,11 @@ extern void (*parport_probe_hook)(struct parport *port);
 #define parport_write_control(p,x)         (p)->ops->write_control(p,x)
 #define parport_read_control(p)            (p)->ops->read_control(p)
 #define parport_frob_control(p,m,v)        (p)->ops->frob_control(p,m,v)
-#define parport_write_econtrol(p,x)        (p)->ops->write_econtrol(p,x)
-#define parport_read_econtrol(p)           (p)->ops->read_econtrol(p)
-#define parport_frob_econtrol(p,m,v)       (p)->ops->frob_econtrol(p,m,v)
-#define parport_write_status(p,v)          (p)->ops->write_status(p,v)
 #define parport_read_status(p)             (p)->ops->read_status(p)
-#define parport_write_fifo(p,v)            (p)->ops->write_fifo(p,v)
-#define parport_read_fifo(p)               (p)->ops->read_fifo(p)
-#define parport_change_mode(p,m)           (p)->ops->change_mode(p,m)
-#define parport_release_resources(p)       (p)->ops->release_resources(p)
-#define parport_claim_resources(p)         (p)->ops->claim_resources(p)
-#define parport_epp_write_data(p,x)        (p)->ops->epp_write_data(p,x)
-#define parport_epp_read_data(p)           (p)->ops->epp_read_data(p)
-#define parport_epp_write_addr(p,x)        (p)->ops->epp_write_addr(p,x)
-#define parport_epp_read_addr(p)           (p)->ops->epp_read_addr(p)
-#define parport_epp_check_timeout(p)       (p)->ops->epp_check_timeout(p)
+#define parport_enable_irq(p)              (p)->ops->enable_irq(p)
+#define parport_disable_irq(p)             (p)->ops->disable_irq(p)
+#define parport_data_forward(p)            (p)->ops->data_forward(p)
+#define parport_data_reverse(p)            (p)->ops->data_reverse(p)
 #endif
 
 #endif /* __KERNEL__ */
index cf93bb0089575513fee6540c413539dad76f4e92..955e685ad9de1883ed60e017302cec44bfe88f15 100644 (file)
 
 /* --- register definitions ------------------------------- */
 
-#define ECONTROL(p)    ((p)->base_hi + 0x02)
-#define CONFIGB(p)     ((p)->base_hi + 0x01)
-#define CONFIGA(p)     ((p)->base_hi + 0x00)
-#define EPPDATA(p)     ((p)->base    + 0x04)
-#define EPPADDR(p)     ((p)->base    + 0x03)
-#define CONTROL(p)     ((p)->base    + 0x02)
-#define STATUS(p)      ((p)->base    + 0x01)
-#define DATA(p)                ((p)->base    + 0x00)
-
-/* Private data for PC low-level driver. */
+#define ECONTROL(p) ((p)->base_hi + 0x2)
+#define CONFIGB(p)  ((p)->base_hi + 0x1)
+#define CONFIGA(p)  ((p)->base_hi + 0x0)
+#define FIFO(p)     ((p)->base_hi + 0x0)
+#define EPPDATA(p)  ((p)->base    + 0x4)
+#define EPPADDR(p)  ((p)->base    + 0x3)
+#define CONTROL(p)  ((p)->base    + 0x2)
+#define STATUS(p)   ((p)->base    + 0x1)
+#define DATA(p)     ((p)->base    + 0x0)
+
 struct parport_pc_private {
        /* Contents of CTR. */
        unsigned char ctr;
-};
 
-extern int parport_pc_epp_clear_timeout(struct parport *pb);
+       /* Bitmask of writable CTR bits. */
+       unsigned char ctr_writable;
 
-extern volatile unsigned char parport_pc_ctr;
+       /* Whether or not there's an ECR. */
+       int ecr;
 
-extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
-{
-       outb(d, EPPDATA(p));
-}
+       /* Number of PWords that FIFO will hold. */
+       int fifo_depth;
 
-extern __inline__ unsigned char parport_pc_read_epp(struct parport *p)
-{
-       return inb(EPPDATA(p));
-}
+       /* Number of bytes per portword. */
+       int pword;
 
-extern __inline__ void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
-{
-       outb(d, EPPADDR(p));
-}
+       /* Not used yet. */
+       int readIntrThreshold;
+       int writeIntrThreshold;
 
-extern __inline__ unsigned char parport_pc_read_epp_addr(struct parport *p)
-{
-       return inb(EPPADDR(p));
-}
+       /* buffer suitable for DMA, if DMA enabled */
+       char *dma_buf;
+};
 
-extern __inline__ int parport_pc_check_epp_timeout(struct parport *p)
+extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
 {
-       if (!(inb(STATUS(p)) & 1))
-               return 0;
-       parport_pc_epp_clear_timeout(p);
-       return 1;
+       outb(d, DATA(p));
 }
 
-extern __inline__ unsigned char parport_pc_read_configb(struct parport *p)
+extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
 {
-       return inb(CONFIGB(p));
+       return inb(DATA(p));
 }
 
-extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
+extern __inline__ unsigned char __frob_control (struct parport *p,
+                                               unsigned char mask,
+                                               unsigned char val)
 {
-       outb(d, DATA(p));
+       struct parport_pc_private *priv = p->physport->private_data;
+       unsigned char ctr = priv->ctr;
+       ctr = (ctr & ~mask) ^ val;
+       ctr &= priv->ctr_writable; /* only write writable bits. */
+       outb (ctr, CONTROL (p));
+       return priv->ctr = ctr; /* update soft copy */
 }
 
-extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
+extern __inline__ void parport_pc_data_reverse (struct parport *p)
 {
-       return inb(DATA(p));
+       __frob_control (p, 0x20, 0x20);
 }
 
-extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d)
+extern __inline__ void parport_pc_write_control (struct parport *p,
+                                                unsigned char d)
 {
-       struct parport_pc_private *priv = p->private_data;
-       priv->ctr = d;/* update soft copy */
-       outb(d, CONTROL(p));
+       const unsigned char wm = (PARPORT_CONTROL_STROBE |
+                                 PARPORT_CONTROL_AUTOFD |
+                                 PARPORT_CONTROL_INIT |
+                                 PARPORT_CONTROL_SELECT);
+
+       /* Take this out when drivers have adapted to newer interface. */
+       if (d & 0x20) {
+                       printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+                                       p->name, p->cad->name);
+                       parport_pc_data_reverse (p);
+       }
+
+       __frob_control (p, wm, d & wm);
 }
 
 extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
 {
-       struct parport_pc_private *priv = p->private_data;
-       return priv->ctr;
+       const struct parport_pc_private *priv = p->physport->private_data;
+       return priv->ctr; /* Use soft copy */
 }
 
-extern __inline__ unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
+extern __inline__ unsigned char parport_pc_frob_control (struct parport *p,
+                                                        unsigned char mask,
+                                                        unsigned char val)
 {
-       struct parport_pc_private *priv = p->private_data;
-       unsigned char ctr = priv->ctr;
-       ctr = (ctr & ~mask) ^ val;
-       outb (ctr, CONTROL(p));
-       return priv->ctr = ctr; /* update soft copy */
-}
+       const unsigned char wm = (PARPORT_CONTROL_STROBE |
+                                 PARPORT_CONTROL_AUTOFD |
+                                 PARPORT_CONTROL_INIT |
+                                 PARPORT_CONTROL_SELECT);
 
-extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d)
-{
-       outb(d, STATUS(p));
+       /* Take this out when drivers have adapted to newer interface. */
+       if (mask & 0x20) {
+                       printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+                                       p->name, p->cad->name);
+                       parport_pc_data_reverse (p);
+       }
+
+       /* Restrict mask and val to control lines. */
+       mask &= wm;
+       val &= wm;
+
+       return __frob_control (p, mask, val);
 }
 
 extern __inline__ unsigned char parport_pc_read_status(struct parport *p)
@@ -99,51 +118,31 @@ extern __inline__ unsigned char parport_pc_read_status(struct parport *p)
        return inb(STATUS(p));
 }
 
-extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned char d)
+extern __inline__ void parport_pc_data_forward (struct parport *p)
 {
-       outb(d, ECONTROL(p));
+       __frob_control (p, 0x20, 0x00);
 }
 
-extern __inline__ unsigned char parport_pc_read_econtrol(struct parport *p)
+extern __inline__ void parport_pc_disable_irq(struct parport *p)
 {
-       return inb(ECONTROL(p));
+       __frob_control (p, 0x10, 0x00);
 }
 
-extern __inline__ unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask,  unsigned char val)
+extern __inline__ void parport_pc_enable_irq(struct parport *p)
 {
-       unsigned char old = inb(ECONTROL(p));
-       outb(((old & ~mask) ^ val), ECONTROL(p));
-       return old;
+       __frob_control (p, 0x10, 0x10);
 }
 
-extern void parport_pc_change_mode(struct parport *p, int m);
-
-extern void parport_pc_write_fifo(struct parport *p, unsigned char v);
-
-extern unsigned char parport_pc_read_fifo(struct parport *p);
-
-extern void parport_pc_disable_irq(struct parport *p);
-
-extern void parport_pc_enable_irq(struct parport *p);
-
 extern void parport_pc_release_resources(struct parport *p);
 
 extern int parport_pc_claim_resources(struct parport *p);
 
-extern void parport_pc_init_state(struct parport_state *s);
+extern void parport_pc_init_state(struct pardevice *, struct parport_state *s);
 
 extern void parport_pc_save_state(struct parport *p, struct parport_state *s);
 
 extern void parport_pc_restore_state(struct parport *p, struct parport_state *s);
 
-extern size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length);
-
-extern size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length);
-
-extern int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle);
-
-extern int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle);
-
 extern void parport_pc_inc_use_count(void);
 
 extern void parport_pc_dec_use_count(void);
index c621b325ef0edaa407d34877d3c9e4352a0e45de..251aa8f9d205a795ed0082ca23615dff65933356 100644 (file)
@@ -172,7 +172,10 @@ struct mm_struct {
        atomic_t count;
        int map_count;                          /* number of VMAs */
        struct semaphore mmap_sem;
+       rwlock_t page_table_lock;
        unsigned long context;
+       unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
+       int swappable:1;
        unsigned long start_code, end_code, start_data, end_data;
        unsigned long start_brk, brk, start_stack;
        unsigned long arg_start, arg_end, env_start, env_end;
@@ -193,6 +196,9 @@ struct mm_struct {
                swapper_pg_dir,                         \
                ATOMIC_INIT(1), 1,                      \
                __MUTEX_INITIALIZER(name.mmap_sem),     \
+               RW_LOCK_UNLOCKED,                       \
+               0,                                      \
+               0, 0, 0, 0, 0, 0,                       \
                0,                                      \
                0, 0, 0, 0,                             \
                0, 0, 0,                                \
@@ -280,9 +286,6 @@ struct task_struct {
        struct tms times;
        unsigned long start_time;
        long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
-/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
-       unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
-       int swappable:1;
 /* process credentials */
        uid_t uid,euid,suid,fsuid;
        gid_t gid,egid,sgid,fsgid;
@@ -343,7 +346,7 @@ struct task_struct {
  */
 #define _STK_LIM       (8*1024*1024)
 
-#define DEF_PRIORITY   (20*HZ/100)     /* 210 ms time slices */
+#define DEF_PRIORITY   (20*HZ/100)     /* 200 ms time slices */
 
 /*
  *  INIT_TASK is used to set up the first task table, touch at
@@ -365,8 +368,6 @@ struct task_struct {
 /* timer */    { NULL, NULL, 0, 0, it_real_fn }, \
 /* utime */    {0,0,0,0},0, \
 /* per CPU times */ {0, }, {0, }, \
-/* flt */      0,0,0,0,0,0, \
-/* swp */      0, \
 /* process credentials */                                      \
 /* uid etc */  0,0,0,0,0,0,0,0,                                \
 /* suppl grps*/ 0, {0,},                                       \
index fa417791400e587d32450ac565265db99fafbcc2..da5665a5be4ad62f7112cef0654d8163c94ae99a 100644 (file)
@@ -90,9 +90,6 @@ extern void rw_swap_page_nolock(int, unsigned long, char *, int);
 extern void swap_after_unlock_page (unsigned long entry);
 
 /* linux/mm/page_alloc.c */
-extern void swap_in(struct task_struct *, struct vm_area_struct *,
-                   pte_t *, unsigned long, int);
-
 
 /* linux/mm/swap_state.c */
 extern void show_swap_cache_info(void);
index 36380c533f234cddd20988a8df9bb41fd5adcf19..395104aaf89de6e2e53fbf3db8a6e42c7c0ea8d0 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -381,8 +381,7 @@ static struct vm_operations_struct shm_vm_ops = {
        NULL,                   /* advise */
        shm_nopage,             /* nopage */
        NULL,                   /* wppage */
-       shm_swapout,            /* swapout */
-       NULL                    /* swapin */
+       shm_swapout             /* swapout */
 };
 
 /* Insert shmd into the list shp->attaches */
@@ -548,6 +547,7 @@ static void shm_open (struct vm_area_struct *shmd)
        unsigned int id;
        struct shmid_kernel *shp;
 
+       lock_kernel();
        id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
        shp = shm_segs[id];
        if (shp == IPC_UNUSED) {
@@ -558,6 +558,7 @@ static void shm_open (struct vm_area_struct *shmd)
        shp->u.shm_nattch++;
        shp->u.shm_atime = CURRENT_TIME;
        shp->u.shm_lpid = current->pid;
+       unlock_kernel();
 }
 
 /*
@@ -571,6 +572,7 @@ static void shm_close (struct vm_area_struct *shmd)
        struct shmid_kernel *shp;
        int id;
 
+       lock_kernel();
        /* remove from the list of attaches of the shm segment */
        id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
        shp = shm_segs[id];
@@ -579,6 +581,7 @@ static void shm_close (struct vm_area_struct *shmd)
        shp->u.shm_dtime = CURRENT_TIME;
        if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST)
                killseg (id);
+       unlock_kernel();
 }
 
 /*
@@ -672,10 +675,10 @@ static unsigned long shm_nopage(struct vm_area_struct * shmd, unsigned long addr
                pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
                shp->shm_pages[idx] = pte_val(pte);
        } else
-               --current->maj_flt;  /* was incremented in do_no_page */
+               --current->mm->maj_flt;  /* was incremented in do_no_page */
 
 done:  /* pte_val(pte) == shp->shm_pages[idx] */
-       current->min_flt++;
+       current->mm->min_flt++;
        get_page(mem_map + MAP_NR(pte_page(pte)));
        return pte_page(pte);
 }
index 57d8441da5e1e7056f83e05ba3ccf31d115f57a5..a4ac8ae66eb8d8da5c896afe10148a44d43adf44 100644 (file)
@@ -52,9 +52,11 @@ static void release(struct task_struct * p)
                write_unlock_irq(&tasklist_lock);
 
                release_thread(p);
+#if 0 /* FIXME! How do we do this right for threads? */
                current->cmin_flt += p->min_flt + p->cmin_flt;
                current->cmaj_flt += p->maj_flt + p->cmaj_flt;
                current->cnswap += p->nswap + p->cnswap;
+#endif
                free_task_struct(p);
        } else {
                printk("task releasing itself\n");
@@ -256,7 +258,6 @@ static inline void __exit_mm(struct task_struct * tsk)
                flush_tlb_mm(mm);
                destroy_context(mm);
                tsk->mm = &init_mm;
-               tsk->swappable = 0;
                SET_PAGE_DIR(tsk, swapper_pg_dir);
                mm_release();
                mmput(mm);
index 7534f1d919e232963079d9348042357533cab306..bb4bec1ea5eb9a2993f211e23a4ba90f8426977f 100644 (file)
@@ -304,6 +304,7 @@ struct mm_struct * mm_alloc(void)
                mm->map_count = 0;
                mm->def_flags = 0;
                init_MUTEX_LOCKED(&mm->mmap_sem);
+               mm->page_table_lock = RW_LOCK_UNLOCKED;
                /*
                 * Leave mm->pgd set to the parent's pgd
                 * so that pgd_offset() is always valid.
@@ -314,6 +315,7 @@ struct mm_struct * mm_alloc(void)
                 * cache or tlb.
                 */
                mm->cpu_vm_mask = 0;
+               mm->swappable = 0;
        }
        return mm;
 }
@@ -376,9 +378,6 @@ static inline int copy_mm(int nr, unsigned long clone_flags, struct task_struct
                goto fail_nomem;
 
        tsk->mm = mm;
-       tsk->min_flt = tsk->maj_flt = 0;
-       tsk->cmin_flt = tsk->cmaj_flt = 0;
-       tsk->nswap = tsk->cnswap = 0;
        copy_segments(nr, tsk, mm);
        retval = new_page_tables(tsk);
        if (retval)
@@ -576,7 +575,6 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
                __MOD_INC_USE_COUNT(p->binfmt->module);
 
        p->did_exec = 0;
-       p->swappable = 0;
        p->state = TASK_UNINTERRUPTIBLE;
 
        copy_flags(clone_flags, p);
@@ -641,7 +639,7 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
        p->semundo = NULL;
 
        /* ok, now we should be set up.. */
-       p->swappable = 1;
+       p->mm->swappable = 1;
        p->exit_signal = clone_flags & CSIGNAL;
        p->pdeath_signal = 0;
 
index 846971a8965a1d295db51249f7c80676f3938610..95b9b823c01ca619bf26eecbcf8b21718994abae 100644 (file)
@@ -1465,7 +1465,7 @@ static void update_process_times(unsigned long ticks, unsigned long system)
        unsigned long user = ticks - system;
        if (p->pid) {
                p->counter -= ticks;
-               if (p->counter < 0) {
+               if (p->counter <= 0) {
                        p->counter = 0;
                        p->need_resched = 1;
                }
@@ -1668,7 +1668,7 @@ asmlinkage int sys_nice(int increment)
         * do a "normalization" of the priority (traditionally
         * Unix nice values are -20 to 20; Linux doesn't really
         * use that kind of thing, but uses the length of the
-        * timeslice instead (default 210 ms). The rounding is
+        * timeslice instead (default 200 ms). The rounding is
         * why we want to avoid negative values.
         */
        newprio = (newprio * DEF_PRIORITY + 10) / 20;
index 5302297d81e0fbf39384e9cbd51b58207a0c33bc..0179dc7ea29deb9bb982164a270933d1bcc2de2b 100644 (file)
@@ -930,6 +930,8 @@ asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
  * either stopped or zombied.  In the zombied case the task won't get
  * reaped till shortly after the call to getrusage(), in both cases the
  * task being examined is in a frozen state so the counters won't change.
+ *
+ * FIXME! Get the fault counts properly!
  */
 int getrusage(struct task_struct *p, int who, struct rusage *ru)
 {
@@ -942,27 +944,27 @@ int getrusage(struct task_struct *p, int who, struct rusage *ru)
                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime);
                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime);
-                       r.ru_minflt = p->min_flt;
-                       r.ru_majflt = p->maj_flt;
-                       r.ru_nswap = p->nswap;
+                       r.ru_minflt = 0;
+                       r.ru_majflt = 0;
+                       r.ru_nswap = 0;
                        break;
                case RUSAGE_CHILDREN:
                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_cutime);
                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_cutime);
                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_cstime);
                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_cstime);
-                       r.ru_minflt = p->cmin_flt;
-                       r.ru_majflt = p->cmaj_flt;
-                       r.ru_nswap = p->cnswap;
+                       r.ru_minflt = 0;
+                       r.ru_majflt = 0;
+                       r.ru_nswap = 0;
                        break;
                default:
                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime + p->times.tms_cutime);
                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime + p->times.tms_cutime);
                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime + p->times.tms_cstime);
                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime + p->times.tms_cstime);
-                       r.ru_minflt = p->min_flt + p->cmin_flt;
-                       r.ru_majflt = p->maj_flt + p->cmaj_flt;
-                       r.ru_nswap = p->nswap + p->cnswap;
+                       r.ru_minflt = 0;
+                       r.ru_majflt = 0;
+                       r.ru_nswap = 0;
                        break;
        }
        return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
index ed5b6d34c7a526acf0c779b0488207db7c8fc116..7ce68148766784bd3e7c2412789ceb9c0b49486b 100644 (file)
@@ -1194,8 +1194,6 @@ asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t cou
        struct file * in_file, * out_file;
        struct inode * in_inode, * out_inode;
 
-       lock_kernel();
-
        /*
         * Get input file, and verify that it is ok..
         */
@@ -1234,7 +1232,6 @@ asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t cou
        if (retval)
                goto fput_out;
 
-       unlock_kernel();
        retval = 0;
        if (count) {
                read_descriptor_t desc;
@@ -1244,7 +1241,7 @@ asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t cou
                ppos = &in_file->f_pos;
                if (offset) {
                        if (get_user(pos, offset))
-                               goto fput_out_lock;
+                               goto fput_out;
                        ppos = &pos;
                }
 
@@ -1261,14 +1258,11 @@ asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t cou
                        put_user(pos, offset);
        }
 
-fput_out_lock:
-       lock_kernel();
 fput_out:
        fput(out_file);
 fput_in:
        fput(in_file);
 out:
-       unlock_kernel();
        return retval;
 }
 
@@ -1297,9 +1291,7 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long
        new_page = 0;
        offset = (address & PAGE_MASK) - area->vm_start + area->vm_offset;
        if (offset >= inode->i_size && (area->vm_flags & VM_SHARED) && area->vm_mm == current->mm)
-               goto no_page_nolock;
-
-       unlock_kernel();
+               goto no_page;
 
        /*
         * Do we have something in the page cache already?
@@ -1344,7 +1336,6 @@ success:
                        page_cache_free(new_page);
 
                flush_page_to_ram(old_page);
-               lock_kernel();
                return old_page;
        }
 
@@ -1354,7 +1345,6 @@ success:
        copy_page(new_page, old_page);
        flush_page_to_ram(new_page);
        page_cache_release(page);
-       lock_kernel();
        return new_page;
 
 no_cached_page:
@@ -1431,8 +1421,6 @@ failure:
        if (new_page)
                page_cache_free(new_page);
 no_page:
-       lock_kernel();
-no_page_nolock:
        return 0;
 }
 
@@ -1648,8 +1636,7 @@ static struct vm_operations_struct file_shared_mmap = {
        NULL,                   /* advise */
        filemap_nopage,         /* nopage */
        NULL,                   /* wppage */
-       filemap_swapout,        /* swapout */
-       NULL,                   /* swapin */
+       filemap_swapout         /* swapout */
 };
 
 /*
@@ -1667,8 +1654,7 @@ static struct vm_operations_struct file_private_mmap = {
        NULL,                   /* advise */
        filemap_nopage,         /* nopage */
        NULL,                   /* wppage */
-       NULL,                   /* swapout */
-       NULL,                   /* swapin */
+       NULL                    /* swapout */
 };
 
 /* This is used for a general mmap of a disk file */
index aac203bbb4f5afab5693eb3b77610a03c900a296..c6cf211aa268d1d4064af7fccac5a6422b07bcdd 100644 (file)
@@ -36,7 +36,9 @@
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/swap.h>
+#include <linux/pagemap.h>
 #include <linux/smp_lock.h>
+#include <linux/swapctl.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -599,21 +601,20 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
  * We also mark the page dirty at this point even though the page will
  * change only once the write actually happens. This avoids a few races,
  * and potentially makes it more efficient.
+ *
+ * We enter with the page table read-lock held, and need to exit without
+ * it.
  */
-static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
+static int do_wp_page(struct mm_struct * mm, struct vm_area_struct * vma,
        unsigned long address, pte_t *page_table, pte_t pte)
 {
        unsigned long old_page, new_page;
        struct page * page;
-       
-       new_page = __get_free_page(GFP_USER);
-       /* Did swap_out() unmap the protected page while we slept? */
-       if (pte_val(*page_table) != pte_val(pte))
-               goto end_wp_page;
+
        old_page = pte_page(pte);
        if (MAP_NR(old_page) >= max_mapnr)
                goto bad_wp_page;
-       tsk->min_flt++;
+       mm->min_flt++;
        page = mem_map + MAP_NR(old_page);
        
        /*
@@ -634,43 +635,43 @@ static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
                /* FallThrough */
        case 1:
                flush_cache_page(vma, address);
-               set_pte(page_table, pte_mkdirty(pte_mkwrite(pte)));
+               set_pte(page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
                flush_tlb_page(vma, address);
-end_wp_page:
-               /*
-                * We can release the kernel lock now.. Now swap_out will see
-                * a dirty page and so won't get confused and flush_tlb_page
-                * won't SMP race. -Andrea
-                */
-               unlock_kernel();
-
-               if (new_page)
-                       free_page(new_page);
+               read_unlock(&mm->page_table_lock);
                return 1;
        }
-               
+
+       /*
+        * Ok, we need to copy. Oh, well..
+        */
+       read_unlock(&mm->page_table_lock);
+       new_page = __get_free_page(GFP_USER);
        if (!new_page)
-               goto no_new_page;
+               return 0;
+       read_lock(&mm->page_table_lock);
 
-       if (PageReserved(page))
-               ++vma->vm_mm->rss;
-       copy_cow_page(old_page,new_page);
-       flush_page_to_ram(old_page);
-       flush_page_to_ram(new_page);
-       flush_cache_page(vma, address);
-       set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
-       flush_tlb_page(vma, address);
-       unlock_kernel();
-       __free_page(page);
+       /*
+        * Re-check the pte - we dropped the lock
+        */
+       if (pte_val(*page_table) == pte_val(pte)) {
+               if (PageReserved(page))
+                       ++vma->vm_mm->rss;
+               copy_cow_page(old_page,new_page);
+               flush_page_to_ram(old_page);
+               flush_page_to_ram(new_page);
+               flush_cache_page(vma, address);
+               set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
+               flush_tlb_page(vma, address);
+
+               /* Free the old page.. */
+               new_page = old_page;
+       }
+       read_unlock(&mm->page_table_lock);
+       free_page(new_page);
        return 1;
 
 bad_wp_page:
        printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
-       send_sig(SIGKILL, tsk, 1);
-no_new_page:
-       unlock_kernel();
-       if (new_page)
-               free_page(new_page);
        return 0;
 }
 
@@ -760,39 +761,82 @@ void vmtruncate(struct inode * inode, unsigned long offset)
 }
 
 
-/*
- * This is called with the kernel lock held, we need
- * to return without it.
+
+/* 
+ * Primitive swap readahead code. We simply read an aligned block of
+ * (1 << page_cluster) entries in the swap area. This method is chosen
+ * because it doesn't cost us any seek time.  We also make sure to queue
+ * the 'original' request together with the readahead ones...  
  */
-static int do_swap_page(struct task_struct * tsk, 
+static void swapin_readahead(unsigned long entry)
+{
+       int i;
+       struct page *new_page;
+       unsigned long offset = SWP_OFFSET(entry);
+       struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
+       
+       offset = (offset >> page_cluster) << page_cluster;
+
+       i = 1 << page_cluster;
+       do {
+               /* Don't read-ahead past the end of the swap area */
+               if (offset >= swapdev->max)
+                       break;
+               /* Don't block on I/O for read-ahead */
+               if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster)
+                       break;
+               /* Don't read in bad or busy pages */
+               if (!swapdev->swap_map[offset])
+                       break;
+               if (swapdev->swap_map[offset] == SWAP_MAP_BAD)
+                       break;
+
+               /* Ok, do the async read-ahead now */
+               new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0);
+               if (new_page != NULL)
+                       __free_page(new_page);
+               offset++;
+       } while (--i);
+       return;
+}
+
+static int do_swap_page(struct mm_struct * mm, 
        struct vm_area_struct * vma, unsigned long address,
-       pte_t * page_table, pte_t entry, int write_access)
+       pte_t * page_table, unsigned long entry, int write_access)
 {
-       if (!vma->vm_ops || !vma->vm_ops->swapin) {
-               swap_in(tsk, vma, page_table, pte_val(entry), write_access);
-               flush_page_to_ram(pte_page(*page_table));
-       } else {
-               pte_t page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, pte_val(entry));
-               if (pte_val(*page_table) != pte_val(entry)) {
-                       free_page(pte_page(page));
-               } else {
-                       if (page_count(mem_map + MAP_NR(pte_page(page))) > 1 &&
-                           !(vma->vm_flags & VM_SHARED))
-                               page = pte_wrprotect(page);
-                       ++vma->vm_mm->rss;
-                       ++tsk->maj_flt;
-                       flush_page_to_ram(pte_page(page));
-                       set_pte(page_table, page);
-               }
+       struct page *page = lookup_swap_cache(entry);
+       pte_t pte;
+
+       if (!page) {
+               lock_kernel();
+               swapin_readahead(entry);
+               page = read_swap_cache(entry);
+               unlock_kernel();
+               if (!page)
+                       return 0;
+
+               flush_page_to_ram(page_address(page));
        }
-       unlock_kernel();
+
+       vma->vm_mm->rss++;
+       mm->min_flt++;
+       swap_free(entry);
+
+       pte = mk_pte(page_address(page), vma->vm_page_prot);
+
+       if (write_access && !is_page_shared(page)) {
+               delete_from_swap_cache(page);
+               pte = pte_mkwrite(pte_mkdirty(pte));
+       }
+       set_pte(page_table, pte);
+               
        return 1;
 }
 
 /*
  * This only needs the MM semaphore
  */
-static int do_anonymous_page(struct task_struct * tsk, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)
+static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)
 {
        pte_t entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));
        if (write_access) {
@@ -802,7 +846,7 @@ static int do_anonymous_page(struct task_struct * tsk, struct vm_area_struct * v
                clear_page(page);
                entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
                vma->vm_mm->rss++;
-               tsk->min_flt++;
+               mm->min_flt++;
                flush_page_to_ram(page);
        }
        set_pte(page_table, entry);
@@ -821,31 +865,25 @@ static int do_anonymous_page(struct task_struct * tsk, struct vm_area_struct * v
  * This is called with the MM semaphore and the kernel lock held.
  * We need to release the kernel lock as soon as possible..
  */
-static int do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
+static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,
        unsigned long address, int write_access, pte_t *page_table)
 {
        unsigned long page;
        pte_t entry;
 
-       if (!vma->vm_ops || !vma->vm_ops->nopage) {
-               unlock_kernel();
-               return do_anonymous_page(tsk, vma, page_table, write_access,
-                                        address);
-       }
+       if (!vma->vm_ops || !vma->vm_ops->nopage)
+               return do_anonymous_page(mm, vma, page_table, write_access, address);
 
        /*
         * The third argument is "no_share", which tells the low-level code
         * to copy, not share the page even if sharing is possible.  It's
         * essentially an early COW detection.
         */
-       page = vma->vm_ops->nopage(vma, address & PAGE_MASK,
-               (vma->vm_flags & VM_SHARED)?0:write_access);
-
-       unlock_kernel();
+       page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access);
        if (!page)
                return 0;
 
-       ++tsk->maj_flt;
+       ++mm->maj_flt;
        ++vma->vm_mm->rss;
        /*
         * This silly early PAGE_DIRTY setting removes a race
@@ -877,41 +915,53 @@ static int do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
  * There is also a hook called "update_mmu_cache()" that architectures
  * with external mmu caches can use to update those (ie the Sparc or
  * PowerPC hashed page tables that act as extended TLBs).
+ *
+ * Note the "page_table_lock". It is to protect against kswapd removing
+ * pages from under us. Note that kswapd only ever _removes_ pages, never
+ * adds them. As such, once we have noticed that the page is not present,
+ * we can drop the lock early.
+ *
+ * The adding of pages is protected by the MM semaphore (which we hold),
+ * so we don't need to worry about a page being suddenly been added into
+ * our VM.
  */
-static inline int handle_pte_fault(struct task_struct *tsk,
+static inline int handle_pte_fault(struct mm_struct *mm,
        struct vm_area_struct * vma, unsigned long address,
        int write_access, pte_t * pte)
 {
        pte_t entry;
 
-       lock_kernel();
        entry = *pte;
-
        if (!pte_present(entry)) {
                if (pte_none(entry))
-                       return do_no_page(tsk, vma, address, write_access, pte);
-               return do_swap_page(tsk, vma, address, pte, entry, write_access);
+                       return do_no_page(mm, vma, address, write_access, pte);
+               return do_swap_page(mm, vma, address, pte, pte_val(entry), write_access);
        }
 
-       entry = pte_mkyoung(entry);
-       set_pte(pte, entry);
-       flush_tlb_page(vma, address);
-       if (write_access) {
-               if (!pte_write(entry))
-                       return do_wp_page(tsk, vma, address, pte, entry);
+       /*
+        * Ok, the entry was present, we need to get the page table
+        * lock to synchronize with kswapd, and verify that the entry
+        * didn't change from under us..
+        */
+       read_lock(&mm->page_table_lock);
+       if (pte_val(entry) == pte_val(*pte)) {
+               if (write_access) {
+                       if (!pte_write(entry))
+                               return do_wp_page(mm, vma, address, pte, entry);
 
-               entry = pte_mkdirty(entry);
-               set_pte(pte, entry);
+                       entry = pte_mkdirty(entry);
+               }
+               set_pte(pte, pte_mkyoung(entry));
                flush_tlb_page(vma, address);
        }
-       unlock_kernel();
+       read_unlock(&mm->page_table_lock);
        return 1;
 }
 
 /*
  * By the time we get here, we already hold the mm semaphore
  */
-int handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma,
+int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,
        unsigned long address, int write_access)
 {
        pgd_t *pgd;
@@ -922,7 +972,7 @@ int handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma,
        if (pmd) {
                pte_t * pte = pte_alloc(pmd, address);
                if (pte) {
-                       if (handle_pte_fault(tsk, vma, address, write_access, pte)) {
+                       if (handle_pte_fault(mm, vma, address, write_access, pte)) {
                                update_mmu_cache(vma, address, *pte);
                                return 1;
                        }
@@ -937,12 +987,13 @@ int handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma,
 void make_pages_present(unsigned long addr, unsigned long end)
 {
        int write;
+       struct mm_struct *mm = current->mm;
        struct vm_area_struct * vma;
 
-       vma = find_vma(current->mm, addr);
+       vma = find_vma(mm, addr);
        write = (vma->vm_flags & VM_WRITE) != 0;
        while (addr < end) {
-               handle_mm_fault(current, vma, addr, write);
+               handle_mm_fault(mm, vma, addr, write);
                addr += PAGE_SIZE;
        }
 }
index c9d07a2916794b70611c4b5d0c29b03891b651d8..8ed2979d9680faebffad7b6fed87342cc5959e9f 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -460,13 +460,13 @@ struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr,
        return NULL;
 }
 
-struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
+struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr)
 {
        struct vm_area_struct * vma;
        unsigned long start;
 
        addr &= PAGE_MASK;
-       vma = find_vma(tsk->mm,addr);
+       vma = find_vma(mm,addr);
        if (!vma)
                return NULL;
        if (vma->vm_start <= addr)
index 3f30a049e35004dbf4c5f64bd1841ba1c22e8402..22ce7ac00fbbc25ceb9b80182a4fa86fb5bbacfb 100644 (file)
@@ -345,90 +345,3 @@ unsigned long __init free_area_init(unsigned long start_mem, unsigned long end_m
        }
        return start_mem;
 }
-
-/* 
- * Primitive swap readahead code. We simply read an aligned block of
- * (1 << page_cluster) entries in the swap area. This method is chosen
- * because it doesn't cost us any seek time.  We also make sure to queue
- * the 'original' request together with the readahead ones...  
- */
-void swapin_readahead(unsigned long entry)
-{
-       int i;
-       struct page *new_page;
-       unsigned long offset = SWP_OFFSET(entry);
-       struct swap_info_struct *swapdev = SWP_TYPE(entry) + swap_info;
-       
-       offset = (offset >> page_cluster) << page_cluster;
-
-       i = 1 << page_cluster;
-       do {
-               /* Don't read-ahead past the end of the swap area */
-               if (offset >= swapdev->max)
-                       break;
-               /* Don't block on I/O for read-ahead */
-               if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster)
-                       break;
-               /* Don't read in bad or busy pages */
-               if (!swapdev->swap_map[offset])
-                       break;
-               if (swapdev->swap_map[offset] == SWAP_MAP_BAD)
-                       break;
-
-               /* Ok, do the async read-ahead now */
-               new_page = read_swap_cache_async(SWP_ENTRY(SWP_TYPE(entry), offset), 0);
-               if (new_page != NULL)
-                       __free_page(new_page);
-               offset++;
-       } while (--i);
-       return;
-}
-
-/*
- * The tests may look silly, but it essentially makes sure that
- * no other process did a swap-in on us just as we were waiting.
- *
- * Also, don't bother to add to the swap cache if this page-in
- * was due to a write access.
- */
-void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
-       pte_t * page_table, unsigned long entry, int write_access)
-{
-       unsigned long page;
-       struct page *page_map = lookup_swap_cache(entry);
-
-       if (!page_map) {
-               swapin_readahead(entry);
-               page_map = read_swap_cache(entry);
-       }
-       if (pte_val(*page_table) != entry) {
-               if (page_map)
-                       free_page_and_swap_cache(page_address(page_map));
-               return;
-       }
-       if (!page_map) {
-               set_pte(page_table, BAD_PAGE);
-               swap_free(entry);
-               oom(tsk);
-               return;
-       }
-
-       page = page_address(page_map);
-       vma->vm_mm->rss++;
-       tsk->min_flt++;
-       swap_free(entry);
-
-       if (!write_access || is_page_shared(page_map)) {
-               set_pte(page_table, mk_pte(page, vma->vm_page_prot));
-               return;
-       }
-
-       /*
-        * The page is unshared and we're going to dirty it - so tear
-        * down the swap cache and give exclusive access to the page to
-        * this process.
-        */
-       delete_from_swap_cache(page_map);
-       set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
-       return;
-}
index 4cccaf1717bc67af25ff5bd846136ede4c9760a4..3567098a15a38951a9345ad4c93df8562c58eafb 100644 (file)
@@ -45,7 +45,11 @@ static int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
        page_addr = pte_page(pte);
        if (MAP_NR(page_addr) >= max_mapnr)
                goto out_failed;
+
        page = mem_map + MAP_NR(page_addr);
+       write_lock(&tsk->mm->page_table_lock);
+       if (pte_val(pte) != pte_val(*page_table))
+               goto out_failed_unlock;
 
        /*
         * Dont be too eager to get aging right if
@@ -58,13 +62,13 @@ static int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
                 */
                set_pte(page_table, pte_mkold(pte));
                set_bit(PG_referenced, &page->flags);
-               goto out_failed;
+               goto out_failed_unlock;
        }
 
        if (PageReserved(page)
            || PageLocked(page)
            || ((gfp_mask & __GFP_DMA) && !PageDMA(page)))
-               goto out_failed;
+               goto out_failed_unlock;
 
        /*
         * Is the page already in the swap cache? If so, then
@@ -82,7 +86,7 @@ drop_pte:
                vma->vm_mm->rss--;
                flush_tlb_page(vma, address);
                __free_page(page);
-               goto out_failed;
+               goto out_failed_unlock;
        }
 
        /*
@@ -109,7 +113,7 @@ drop_pte:
         * locks etc.
         */
        if (!(gfp_mask & __GFP_IO))
-               goto out_failed;
+               goto out_failed_unlock;
 
        /*
         * Ok, it's really dirty. That means that
@@ -134,6 +138,7 @@ drop_pte:
        if (vma->vm_ops && vma->vm_ops->swapout) {
                pid_t pid = tsk->pid;
                pte_clear(page_table);
+               write_unlock(&tsk->mm->page_table_lock);
                flush_tlb_page(vma, address);
                vma->vm_mm->rss--;
                
@@ -153,8 +158,10 @@ drop_pte:
                goto out_failed; /* No swap space left */
                
        vma->vm_mm->rss--;
-       tsk->nswap++;
+       tsk->mm->nswap++;
        set_pte(page_table, __pte(entry));
+       write_unlock(&tsk->mm->page_table_lock);
+
        flush_tlb_page(vma, address);
        swap_duplicate(entry);  /* One for the process, one for the swap cache */
 
@@ -167,6 +174,8 @@ drop_pte:
 out_free_success:
        __free_page(page);
        return 1;
+out_failed_unlock:
+       write_unlock(&tsk->mm->page_table_lock);
 out_failed:
        return 0;
 }
@@ -343,7 +352,7 @@ static int swap_out(unsigned int priority, int gfp_mask)
                read_lock(&tasklist_lock);
                p = init_task.next_task;
                for (; p != &init_task; p = p->next_task) {
-                       if (!p->swappable)
+                       if (!p->mm->swappable)
                                continue;
                        if (p->mm->rss <= 0)
                                continue;
index 4c8c6e390cbface848b7a318fb2e6f172ff4fe6f..32228f25ec2354b33f87a28c254821baf3d1b515 100644 (file)
@@ -987,6 +987,8 @@ int atif_ioctl(int cmd, void *arg)
                                 return (-EPERM);
                         if(sa->sat_family != AF_APPLETALK)
                                 return (-EINVAL);
+                        if (atif == NULL)
+                                return (-EADDRNOTAVAIL);
 
                         /*
                          * give to aarp module to remove proxy entry
index 9a34b7580e6754224e68588fa7e44d8a08ef0b95..2594dbfe8557b34f9575c1d6a5d87483db188485 100644 (file)
@@ -1443,7 +1443,7 @@ void __init sock_init(void)
 {
        int i;
 
-       printk(KERN_INFO "Linux NET4.0 for Linux 2.2\n");
+       printk(KERN_INFO "Linux NET4.0 for Linux 2.3\n");
        printk(KERN_INFO "Based upon Swansea University Computer Society NET3.039\n");
 
        /*
index 0f2922dfd5817c227da94ab4dc74c71404ed7c23..d0de24eff8ad54dca3cda8aeeb2d3e7aef7af89b 100644 (file)
@@ -42,6 +42,7 @@
 #define __KERNEL_SYSCALLS__
 
 #include <linux/version.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/malloc.h>
 #include <linux/sched.h>
@@ -362,10 +363,7 @@ xprt_close(struct rpc_xprt *xprt)
        sk->state_change = xprt->old_state_change;
        sk->write_space  = xprt->old_write_space;
 
-       if (xprt->file)
-               fput(xprt->file);
-       else
-               sock_release(xprt->sock);
+       sock_release(xprt->sock);
        /*
         *      TCP doesnt require the rpciod now - other things may
         *      but rpciod handles that not us.
@@ -1429,39 +1427,6 @@ xprt_setup(struct socket *sock, int proto,
        return xprt;
 }
 
-/*
- * Create and initialize an RPC client given an open file.
- * This is obsolete now.
- */
-#if 0
-struct rpc_xprt *
-xprt_create(struct file *file, struct sockaddr_in *ap, struct rpc_timeout *to)
-{
-       struct rpc_xprt *xprt;
-       struct socket   *sock;
-       int             proto;
-
-       if (!file) {
-               printk("RPC: file == NULL in xprt_create!\n");
-               return NULL;
-       }
-
-       sock = &file->f_inode->u.socket_i;
-       if (sock->ops->family != PF_INET) {
-               printk(KERN_WARNING "RPC: only INET sockets supported\n");
-               return NULL;
-       }
-
-       proto = (sock->type == SOCK_DGRAM)? IPPROTO_UDP : IPPROTO_TCP;
-       if ((xprt = xprt_setup(sock, proto, ap, to)) != NULL) {
-               xprt->file = file;
-               atomic_inc(&file->f_count);
-       }
-
-       return xprt;
-}
-#endif
-
 /*
  * Bind to a reserved port
  */
diff --git a/scripts/ksymoops/Makefile b/scripts/ksymoops/Makefile
deleted file mode 100644 (file)
index 81e80c1..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-# Description file for ksymoops
-
-#      Thu Nov 26 16:37:46 EST 1998
-#      Version 0.6c
-#      Add -c option.
-
-#      Tue Nov  3 02:31:01 EST 1998
-#      Version 0.6
-#      Read lsmod (/proc/modules).
-#      Add Makefile defaults for vmlinux, ksyms, objects, System.map, lsmod.
-#      Upper case variables.
-#      Convert from a.out to bfd, using same format as ksymoops.
-
-DEFS = Makefile ksymoops.h
-
-# Defaults for vmlinux, ksyms, objects, lsmod, System.map.  Externalised so
-# distributions can tweak to suit their own file system layout.
-
-# To default to not reading a source, set to any empty string.
-# To default to reading a source, supply a quoted and escaped string.
-
-# If the string contains *r (*m, *n, *s) then it is replaced at run time by
-# the current value of `uname -r` (-m, -n, -s).  '*' was chosen as something
-# that rarely appears in filenames and does not cause problems like '%' or '$'.
-
-DEF_VMLINUX =                          # default no vmlinux
-DEF_OBJECTS = \"/lib/modules/*r/\"     # default current modules
-DEF_KSYMS = \"/proc/ksyms\"            # default current ksyms
-DEF_LSMOD = \"/proc/modules\"          # default current lsmod
-DEF_MAP = \"/usr/src/linux/System.map\"        # default current map
-DEF_CODE_BYTES = 1                     # default bytes per code unit
-
-# RedHat users might want defaults like these
-# DEF_MAP = \"/boot/System.map-*r\"
-# DEF_OBJECTS = \"/boot/module-info-*r\"
-
-PROGS = ksymoops
-
-CC=gcc
-CFLAGS = -Dlinux \
-        -Wall \
-        -Wno-conversion \
-        -Waggregate-return \
-        -Wstrict-prototypes \
-        -Wmissing-prototypes \
-        $(DEBUG)
-
-ifneq ($(strip $(DEF_VMLINUX)),)
-       CFLAGS += -DDEF_VMLINUX=$(strip $(DEF_VMLINUX))
-endif
-ifneq ($(strip $(DEF_OBJECTS)),)
-       CFLAGS += -DDEF_OBJECTS=$(strip $(DEF_OBJECTS))
-endif
-ifneq ($(strip $(DEF_KSYMS)),)
-       CFLAGS += -DDEF_KSYMS=$(strip $(DEF_KSYMS))
-endif
-ifneq ($(strip $(DEF_LSMOD)),)
-       CFLAGS += -DDEF_LSMOD=$(strip $(DEF_LSMOD))
-endif
-ifneq ($(strip $(DEF_MAP)),)
-       CFLAGS += -DDEF_MAP=$(strip $(DEF_MAP))
-endif
-
-CFLAGS += -DDEF_CODE_BYTES=$(strip $(DEF_CODE_BYTES))
-
-OBJECTS = io.o ksyms.o ksymoops.o map.o misc.o object.o oops.o re.o symbol.o
-
-all:   $(PROGS)
-
-:      $(OBJECTS)
-
-$(OBJECTS): $(DEFS)
-
-$(PROGS): %: %.o $(DEFS) $(OBJECTS)
-       $(CC) $(OBJECTS) $(CFLAGS) -lbfd -liberty -o $@
-       -@size $@
-
-clean:
-       rm -f core *.o $(PROGS)
index e38ee2c1013db0fe7564277c93adba5a34a47326..c463b4c7182ea7ee9454b707d7b8cc5e51d8091f 100644 (file)
@@ -1,399 +1,7 @@
-  ksymoops.
+ksymoops has been removed from the kernel.  It was always meant to be a
+free standing utility, not linked to any particular kernel version.
+The latest version can be found in ftp://ftp.ocs.com.au/pub/ksymoops,
+together with patches to other utilities in order to give more accurate
+Oops debugging.
 
-  Read a kernel Oops file and make the best stab at converting the code to
-  instructions and mapping stack values to kernel symbols.
-
-  Copyright Keith Owens <kaos@ocs.com.au>.
-  Released under the GNU Public Licence, Version 2.
-
-  To compile, simply type "make" in the ksymoops directory.
-
-  TESTERS WANTED.
-
-  ksymoops handles ix86.  It appears to handle Alpha, Sparc, M68K, PPC,
-  MIPS but I have no machine to test on.  I would appreciate feedback
-  from users of non ix86 machines.  In particular, it would be nice if
-  you could run
-
-   ksymoops -VMO -k /proc/ksyms -dd <oops.file >/tmp/ksymoops.log 2>&1
-
-  and mail /tmp/ksymoops.log to kaos@ocs.com.au
-
-  TODO:
-  Clean up these docs.
-  Tweak System.map to include arch information.
-  Tweak modutils to log at least one symbol for each module loaded,
-  otherwise they are invisible to ksymoops.  Also arch and version data.
-  Include sparc/sparc64 patches from Jakub Jelinek <jj@sunsite.mff.cuni.cz>.
-  Add object format override for sparc/soparc64 or any cross platform
-  oops debugging.
-
-  Mon Jan  4 09:48:13 EST 1999
-  Version 0.6e
-  Added to kernel.
-  Add ARM support.
-  Typo in oops_code.
-  Add -c option.
-  Add -1 option.
-  Report if options were specified or defaulted.
-  Remove false warnings when comparing ksyms and lsmod.
-  Performance inprovements.
-
-  Wed Oct 28 23:14:55 EST 1998
-  Version 0.5
-  No longer read vmlinux by default, it only duplicates System.map.
-
-  Wed Oct 28 13:46:39 EST 1998
-  Version 0.4
-  Split into separate sources.
-
-  Mon Oct 26 00:01:47 EST 1998
-  Version 0.3c
-  Add alpha (arm) processing.
-
-  Mon Oct 26 00:01:47 EST 1998
-  Version 0.3b
-  Add sparc processing.
-  Handle kernel symbol versions.
-
-  Fri Oct 23 13:11:20 EST 1998
-  Version 0.3
-  Add -follow to find command for people who use symlinks to modules.
-  Add Version_ checking.
-
-  Thu Oct 22 22:28:30 EST 1998
-  Version 0.2.
-  Generalise text prefix handling.
-  Handle messages on Code: line.
-  Format addresses with leading zeroes.
-  Minor bug fixes.
-
-  Wed Oct 21 23:28:48 EST 1998
-  Version 0.1.  Rewrite from scratch in C.
-
-  CREDITS.
-  Oops disassembly based on ksymoops.cc,
-    Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
-  m68k code based on ksymoops.cc changes by
-    Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-
-  This code subsumes the Perl script make_System.map.pl which is no longer
-  supported.
-
-  Why another ksymoops I hear you ask?  Various complaints about
-  ksymoops.cc -
-
-  * It requires C++.
-  * It has hard wired limitations on the number of symbols.
-  * It does not handle modules at all.
-  * Very rigid requirements on the format of input, especially the Oops
-    log.
-  * No cross checking between ksyms, modules, System.map etc.
-  * Very little error checking, diagnostics are not suitable for
-    beginners.
-  * It only prints the trace and decoded code, users have to manually
-    extract the other lines from the Oops.
-  * Gives up on the slightest problem.
-  * Only handles i386 and possibly m68k.  The code is difficult to extend
-    to other architectures.
-  * Stops after the first Oops, you have to manually extract each one and
-    run through ksymoops one at a time.
-
-  This version is -
-  * C.
-  * No hard wired limitations (malloc as far as the eye can see).
-  * Handles modules by default.
-  * Uses regular pattern matching so it is a lot more forgiving about
-    input formats.
-  * By default, cross checks ksyms, modules, System.map and vmlinux.
-  * Lots of diagnostics and error checking.
-  * Prints all relevant lines for a complete Oops report.
-  * Tries to provide output no matter how bad the input is.  The level of
-     progress and error reporting is aimed at beginners.
-  * Handles i386, alpha, sparc, sparc64, m68k.  It is a lot easier to extend
-    to other architectures (patches and/or sample data gratefully accepted).
-  * Handles all Oops in the input file(s).
-
-
-  Usage:       ksymoops
-                 [-v vmlinux]  Where to read vmlinux
-                 [-V]          No vmlinux is available
-                 [-o object_dir]       Directory containing modules
-                 [-O]          No modules is available
-                 [-k ksyms]    Where to read ksyms
-                 [-K]          No ksyms is available
-                 [-l lsmod]    Where to read lsmod
-                 [-L]          No lsmod is available
-                 [-m system.map]       Where to read System.map
-                 [-M]          No System.map is available
-                 [-s save.map] Save consolidated map
-                 [-c code_bytes]       How many bytes in each unit of code
-                 [-1]          One shot toggle (exit after first Oops)
-                 [-d]          Increase debug level by 1
-                 [-h]          Print help text
-                 Oops.file     Oops to decode
-
-         All flags can occur more than once.  With the exception of -o
-         and -d which are cumulative, the last occurrence of each flag is
-         used.  Note that "-v my.vmlinux -V" will be taken as "No vmlinux
-         available" but "-V -v my.vmlinux" will read my.vmlinux.  You
-         will be warned about such combinations.
-
-         Each occurrence of -d increases the debug level.
-
-         Each -o flag can refer to a directory or to a single object
-         file.  If a directory is specified then all *.o files in that
-         directory and its subdirectories are assumed to be modules.
-
-         If any of the vmlinux, object_dir, ksyms or system.map options
-         contain the string *r (*m, *n, *s) then it is replaced at run time
-         by the current value of `uname -r` (-m, -n, -s).
-
-         The defaults can be changed in the Makefile, typical options are
-
-         Defaults:       -V
-                         -o /lib/modules/%r
-                         -k /proc/ksyms
-                         -l /proc/modules
-                         -m /usr/src/linux/System.map
-                         -c 1
-                         Oops report is read from stdin
-
-  Note:          Unless you tell ksymoops *NOT* to read a particular file, it
-         will try to read and reconcile almost all possible sources of kernel
-         symbol information.  This is intended for beginners, they just
-         type
-
-           ksymoops < /var/log/syslog
-
-         no thinking required.  Experts can point at different files or
-         suppress the input from selected files.  For example, if you
-         save /proc/ksyms before doing a test that creates an Oops, you
-         can point ksymoops at the saved ksyms instead of using
-         /proc/ksyms.
-
-         vmlinux is not read by default, it only duplicates the
-         information in System.map.  If you want to read vmlinux as well
-         as or instead of System.map, use -v.
-
-         To get the equivalent of the old ksymoops.cc (no vmlinux, no
-         modules objects, no ksyms, no System.map) just do ksymoops
-         -VOKLM.  Or to just read System.map, ksymoops -VOKL -m mapfile.
-
-
-  Return codes:          0 - normal.
-                 1 - error(s) or warning(s) issued, results may not be
-                     reliable.
-                 2 - fatal error, no useful results.
-                 3 - One shot mode, end of input reached.
-
-  Supported architectures
-
-         i386 tested.
-          m68k code derived from ksymoops.cc and reading traps.c, untested.
-         MIPS tested.
-         Sparc tested.
-         Sparc64 tested.
-         Alpha tested.
-         ARM tested.
-
-         The term "eip" is generic, for example it includes the i386 EIP
-         and the m68k PC.  Remember that objdump output always says EIP,
-         no matter what the architecture, see objfile_head.
-
-         To support another arch, check the Oops_ procedures between
-         'Start architecture sensitive code' and 'End architecture
-         sensitive code'.
-
-         The pattern matching should take care of different lengths for
-         the address, i.e. addresses should not be arch sensitive.  I
-         assume that all addresses are at least 4 characters.
-
-         If nm output has a different format on your arch, check for uses
-         of re_nm.
-
-
-
-  Because ksymoops reads kernel information from multiple sources, there
-  could be mismatches.  ksymoops does the following cross checks, but only
-  if the specified files exist -
-
-  * Compare Version_nnn numbers from all sources against each other.  Pity
-    that only vmlinux and System.map have these symbols (as at 2.1.125),
-    however I check ksyms, modules and Oops as well.  If somebody adds
-    symbol Version_nnn to ksyms or modules or adds a Version_nnn line to
-    the Oops log, this code is ready.
-
-  * Compare kernel ksyms against vmlinux.  vmlinux takes precedence.
-
-  * Compare System.map against vmlinux.   vmlinux takes precedence.
-
-  * Compare vmlinux against System.map.   vmlinux takes precedence.
-
-  * Compare kernel ksyms against System.map.  System.map takes precedence.
-
-  * Compare modules against module ksyms.  modules take precedence.  Only
-    if at least one module appears in ksyms.
-
-  * Compare module names in ksyms against lsmod.  Warn if a module
-    appears in lsmod but not in ksyms.  Error if a modules appears in
-    ksyms but is not in lsmod.  Only if both ksyms and lsmod have being
-    read.
-
-  The precedence order is somewhat arbitrary, however it only applies if
-  there is any difference between the various sources.
-
-  Handling modules is awkward.  They can be loaded under different names
-  (insmod -o dummy1 dummy.o) and the text, data and read only data are
-  loaded at different offsets.  Although you can give the -m option to
-  insmod which will output the module map when it is loaded, this has a
-  few problems -
-
-  * No equivalent for removing a module.  If you load and remove a lot of
-    modules, you end up with multiple sets of symbols around the same
-    offsets, which set is correct?
-
-  * "insmod -o dummy1 dummy.o" still reports as dummy.  That is, there is
-     no way of telling which particular version of a multiply loaded
-     module the insmod output refers to.  Therefore there is no way of
-     telling which instantiation failed.
-
-  * Even if the above problems are fixed, how do you tell what the module
-    environment looked like when the Oops occurred?  What if a module is
-    loaded or removed just after Oops, how is the user expected to edit
-    the insmod log?  Rule 1 - make ksymoops easy for beginners.
-
-  Although those problems could be fixed, they require changes to
-  modutils.  Working from ksyms and the module objects can be done without
-  changing modutils and without confusing beginners.
-  
-  Alas the ksyms plus object approach has another problem - matching ksyms
-  to module objects.  Nowhere does the kernel say that module dummy1 came
-  from module /lib/modules/2.1.215/net/dummy.o, ksyms just says dummy1.  I
-  have to match ksyms to the relevant object by finding a globally unique
-  external symbol in each module that can be used to map to the external
-  symbols in ksyms.  This assumes that each module exports at least one
-  text symbol that is unique amongst all modules.
-
-  It may not be possible to correctly map other sections such as data and
-  readonly data for modules because they may not have exported symbols.
-  Since the main aim of ksymoops is to map a code Oops, this should not be
-  a problem.
-
-  Unfortunately some modules export no symbols.  They are marked as
-  EXPORT_NO_SYMBOLS are simply do not export anything.  It is
-  impossible to detect these in ksyms because, by definition, ksyms
-  only contains exported symbols for modules.  Since all modules appear
-  in lsmod (/proc/modules), a cross check of lsmod against the module
-  names will find loaded modules with no symbols, at least I can warn
-  about these.
-
-  After merging the various sources, ksymoops has a (hopefully) accurate
-  map including modules.  The -s option lets you save the merged
-  System.map, but remember that module data and readonly data sections may
-  not be correctly relocated, see above.
-
-  Environment Variables.
-  KSYMOOPS_NM          path for nm, defaults to /usr/bin/nm.
-  KSYMOOPS_FIND                path for find, defaults to /usr/bin/find.
-  KSYMOOPS_OBJDUMP     path for objdump, defaults to /usr/bin/objdump.
-
-
-  Input Oops data.
-
-  The ideal input is to feed the syslog straight into this program.  If
-  you cannot do that, you need to know what the program looks for.
-  Especially if you are typing in the Oops by hand :(.  All input is case
-  insensitive.
-
-  * White space in this context means space or tab.  It does not include
-    newline.
-
-  * Oops in syslog has a syslog prefix.  Leading text up to and including
-    ' kernel: ' is always ignored, there is no need to edit syslog first.
-    This leading text need not exist but if it does, it must end in
-    ' kernel: '.
-
-  * An alternative prefix is <n> where n is the kernel print level.  Also
-    ignored if present.
-
-  * Leading white space is treated as a prefix and ignored, the input is
-    not indentation sensitive.
-
-  * In the following paragraphs, assume that any prefixes have been
-    skipped.  If there is more than one prefix, all are skipped, no matter
-    which order they appear in.
-
-  * A bracketed address is optional '[', required '<', at least 4 hex
-    digits, required '>', optional ']'.  For example [<01234567>] or
-    <1234>.
-
-  * The ix86 EIP line is identified by optional white space followed by
-    'EIP:', followed by a least one white space, followed by a bracketed
-    address.
-
-  * The m68k PC line is identified by optional white space followed by
-    'PC', optionally followed by white space, followed by '=', optionally
-    followed by white space, followed by a bracketed address.
-
-  * The sparc PC line starts with PSR and PC is the second hex value, not
-    bracketed.
-
-  * The sparc64 TPC line starts with TSTATE and TPC is the second hex value,
-    not bracketed.
-
-  * A call trace line is identified by 'Call Trace:' followed by at least
-    one white space.  Or it is a line starting with a bracketed address,
-    but only if the previous line was a call trace line (I hate multi line
-    output that relies on identation for recognition, especially when
-    lines can have a variable prefix).
-
-  * The Code line is identified by 'Code:' followed by a least one white
-    space character followed by at least one hex value.  The line can
-    contain multiple hex values, each separated by at least one white
-    space.  Each hex value must be 2 to 8 digits and must be a multiple of
-    2 digits.
-
-    On some architectures the Code: data is a stream of single bytes,
-    in machine order.  On other architectures, it is a stream of shorts
-    or ints in human readable order which does not always match the
-    machine order, endianess raises its ugly head.  We are consistently
-    inconsistent.
-
-    To cater for these architecture inconsistencies, use the -c option.
-    If the Code: line is already in machine order, use -c 1.  If the
-    Code: data is a stream of shorts or ints which do not match the
-    machine order, use -c 2 or -c 4.  Each set of 'c' bytes are swapped
-    to (hopefully) reflect the machine order.
-
-    Special cases where Code: can be followed by text.
-      'Code: general protection'
-      'Code: <n>'
-    Dump the data anyway, the code was unavailable.
-
-  * Formatted data is only output when the Code: line is seen.  If any
-    data has been stored and more than 5 lines other than Oops text (see
-    Oops_print) or end of file are encountered then ksymoops assumes that
-    the Code: line is missing or garbled and dumps the formatted data
-    anyway.  Fail safe, I hope.
-
-  * By default, ksymoops reads its entire input file.  If the -1 toggle
-    is set, it will run in one shot mode and exit after the first Oops.
-    This is useful for automatically mailing reports as they happen,
-    like this :-
-
-    #!/bin/sh
-    # ksymoops1
-    while (true)
-    do
-       ksymoops -1 > $HOME/oops1
-       if [ $? -eq 3 ]
-       then
-          exit 0
-       fi
-       mail -s Oops admin < $HOME/oops1
-    done
-
-    tail -f /var/log/messages | ksymoops1
-
-    Restarting after log rotation is left as an exercise for the reader.
+Keith Owens <kaos@ocs.com.au> Sat Jun 19 10:30:34 EST 1999
diff --git a/scripts/ksymoops/io.c b/scripts/ksymoops/io.c
deleted file mode 100644 (file)
index b54e8ad..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
-       io.c.
-
-       Local I/O routines for ksymoops.
-
-       Copyright Keith Owens <kaos@ocs.com.au>.
-       Released under the GNU Public Licence, Version 2.
-
-       Tue Nov  3 02:31:01 EST 1998
-       Version 0.6
-       fwrite_local is redundant, replaced by bfd.
-
-       Wed Oct 28 13:47:23 EST 1998
-       Version 0.4
-       Split into separate sources.
-
- */
-
-#include "ksymoops.h"
-#include <errno.h>
-#include <malloc.h>
-#include <string.h>
-#include <sys/stat.h>
-
-int regular_file(const char *file, const char *msg)
-{
-       struct stat statbuf;
-       if (stat(file, &statbuf)) {
-               fprintf(stderr, "%s: %s stat %s failed",
-                       prefix, msg, file);
-               perror(" ");
-               ++errors;
-               return 0;
-       }
-
-       if (!S_ISREG(statbuf.st_mode)) {
-               fprintf(stderr,
-                       "%s: %s %s is not a regular file, ignored\n",
-                       prefix, msg, file);
-               ++errors;
-               return 0;
-       }
-       return 1;
-}
-
-FILE *fopen_local(const char *file, const char *mode, const char *msg)
-{
-       FILE *f;
-       if (!(f = fopen(file, mode))) {
-               fprintf(stderr, "%s: %s fopen '%s' failed",
-                       prefix, msg, file);
-               perror(" ");
-               ++errors;
-       }
-       return f;
-}
-
-void fclose_local(FILE *f, const char *msg)
-{
-       int i;
-       if ((i = fclose(f))) {
-               fprintf(stderr, "%s: %s fclose failed %d", prefix, msg, i);
-               perror(" ");
-               ++errors;
-       }
-}
-
-/* Read a line, increasing the size of the line as necessary until \n is read */
-#define INCREMENT 10   /* arbitrary */
-char *fgets_local(char **line, int *size, FILE *f, const char *msg)
-{
-       char *l, *p, *r;
-       int longline = 1;
-
-       if (!*line) {
-               *size = INCREMENT;
-               *line = malloc(*size);
-               if (!*line)
-                       malloc_error("fgets_local alloc line");
-       }
-
-       l = *line;
-       while (longline) {
-               r = fgets(l, *size-(l-*line), f);
-               if (!r) {
-                       if (ferror(f)) {
-                               fprintf(stderr,
-                                       "%s: %s fgets failed", prefix, msg);
-                               perror(" ");
-                               ++errors;
-                       }
-                       if (l != *line)
-                               return(*line);
-                       else
-                               return(r);
-               }
-               if (!(p = strchr(*line, '\n'))) {
-                       *size += INCREMENT;
-                       *line = realloc(*line, *size);
-                       if (!*line)
-                               malloc_error("fgets_local realloc line");
-                       l = *line+*size-INCREMENT-1;
-               }
-               else {
-                       *p = '\0';
-                       longline = 0;
-               }
-       }
-
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s line '%s'\n", msg, *line);
-       return(*line);
-}
-
-FILE *popen_local(const char *cmd, const char *msg)
-{
-       FILE *f;
-       if (!(f = popen(cmd, "r"))) {
-               fprintf(stderr, "%s: %s popen '%s' failed",
-                       prefix, msg, cmd);
-               perror(" ");
-               ++errors;
-       }
-       return f;
-}
-
-void pclose_local(FILE *f, const char *msg)
-{
-       int i;
-       errno = 0;
-       if ((i = pclose(f))) {
-               fprintf(stderr, "%s: %s pclose failed 0x%x", prefix, msg, i);
-               if (errno)
-                       perror(" ");
-               else
-                       fprintf(stderr, "\n");
-               ++errors;
-       }
-}
diff --git a/scripts/ksymoops/ksymoops.c b/scripts/ksymoops/ksymoops.c
deleted file mode 100644 (file)
index 0cd6579..0000000
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
-       ksymoops.c.
-
-       Read a kernel Oops file and make the best stab at converting the code to
-       instructions and mapping stack values to kernel symbols.
-
-       Copyright Keith Owens <kaos@ocs.com.au>.
-       Released under the GNU Public Licence, Version 2.
-*/
-
-#define VERSION "0.6e"
-
-/*
-
-       Tue Jan  5 19:26:02 EST 1999
-       Version 0.6e
-       Added to kernel.
-
-       Mon Jan  4 09:48:13 EST 1999
-       Version 0.6d
-       Add ARM support.
-
-       Thu Nov 26 16:37:46 EST 1998
-       Version 0.6c
-       Typo in oops_code.
-       Add -c option.
-       Add -1 option.
-       Report if options were specified or defaulted.
-
-       Fri Nov  6 10:38:42 EST 1998
-       Version 0.6b
-       Remove false warnings when comparing ksyms and lsmod.
-
-       Tue Nov  3 23:33:04 EST 1998
-       Version 0.6a
-       Performance inprovements.
-
-       Tue Nov  3 02:31:01 EST 1998
-       Version 0.6
-       Read lsmod (/proc/modules).
-       Ignore addresses 0-4095 when mapping address to symbol.
-       Discard default objects if -o specified.
-       Oops file must be regular.
-       Add "invalid operand" to Oops_print.
-       Move "Using_Version" copy to map.c.
-       Add Makefile defaults for vmlinux, ksyms, objects, System.map, lsmod.
-       Minor adjustment to re for ppc.
-       Minor adjustment to re for objdump lines with <_EIP+xxx>.
-       Convert from a.out to bfd, using same format as ksymoops.
-       Added MIPS.
-       PPC handling based on patches by "Ryan Nielsen" <ran@krazynet.com>
-
-       Wed Oct 28 23:14:55 EST 1998
-       Version 0.5
-       No longer read vmlinux by default, it only duplicates System.map.
-
-       Wed Oct 28 13:47:38 EST 1998
-       Version 0.4
-       Split into separate sources.
-
-       Mon Oct 26 00:01:47 EST 1998
-       Version 0.3c
-       Add alpha (arm) processing.
-
-       Mon Oct 26 00:01:47 EST 1998
-       Version 0.3b
-       Add sparc processing.
-       Handle kernel symbol versions.
-
-       Fri Oct 23 13:11:20 EST 1998
-       Version 0.3
-       Add -follow to find command for people who use symlinks to modules.
-       Add Version_ checking.
-
-       Thu Oct 22 22:28:30 EST 1998
-       Version 0.2.
-       Generalise text prefix handling.
-       Handle messages on Code: line.
-       Format addresses with leading zeroes.
-       Minor bug fixes.
-
-       Wed Oct 21 23:28:48 EST 1998
-       Version 0.1.  Rewrite from scratch in C.
-
-       CREDITS.
-       Oops disassembly based on ksymoops.cc,
-         Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
-       m68k code based on ksymoops.cc changes by
-         Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- */
-
-#include "ksymoops.h"
-#include <ctype.h>
-#include <errno.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/utsname.h>
-
-char *prefix;
-char *path_nm = "/usr/bin/nm";                 /* env KSYMOOPS_NM */
-char *path_find = "/usr/bin/find";             /* env KSYMOOPS_FIND */
-char *path_objdump = "/usr/bin/objdump";       /* env KSYMOOPS_OBJDUMP */
-int debug = 0;
-int errors = 0;
-int warnings = 0;
-
-SYMBOL_SET  ss_vmlinux;
-SYMBOL_SET  ss_ksyms_base;
-SYMBOL_SET *ss_ksyms_module;
-int         ss_ksyms_modules;
-SYMBOL_SET  ss_lsmod;
-SYMBOL_SET *ss_object;
-int         ss_objects;
-SYMBOL_SET  ss_system_map;
-
-SYMBOL_SET  ss_merged;   /* merged map with info from all sources */
-SYMBOL_SET  ss_Version;  /* Version_ numbers where available */
-
-/* Regular expression stuff */
-
-regex_t     re_nm;
-regmatch_t *re_nm_pmatch;
-regex_t     re_bracketed_address;
-regmatch_t *re_bracketed_address_pmatch;
-regex_t     re_unbracketed_address;
-regmatch_t *re_unbracketed_address_pmatch;
-
-static void usage(void)
-{
-       fprintf(stderr, "Version " VERSION "\n");
-       fprintf(stderr, "usage: %s\n", prefix);
-       fprintf(stderr,
-               "\t\t[-v vmlinux]\tWhere to read vmlinux\n"
-               "\t\t[-V]\t\tNo vmlinux is available\n"
-               "\t\t[-o object_dir]\tDirectory containing modules\n"
-               "\t\t[-O]\t\tNo modules is available\n"
-               "\t\t[-k ksyms]\tWhere to read ksyms\n"
-               "\t\t[-K]\t\tNo ksyms is available\n"
-               "\t\t[-l lsmod]\tWhere to read lsmod\n"
-               "\t\t[-L]\t\tNo lsmod is available\n"
-               "\t\t[-m system.map]\tWhere to read System.map\n"
-               "\t\t[-M]\t\tNo System.map is available\n"
-               "\t\t[-s save.map]\tSave consolidated map\n"
-               "\t\t[-d]\t\tIncrease debug level by 1\n"
-               "\t\t[-h]\t\tPrint help text\n"
-               "\t\t[-c code_bytes]\tHow many bytes in each unit of code\n"
-               "\t\t[-1]\t\tOne shot toggle (exit after first Oops)\n"
-               "\t\t<Oops.file\tOops report to decode\n"
-               "\n"
-               "\t\tAll flags can occur more than once.  With the exception "
-                       "of -o\n"
-               "\t\tand -d which are cumulative, the last occurrence of each "
-                       "flag is\n"
-               "\t\tused.  Note that \"-v my.vmlinux -V\" will be taken as "
-                       "\"No vmlinux\n"
-               "\t\tavailable\" but \"-V -v my.vmlinux\" will read "
-                       "my.vmlinux.  You\n"
-               "\t\twill be warned about such combinations.\n"
-               "\n"
-               "\t\tEach occurrence of -d increases the debug level.\n"
-               "\n"
-               "\t\tEach -o flag can refer to a directory or to a single "
-                       "object\n"
-               "\t\tfile.  If a directory is specified then all *.o files in "
-                       "that\n"
-               "\t\tdirectory and its subdirectories are assumed to be "
-                       "modules.\n"
-               "\n"
-               "\t\tIf any of the vmlinux, object_dir, ksyms or system.map "
-               "options\n"
-               "\t\tcontain the string *r (*m, *n, *s) then it is replaced "
-               "at run\n"
-               "\t\ttime by the current value of `uname -r` (-m, -n, -s).\n"
-               "\n"
-               "\t\tThe defaults can be changed in the Makefile, current "
-               "defaults\n"
-               "\t\tare\n\n"
-               "\t\t\t"
-#ifdef DEF_VMLINUX
-               "-v " DEF_LINUX
-#else
-               "-V"
-#endif
-               "\n"
-               "\t\t\t"
-#ifdef DEF_OBJECTS
-               "-o " DEF_OBJECTS
-#else
-               "-O"
-#endif
-               "\n"
-               "\t\t\t"
-#ifdef DEF_KSYMS
-               "-k " DEF_KSYMS
-#else
-               "-K"
-#endif
-               "\n"
-               "\t\t\t"
-#ifdef DEF_LSMOD
-               "-l " DEF_LSMOD
-#else
-               "-L"
-#endif
-               "\n"
-               "\t\t\t"
-#ifdef DEF_MAP
-               "-m " DEF_MAP
-#else
-               "-M"
-#endif
-               "\n"
-               "\t\t\t-c %d\n" /* DEF_CODE_BYTES */
-               "\t\t\tOops report is read from stdin\n"
-               "\n",
-       DEF_CODE_BYTES
-              );
-}
-
-/* Check if possibly conflicting options were specified */
-static void multi_opt(int specl, int specu, char type, const char *using)
-{
-       if (specl && specu) {
-               fprintf(stderr,
-                       "Warning - you specified both -%c and -%c.  Using '",
-                       type, toupper(type));
-               ++warnings;
-               if (using) {
-                       fprintf(stderr, "-%c %s", type, using);
-                       if (type == 'o')
-                               fprintf(stderr, " ...");
-                       fprintf(stderr, "'\n");
-               }
-               else
-                       fprintf(stderr, "-%c'\n", toupper(type));
-       }
-       else if (specl > 1 && type != 'o') {
-               fprintf(stderr,
-                       "Warning - you specified -%c more than once.  "
-                       "Using '-%c %s'\n",
-                       type, type, using);
-               ++warnings;
-       }
-       else if (specu > 1) {
-               fprintf(stderr,
-                       "Warning - you specified -%c more than once.  "
-                       "Second and subsequent '-%c' ignored\n",
-                       toupper(type), toupper(type));
-               ++warnings;
-       }
-}
-
-/* If a name contains *r (*m, *n, *s), replace with the current value of
- * `uname -r` (-m, -n, -s).  Actually uses uname system call rather than the
- * uname command but the result is the same.
- */
-static void convert_uname(char **name)
-{
-       char *p, *newname, *oldname, *replacement;
-       unsigned len;
-       int free_oldname = 0;
-       static char procname[] = "convert_uname";
-
-       if (!*name)
-               return;
-
-       while ((p = strchr(*name, '*'))) {
-               struct utsname buf;
-               int i = uname(&buf);
-               if (debug)
-                       fprintf(stderr, "DEBUG: %s %s in\n", procname, *name);
-               if (i) {
-                       fprintf(stderr,
-                               "%s: uname failed, %s will not be processed\n",
-                               prefix, *name);
-                       perror(prefix);
-                       ++errors;
-                       return;
-               }
-               switch (*(p+1)) {
-               case 'r':
-                       replacement = buf.release;
-                       break;
-               case 'm':
-                       replacement = buf.machine;
-                       break;
-               case 'n':
-                       replacement = buf.nodename;
-                       break;
-               case 's':
-                       replacement = buf.sysname;
-                       break;
-               default:
-                       fprintf(stderr,
-                               "%s: invalid replacement character '*%c' "
-                               "in %s\n",
-                               prefix, *(p+1), *name);
-                       ++errors;
-                       return;
-               }
-               len = strlen(*name)-2+strlen(replacement)+1;
-               if (!(newname = malloc(len)))
-                       malloc_error(procname);
-               strncpy(newname, *name, (p-*name));
-               strcpy(newname+(p-*name), replacement);
-               strcpy(newname+(p-*name)+strlen(replacement), p+2);
-               p = newname+(p-*name)+strlen(replacement);      /* no rescan */
-               oldname = *name;
-               *name = newname;
-               if (free_oldname)
-                       free(oldname);
-               free_oldname = 1;
-               if (debug)
-                       fprintf(stderr, "DEBUG: %s %s out\n", procname, *name);
-       }
-       return;
-}
-
-/* Report if the option was specified or defaulted */
-static void spec_or_default(int spec, int *some_spec) {
-       if (spec) {
-               printf(" (specified)\n");
-               if (some_spec)
-                       *some_spec = 1;
-       }
-       else
-               printf(" (default)\n");
-}
-
-/* Parse the options.  Verbose but what's new with getopt? */
-static void parse(int argc,
-                 char **argv,
-                 char **vmlinux,
-                 char ***object,
-                 int *objects,
-                 char **ksyms,
-                 char **lsmod,
-                 char **system_map,
-                 char **save_system_map,
-                 char ***filename,
-                 int *filecount,
-                 int *spec_h,
-                 int *code_bytes,
-                 int *one_shot
-                )
-{
-       int spec_v = 0, spec_V = 0;
-       int spec_o = 0, spec_O = 0;
-       int spec_k = 0, spec_K = 0;
-       int spec_l = 0, spec_L = 0;
-       int spec_m = 0, spec_M = 0;
-       int spec_s = 0;
-       int spec_c = 0;
-
-       int c, i, some_spec = 0;
-       char *p;
-
-       while ((c = getopt(argc, argv, "v:Vo:Ok:Kl:Lm:Ms:dhc:1")) != EOF) {
-               if (debug && c != 'd')
-                       fprintf(stderr, "DEBUG: getopt '%c' '%s'\n", c, optarg);
-               switch(c) {
-               case 'v':
-                       *vmlinux = optarg;
-                       ++spec_v;
-                       break;
-               case 'V':
-                       *vmlinux = NULL;
-                       ++spec_V;
-                       break;
-               case 'o':
-                       if (!spec_o) {
-                               /* First -o, discard default value(s) */
-                               for (i = 0; i < *objects; ++i)
-                                       free((*object)[i]);
-                               free(*object);
-                               *object = NULL;
-                               *objects = 0;
-                       }
-                       *object = realloc(*object,
-                               ((*objects)+1)*sizeof(**object));
-                       if (!*object)
-                               malloc_error("object");
-                       if (!(p = strdup(optarg)))
-                               malloc_error("strdup -o");
-                       else {
-                               (*object)[(*objects)++] = p;
-                               ++spec_o;
-                       }
-                       break;
-               case 'O':
-                       ++spec_O;
-                       for (i = 0; i < *objects; ++i)
-                               free((*object)[i]);
-                       free(*object);
-                       *object = NULL;
-                       *objects = 0;
-                       break;
-               case 'k':
-                       *ksyms = optarg;
-                       ++spec_k;
-                       break;
-               case 'K':
-                       *ksyms = NULL;
-                       ++spec_K;
-                       break;
-               case 'l':
-                       *lsmod = optarg;
-                       ++spec_l;
-                       break;
-               case 'L':
-                       *lsmod = NULL;
-                       ++spec_L;
-                       break;
-               case 'm':
-                       *system_map = optarg;
-                       ++spec_m;
-                       break;
-               case 'M':
-                       *system_map = NULL;
-                       ++spec_M;
-                       break;
-               case 's':
-                       *save_system_map = optarg;
-                       ++spec_s;
-                       break;
-               case 'd':
-                       ++debug;
-                       break;
-               case 'h':
-                       usage();
-                       ++*spec_h;
-                       break;
-               case 'c':
-                       ++spec_c;
-                       errno = 0;
-                       *code_bytes = strtoul(optarg, &p, 10);
-                       /* Oops_code_values assumes that code_bytes is a
-                        * multiple of 2.
-                        */
-                       if (!*optarg || *p || errno ||
-                               (*code_bytes != 1 &&
-                                *code_bytes != 2 &&
-                                *code_bytes != 4 &&
-                                *code_bytes != 8)) {
-                               fprintf(stderr,
-                                       "%s Invalid value for -c '%s'\n",
-                                       prefix, optarg);
-                               ++errors;
-                               if (errno)
-                                       perror(" ");
-                               *code_bytes = DEF_CODE_BYTES;
-                       }
-                       break;
-               case '1':
-                       *one_shot = !*one_shot;
-                       break;
-               case '?':
-                       usage();
-                       exit(2);
-               }
-       }
-
-       *filecount = argc - optind;
-       *filename = argv + optind;
-
-       /* Expand any requests for the current uname values */
-       convert_uname(vmlinux);
-       if (*objects) {
-               for (i = 0; i < *objects; ++i)
-                       convert_uname(*object+i);
-       }
-       convert_uname(ksyms);
-       convert_uname(lsmod);
-       convert_uname(system_map);
-
-       /* Check for multiple options specified */
-       multi_opt(spec_v, spec_V, 'v', *vmlinux);
-       multi_opt(spec_o, spec_O, 'o', *object ? **object : NULL);
-       multi_opt(spec_k, spec_K, 'k', *ksyms);
-       multi_opt(spec_l, spec_L, 'l', *lsmod);
-       multi_opt(spec_m, spec_M, 'm', *system_map);
-
-       printf("Options used:");
-       if (*vmlinux)
-               printf(" -v %s", *vmlinux);
-       else
-               printf(" -V");
-       spec_or_default(spec_v || spec_V, &some_spec);
-       
-       printf("             ");
-       if (*objects) {
-               for (i = 0; i < *objects; ++i)
-                       printf(" -o %s", (*object)[i]);
-       }
-       else
-               printf(" -O");
-       spec_or_default(spec_o || spec_O, &some_spec);
-
-       printf("             ");
-       if (*ksyms)
-               printf(" -k %s", *ksyms);
-       else
-               printf(" -K");
-       spec_or_default(spec_k || spec_K, &some_spec);
-
-       printf("             ");
-       if (*lsmod)
-               printf(" -l %s", *lsmod);
-       else
-               printf(" -L");
-       spec_or_default(spec_l || spec_L, &some_spec);
-
-       printf("             ");
-       if (*system_map)
-               printf(" -m %s", *system_map);
-       else
-               printf(" -M");
-       spec_or_default(spec_m || spec_M, &some_spec);
-
-       printf("             ");
-       printf(" -c %d", *code_bytes);
-       spec_or_default(spec_c, NULL);
-
-       if (*one_shot) {
-               printf("             ");
-               printf(" -1");
-       }
-
-       printf("\n");
-
-       if (!some_spec) {
-               printf(
-"You did not tell me where to find symbol information.  I will assume\n"
-"that the log matches the kernel and modules that are running right now\n"
-"and I'll use the default options above for symbol resolution.\n"
-"If the current kernel and/or modules do not match the log, you can get\n"
-"more accurate output by telling me the kernel version and where to find\n"
-"map, modules, ksyms etc.  ksymoops -h explains the options.\n"
-                       "\n");
-               ++warnings;
-       }
-}
-
-/* Read environment variables */
-static void read_env(const char *external, char **internal)
-{
-       char *p;
-       if ((p = getenv(external))) {
-               *internal = p;
-               if (debug)
-                       fprintf(stderr,
-                               "DEBUG: env override %s=%s\n",
-                               external, *internal);
-       }
-       else {
-               if (debug)
-                       fprintf(stderr,
-                               "DEBUG: env default %s=%s\n",
-                               external, *internal);
-       }
-}
-
-
-int main(int argc, char **argv)
-{
-       char *vmlinux = NULL;
-       char **object = NULL;
-       int objects = 0;
-       char *ksyms = NULL;
-       char *lsmod = NULL;
-       char *system_map = NULL;
-       char *save_system_map = NULL;
-       char **filename;
-       int filecount = 0;
-       int spec_h = 0;         /* -h was specified */
-       int code_bytes = DEF_CODE_BYTES;
-       int one_shot = 0;
-       int i, ret;
-
-       prefix = *argv;
-       setvbuf(stdout, NULL, _IONBF, 0);
-
-#ifdef DEF_VMLINUX
-       vmlinux = DEF_LINUX;
-#endif
-#ifdef DEF_OBJECTS
-       {
-               char *p;
-               object = realloc(object, (objects+1)*sizeof(*object));
-               if (!object)
-                       malloc_error("DEF_OBJECTS");
-               if (!(p = strdup(DEF_OBJECTS)))
-                       malloc_error("DEF_OBJECTS");
-               else
-                       object[objects++] = p;
-       }
-#endif
-#ifdef DEF_KSYMS
-       ksyms = DEF_KSYMS;
-#endif
-#ifdef DEF_LSMOD
-       lsmod = DEF_LSMOD;
-#endif
-#ifdef DEF_MAP
-       system_map = DEF_MAP;
-#endif
-
-       parse(argc,
-             argv,
-             &vmlinux,
-             &object,
-             &objects,
-             &ksyms,
-             &lsmod,
-             &system_map,
-             &save_system_map,
-             &filename,
-             &filecount,
-             &spec_h,
-             &code_bytes,
-             &one_shot
-            );
-
-       if (spec_h && filecount == 0)
-               return(0);      /* just the help text */
-
-       if (errors)
-               return(1);
-
-       if (debug)
-               fprintf(stderr, "DEBUG: level %d\n", debug);
-
-       read_env("KSYMOOPS_NM", &path_nm);
-       read_env("KSYMOOPS_FIND", &path_find);
-       read_env("KSYMOOPS_OBJDUMP", &path_objdump);
-
-       re_compile_common();
-       ss_init_common();
-
-       read_vmlinux(vmlinux);
-       read_ksyms(ksyms);
-       /* No point in reading modules unless ksyms shows modules loaded */
-       if (ss_ksyms_modules) {
-               expand_objects(object, objects);
-               for (i = 0; i < ss_objects; ++i)
-                       read_object(ss_object[i].source, i);
-       }
-       else if (objects)
-               printf("No modules in ksyms, skipping objects\n");
-       /* No point in reading lsmod without ksyms */
-       if (ss_ksyms_modules || ss_ksyms_base.used)
-               read_lsmod(lsmod);
-       else if (lsmod)
-               printf("No ksyms, skipping lsmod\n");
-       read_system_map(system_map);
-       merge_maps(save_system_map);
-
-       /* After all that work, it is finally time to read the Oops report */
-       ret = Oops_read(filecount, filename, code_bytes, one_shot);
-
-       if (warnings || errors) {
-               printf("\n");
-               if (warnings)
-                       printf("%d warning%s ",
-                              warnings, warnings == 1 ? "" : "s");
-               if (warnings && errors)
-                       printf("and ");
-               if (errors)
-                       printf("%d error%s ", errors, errors == 1 ? "" : "s");
-               printf("issued.  Results may not be reliable.\n");
-               if (!ret)
-                       return(1);
-       }
-
-       return(ret);
-}
diff --git a/scripts/ksymoops/ksymoops.h b/scripts/ksymoops/ksymoops.h
deleted file mode 100644 (file)
index fb3e99d..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
-       ksymoops.h.
-
-       Copyright Keith Owens <kaos@ocs.com.au>.
-       Released under the GNU Public Licence, Version 2.
-
-       Tue Nov  3 02:31:01 EST 1998
-       Version 0.6
-       Read lsmod (/proc/modules).
-       Convert from a.out to bfd, using same format as ksymoops.
-       PPC trace addresses are not bracketed, add new re.
-
-       Wed Oct 28 13:47:23 EST 1998
-       Version 0.4
-       Split into separate sources.
-*/
-
-#include <sys/types.h>
-#include <regex.h>
-#include <stdio.h>
-
-
-/* Pity this is not externalised, see binfmt_elf.c */
-#define elf_addr_t unsigned long
-
-extern char *prefix;
-extern char *path_nm;          /* env KSYMOOPS_NM */
-extern char *path_find;                /* env KSYMOOPS_FIND */
-extern char *path_objdump;     /* env KSYMOOPS_OBJDUMP */
-extern int debug;
-extern int errors;
-extern int warnings;
-
-typedef struct symbol SYMBOL;
-
-struct symbol {
-       char *name;             /* name of symbol */
-       char type;              /* type of symbol from nm/System.map */
-       char keep;              /* keep this symbol in merged map? */
-       elf_addr_t address;     /* address in kernel */
-};
-
-/* Header for symbols from one particular source */
-
-typedef struct symbol_set SYMBOL_SET;
-
-struct symbol_set {
-       char *source;                   /* where the symbols came from */
-       int used;                       /* number of symbols used */
-       int alloc;                      /* number of symbols allocated */
-       SYMBOL *symbol;                 /* dynamic array of symbols */
-       SYMBOL_SET *related;            /* any related symbol set */
-};
-
-extern SYMBOL_SET  ss_vmlinux;
-extern SYMBOL_SET  ss_ksyms_base;
-extern SYMBOL_SET *ss_ksyms_module;
-extern int         ss_ksyms_modules;
-extern SYMBOL_SET  ss_lsmod;
-extern SYMBOL_SET *ss_object;
-extern int         ss_objects;
-extern SYMBOL_SET  ss_system_map;
-
-extern SYMBOL_SET  ss_merged;  /* merged map with info from all sources */
-extern SYMBOL_SET  ss_Version; /* Version_ numbers where available */
-
-/* Regular expression stuff */
-
-extern regex_t     re_nm;
-extern regmatch_t *re_nm_pmatch;
-extern regex_t     re_bracketed_address;
-extern regmatch_t *re_bracketed_address_pmatch;
-extern regex_t     re_unbracketed_address;
-extern regmatch_t *re_unbracketed_address_pmatch;
-
-/* Bracketed address: optional '[', required '<', at least 4 hex characters,
- * required '>', optional ']', optional white space.
- */
-#define BRACKETED_ADDRESS      "\\[*<([0-9a-fA-F]{4,})>\\]*[ \t]*"
-
-#define UNBRACKETED_ADDRESS    "([0-9a-fA-F]{4,})[ \t]*"
-
-/* io.c */
-extern int regular_file(const char *file, const char *msg);
-extern FILE *fopen_local(const char *file, const char *mode, const char *msg);
-extern void fclose_local(FILE *f, const char *msg);
-extern char *fgets_local(char **line, int *size, FILE *f, const char *msg);
-extern int fwrite_local(void const *ptr, size_t size, size_t nmemb,
-                       FILE *stream, const char *msg);
-extern FILE *popen_local(const char *cmd, const char *msg);
-extern void pclose_local(FILE *f, const char *msg);
-
-/* ksyms.c */
-extern void read_ksyms(const char *ksyms);
-extern void map_ksyms_to_modules(void);
-extern void read_lsmod(const char *lsmod);
-extern void compare_ksyms_lsmod(void);
-
-/* misc.c */
-extern void malloc_error(const char *msg);
-extern const char *format_address(elf_addr_t address);
-extern char *find_fullpath(const char *program);
-
-/* map.c */
-extern void read_system_map(const char *system_map);
-extern void merge_maps(const char *save_system_map);
-extern void compare_maps(const SYMBOL_SET *ss1, const SYMBOL_SET *ss2,
-                        int precedence);
-
-
-/* object.c */
-extern SYMBOL_SET *adjust_object_offsets(SYMBOL_SET *ss);
-extern void read_vmlinux(const char *vmlinux);
-extern void expand_objects(char * const *object, int objects);
-extern void read_object(const char *object, int i);
-
-/* oops.c */
-extern int Oops_read(int filecount, char * const *filename, int code_bytes,
-                    int one_shot);
-
-/* re.c */
-extern void re_compile(regex_t *preg, const char *regex, int cflags,
-                      regmatch_t **pmatch);
-extern void re_compile_common(void);
-extern void re_strings(regex_t *preg, const char *text, regmatch_t *pmatch,
-                      char ***string);
-extern void re_strings_free(const regex_t *preg, char ***string);
-extern void re_string_check(int need, int available, const char *msg);
-
-/* symbol.c */
-extern void ss_init(SYMBOL_SET *ss, const char *msg);
-extern void ss_free(SYMBOL_SET *ss);
-extern void ss_init_common(void);
-extern SYMBOL *find_symbol_name(const SYMBOL_SET *ss, const char *symbol,
-                               int *start);
-extern void add_symbol_n(SYMBOL_SET *ss, const elf_addr_t address,
-                        const char type, const char keep, const char *symbol);
-extern void add_symbol(SYMBOL_SET *ss, const char *address, const char type,
-                      const char keep, const char *symbol);
-extern char *map_address(const SYMBOL_SET *ss, const elf_addr_t address);
-extern void ss_sort_atn(SYMBOL_SET *ss);
-extern void ss_sort_na(SYMBOL_SET *ss);
-extern SYMBOL_SET *ss_copy(const SYMBOL_SET *ss);
-extern void add_Version(const char *version, const char *source);
-extern void extract_Version(SYMBOL_SET *ss);
-extern void compare_Version(void);
diff --git a/scripts/ksymoops/ksyms.c b/scripts/ksymoops/ksyms.c
deleted file mode 100644 (file)
index 608254a..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
-       ksyms.c.
-
-       Process ksyms for ksymoops.
-
-       Copyright Keith Owens <kaos@ocs.com.au>.
-       Released under the GNU Public Licence, Version 2.
-
-       Fri Nov  6 10:38:42 EST 1998
-       Version 0.6b
-       Remove false warnings when comparing ksyms and lsmod.
-
-       Tue Nov  3 02:31:01 EST 1998
-       Version 0.6
-       Read lsmod (/proc/modules).
-       Move "Using_Version" copy to map.c.
-
-       Wed Oct 28 13:47:23 EST 1998
-       Version 0.4
-       Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-#include <string.h>
-
-/* Scan one line from ksyms.  Split lines into the base symbols and the module
- * symbols.  Separate ss for base and each module.
- */
-static void scan_ksyms_line(const char *line)
-{
-       int i;
-       char **string = NULL;
-       SYMBOL_SET *ssp;
-       static char *prev_module = NULL;
-       static regex_t     re_ksyms;
-       static regmatch_t *re_ksyms_pmatch;
-       static char const procname[] = "scan_ksyms_line";
-
-       /* ksyms: address, symbol, optional module */
-       re_compile(&re_ksyms,
-               "^([0-9a-fA-F]{4,}) +([^ \t]+)([ \t]+\\[([^ ]+)\\])?$",
-               REG_NEWLINE|REG_EXTENDED,
-               &re_ksyms_pmatch);
-
-       i = regexec(&re_ksyms, line,
-                   re_ksyms.re_nsub+1, re_ksyms_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-       if (i)
-               return;
-
-       /* string [1] - address, [2] - symbol, [3] - white space+module,
-        * [4] - module.
-        */
-       re_strings(&re_ksyms, line, re_ksyms_pmatch, &string);
-       if (string[4]) {
-               if (!prev_module || strcmp(prev_module, string[4])) {
-                       /* start of a new module in ksyms */
-                       ++ss_ksyms_modules;
-                       ss_ksyms_module = realloc(ss_ksyms_module,
-                               ss_ksyms_modules*sizeof(*ss_ksyms_module));
-                       if (!ss_ksyms_module)
-                               malloc_error("realloc ss_ksyms_module");
-                       ssp = ss_ksyms_module+ss_ksyms_modules-1;
-                       ss_init(ssp, string[4]);
-                       prev_module = strdup(string[4]);
-                       if (!prev_module)
-                               malloc_error("strdup prev_module");
-               }
-               ssp = ss_ksyms_module+ss_ksyms_modules-1;
-       }
-       else
-               ssp = &ss_ksyms_base;
-       add_symbol(ssp, string[1], ' ', 1, string[2]);
-       re_strings_free(&re_ksyms, &string);
-}
-
-/* Read the symbols from ksyms.  */
-void read_ksyms(const char *ksyms)
-{
-       FILE *f;
-       char *line = NULL;
-       int i, size;
-       static char const procname[] = "read_ksyms";
-
-       if (!ksyms)
-               return;
-       ss_init(&ss_ksyms_base, "ksyms_base");
-       if (debug)
-               fprintf(stderr, "DEBUG: %s %s\n", procname, ksyms);
-
-       if (!regular_file(ksyms, procname))
-               return;
-
-       if (!(f = fopen_local(ksyms, "r", procname)))
-               return;
-
-       while (fgets_local(&line, &size, f, procname))
-               scan_ksyms_line(line);
-
-       fclose_local(f, procname);
-       free(line);
-
-       for (i = 0; i < ss_ksyms_modules; ++i) {
-               ss_sort_na(ss_ksyms_module+i);
-               extract_Version(ss_ksyms_module+i);
-       }
-       if (ss_ksyms_base.used) {
-               ss_sort_na(&ss_ksyms_base);
-               extract_Version(&ss_ksyms_base);
-       }
-       else {
-               fprintf(stderr,
-                       "Warning, no kernel symbols in ksyms, is %s a valid "
-                       "ksyms file?\n",
-                       ksyms);
-               ++warnings;
-       }
-
-       if (debug > 1) {
-               for (i = 0; i < ss_ksyms_modules; ++i) {
-                       fprintf(stderr,
-                               "DEBUG: %s %s used %d out of %d entries\n",
-                               procname,
-                               ss_ksyms_module[i].source,
-                               ss_ksyms_module[i].used,
-                               ss_ksyms_module[i].alloc);
-               }
-               fprintf(stderr,
-                       "DEBUG: %s %s used %d out of %d entries\n",
-                       procname, ss_ksyms_base.source, ss_ksyms_base.used,
-                       ss_ksyms_base.alloc);
-       }
-}
-
-/* Map each ksyms module entry to the corresponding object entry.  Tricky,
- * see the comments in the docs about needing a unique symbol in each
- * module.
- */
-static void map_ksym_to_module(SYMBOL_SET *ss)
-{
-       int i, j, matches;
-       char *name = NULL;
-
-       for (i = 0; i < ss->used; ++i) {
-               matches = 0;
-               for (j = 0; j < ss_objects; ++j) {
-                       name = (ss->symbol)[i].name;
-                       if (find_symbol_name(ss_object+j, name, NULL)) {
-                               ++matches;
-                               ss->related = ss_object+j;
-                       }
-               }
-               if (matches == 1)
-                       break;          /* unique symbol over all objects */
-               ss->related = NULL;     /* keep looking */
-       }
-       if (!(ss->related)) {
-               fprintf(stderr,
-                       "Warning: cannot match loaded module %s to any "
-                       "module object.  Trace may not be reliable.\n",
-                       ss->source);
-               ++warnings;
-       }
-       else if (debug)
-               fprintf(stderr,
-                       "DEBUG: ksyms %s matches to %s based on unique "
-                       "symbol %s\n",
-                       ss->source, ss->related->source, name);
-}
-
-/* Map all ksyms module entries to their corresponding objects */
-void map_ksyms_to_modules(void)
-{
-       int i;
-       SYMBOL_SET *ss, *ssc;
-
-       for (i = 0; i < ss_ksyms_modules; ++i) {
-               ss = ss_ksyms_module+i;
-               map_ksym_to_module(ss);
-               if (ss->related) {
-                       ssc = adjust_object_offsets(ss);
-                       compare_maps(ss, ssc, 1);
-               }
-       }
-}
-
-/* Read the modules from lsmod.  */
-void read_lsmod(const char *lsmod)
-{
-       FILE *f;
-       char *line = NULL;
-       int i, size;
-       char **string = NULL;
-       static regex_t     re_lsmod;
-       static regmatch_t *re_lsmod_pmatch;
-       static char const procname[] = "read_lsmod";
-
-       if (!lsmod)
-               return;
-       ss_init(&ss_lsmod, "lsmod");
-       if (debug)
-               fprintf(stderr, "DEBUG: %s %s\n", procname, lsmod);
-
-       if (!regular_file(lsmod, procname))
-               return;
-
-       if (!(f = fopen_local(lsmod, "r", procname)))
-               return;
-
-       /* lsmod: module, size, use count, optional used by */
-       re_compile(&re_lsmod,
-               "^"
-               "[ \t]*([^ \t]+)"                               /* 1 module */
-               "[ \t]*([^ \t]+)"                               /* 2 size */
-               "[ \t]*([^ \t]+)"                               /* 3 count */
-               "[ \t]*(.*)"                                    /* 4 used by */
-               "$",
-               REG_NEWLINE|REG_EXTENDED,
-               &re_lsmod_pmatch);
-
-       while (fgets_local(&line, &size, f, procname)) {
-               i = regexec(&re_lsmod, line,
-                           re_lsmod.re_nsub+1, re_lsmod_pmatch, 0);
-               if (debug > 3)
-                       fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-               if (i)
-                       continue;
-               re_strings(&re_lsmod, line, re_lsmod_pmatch, &string);
-               add_symbol(&ss_lsmod, string[2], ' ', 1, string[1]);
-       }
-
-       fclose_local(f, procname);
-       free(line);
-       re_strings_free(&re_lsmod, &string);
-       if (ss_lsmod.used)
-               ss_sort_na(&ss_lsmod);
-       else {
-               fprintf(stderr,
-                       "Warning, no symbols in lsmod, is %s a valid "
-                       "lsmod file?\n",
-                       lsmod);
-               ++warnings;
-       }
-
-       if (debug > 1)
-               fprintf(stderr,
-                       "DEBUG: %s %s used %d out of %d entries\n",
-                       procname, ss_lsmod.source, ss_lsmod.used,
-                       ss_lsmod.alloc);
-}
-
-/* Compare modules from ksyms against module list in lsmod and vice versa.
- * There is one ss_ for each ksyms module and a single ss_lsmod to cross
- * check.
- */
-void compare_ksyms_lsmod(void)
-{
-       int i, j;
-       SYMBOL_SET *ss;
-       SYMBOL *s;
-       static char const procname[] = "compare_ksyms_lsmod";
-
-       if (!(ss_lsmod.used && ss_ksyms_modules))
-               return;
-
-       s = ss_lsmod.symbol;
-       for (i = 0; i < ss_lsmod.used; ++i, ++s) {
-               for (j = 0; j < ss_ksyms_modules; ++j) {
-                       ss = ss_ksyms_module+j;
-                       if (strcmp(s->name, ss->source) == 0)
-                               break;
-               }
-               if (j >= ss_ksyms_modules) {
-                       fprintf(stderr,
-                               "Warning in %s, module %s is in lsmod but not "
-                               "in ksyms, probably no symbols exported\n",
-                               procname, s->name);
-                       ++warnings;
-               }
-       }
-
-       for (i = 0; i < ss_ksyms_modules; ++i) {
-               ss = ss_ksyms_module+i;
-               if (!find_symbol_name(&ss_lsmod, ss->source, NULL)) {
-                       fprintf(stderr,
-                               "Error in %s, module %s is in ksyms but not "
-                               "in lsmod\n",
-                               procname, ss->source);
-                       ++errors;
-               }
-       }
-}
diff --git a/scripts/ksymoops/map.c b/scripts/ksymoops/map.c
deleted file mode 100644 (file)
index 6f91e9d..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
-       map.c.
-
-       Read System.map for ksymoops, create merged System.map.
-
-       Copyright Keith Owens <kaos@ocs.com.au>.
-       Released under the GNU Public Licence, Version 2.
-
-       Tue Nov  3 02:31:01 EST 1998
-       Version 0.6
-       Remove addresses 0-4095 from merged map after writing new map.
-       Move "Using_Version" copy to map.c.
-
-       Wed Oct 28 13:47:23 EST 1998
-       Version 0.4
-       Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-
-/* Read the symbols from System.map */
-void read_system_map(const char *system_map)
-{
-       FILE *f;
-       char *line = NULL, **string = NULL;
-       int i, size = 0;
-       static char const procname[] = "read_system_map";
-
-       if (!system_map)
-               return;
-       ss_init(&ss_system_map, "System.map");
-       if (debug)
-               fprintf(stderr, "DEBUG: %s %s\n", procname, system_map);
-
-       if (!regular_file(system_map, procname))
-               return;
-
-       if (!(f = fopen_local(system_map, "r", procname)))
-               return;
-
-       while (fgets_local(&line, &size, f, procname)) {
-               i = regexec(&re_nm, line, re_nm.re_nsub+1, re_nm_pmatch, 0);
-               if (debug > 3)
-                       fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-               if (i == 0) {
-                       re_strings(&re_nm, line, re_nm_pmatch, &string);
-                       add_symbol(&ss_system_map, string[1], *string[2],
-                                  1, string[3]);
-               }
-       }
-
-       fclose_local(f, procname);
-       re_strings_free(&re_nm, &string);
-       free(line);
-       if (ss_system_map.used) {
-               ss_sort_na(&ss_system_map);
-               extract_Version(&ss_system_map);
-       }
-       else {
-               fprintf(stderr,
-                       "Warning, no kernel symbols in System.map, is %s a "
-                       "valid System.map file?\n",
-                       system_map);
-               ++warnings;
-       }
-
-       if (debug > 1)
-               fprintf(stderr,
-                       "DEBUG: %s %s used %d out of %d entries\n",
-                       procname,
-                       ss_system_map.source,
-                       ss_system_map.used,
-                       ss_system_map.alloc);
-}
-
-/* Compare two maps, all symbols in the first should appear in the second. */
-void compare_maps(const SYMBOL_SET *ss1, const SYMBOL_SET *ss2,
-                        int precedence)
-{
-       int i, start = 0;
-       SYMBOL *s1, *s2, **sdrop = precedence == 1 ? &s2 : &s1;
-       const SYMBOL_SET **ssdrop = precedence == 1 ? &ss2 : &ss1;
-
-       if (!(ss1->used && ss2->used))
-               return;
-
-       if (debug > 1)
-               fprintf(stderr,
-                       "DEBUG: compare_maps %s vs %s, %s takes precedence\n",
-                       ss1->source, ss2->source,
-                       precedence == 1 ? ss1->source : ss2->source);
-
-       for (i = 0; i < ss1->used; ++i) {
-               s1 = ss1->symbol+i;
-               if (!(s1->keep))
-                       continue;
-               s2 = find_symbol_name(ss2, s1->name, &start);
-               if (!s2) {
-                       /* Some types only appear in nm output, not in things
-                        * like System.map.  Silently ignore them.
-                        */
-                       if (s1->type == 'a' || s1->type == 't')
-                               continue;
-                       fprintf(stderr,
-                               "Warning: %s symbol %s not found in %s.  "
-                               "Ignoring %s entry\n",
-                               ss1->source, s1->name,
-                               ss2->source, (*ssdrop)->source);
-                       ++warnings;
-                       if (*sdrop)
-                               (*sdrop)->keep = 0;
-               }
-               else if (s1->address != s2->address) {
-                       /* Type C symbols cannot be resolved from nm to ksyms,
-                        * silently ignore them.
-                        */
-                       if (s1->type == 'C' || s2->type == 'C')
-                               continue;
-                       fprintf(stderr,
-                               "Warning: mismatch on symbol %s %c, "
-                               "%s says %lx, %s says %lx.  "
-                               "Ignoring %s entry\n",
-                               s1->name, s1->type, ss1->source, s1->address,
-                               ss2->source, s2->address, (*ssdrop)->source);
-                       ++warnings;
-                       if (*sdrop)
-                               (*sdrop)->keep = 0;
-               }
-               else
-                       ++start;        /* step to next entry in ss2 */
-       }
-}
-
-/* Append the second symbol set onto the first */
-static void append_map(SYMBOL_SET *ss1, const SYMBOL_SET *ss2)
-{
-       int i;
-       SYMBOL *s;
-
-       if (!ss2 || !ss2->used)
-               return;
-       if (debug > 1)
-               fprintf(stderr, "DEBUG: append_map %s to %s\n",
-                       ss2->source, ss1->source);
-
-       for (i = 0; i < ss2->used; ++i) {
-               s = ss2->symbol+i;
-               if (s->keep)
-                       add_symbol_n(ss1, s->address, s->type, 1,
-                               s->name);
-       }
-}
-
-/* Compare the various sources and build a merged system map */
-void merge_maps(const char *save_system_map)
-{
-       int i;
-       SYMBOL *s;
-       FILE *f;
-       static char const procname[] = "merge_maps";
-
-       if (debug)
-               fprintf(stderr, "DEBUG: %s\n", procname);
-
-       /* Using_Versions only appears in ksyms, copy to other tables */
-       if ((s = find_symbol_name(&ss_ksyms_base,
-                       "Using_Versions", 0))) {
-               if (ss_system_map.used) {
-                       add_symbol_n(&ss_system_map, s->address,
-                               s->type, s->keep, s->name);
-                       ss_sort_na(&ss_system_map);
-               }
-               if (ss_vmlinux.used) {
-                       add_symbol_n(&ss_vmlinux, s->address, s->type,
-                               s->keep, s->name);
-                       ss_sort_na(&ss_vmlinux);
-               }
-       }
-
-       compare_Version();      /* highlight any version problems first */
-       compare_ksyms_lsmod();  /* highlight any missing modules next */
-       compare_maps(&ss_ksyms_base, &ss_vmlinux, 2);
-       compare_maps(&ss_system_map, &ss_vmlinux, 2);
-       compare_maps(&ss_vmlinux, &ss_system_map, 1);
-       compare_maps(&ss_ksyms_base, &ss_system_map, 2);
-
-       if (ss_objects) {
-               map_ksyms_to_modules();
-       }
-
-       ss_init(&ss_merged, "merged");
-       append_map(&ss_merged, &ss_vmlinux);
-       append_map(&ss_merged, &ss_ksyms_base);
-       append_map(&ss_merged, &ss_system_map);
-       for (i = 0; i < ss_ksyms_modules; ++i)
-               append_map(&ss_merged, (ss_ksyms_module+i)->related);
-       if (!ss_merged.used) {
-               fprintf(stderr, "Warning, no symbols in merged map\n");
-               ++warnings;
-       }
-
-       /* drop duplicates, type a (registers) and gcc2_compiled. */
-       ss_sort_atn(&ss_merged);
-       s = ss_merged.symbol;
-       for (i = 0; i < ss_merged.used-1; ++i) {
-               if (s->type == 'a' ||
-                   (s->type == 't' && !strcmp(s->name, "gcc2_compiled.")))
-                       s->keep = 0;
-               else if (strcmp(s->name, (s+1)->name) == 0 &&
-                   s->address == (s+1)->address) {
-                       if (s->type != ' ')
-                               (s+1)->keep = 0;
-                       else
-                               s->keep = 0;
-               }
-               ++s;
-       }
-       ss_sort_atn(&ss_merged);        /* will remove dropped variables */
-
-       if (save_system_map) {
-               if (debug)
-                       fprintf(stderr, "DEBUG: writing merged map to %s\n",
-                               save_system_map);
-               if (!(f = fopen_local(save_system_map, "w", procname)))
-                       return;
-               s = ss_merged.symbol;
-               for (i = 0; i < ss_merged.used; ++i) {
-                       if (s->keep)
-                               fprintf(f, "%s %c %s\n",
-                                       format_address(s->address),
-                                       s->type, s->name);
-                       ++s;
-               }
-       }
-
-       /* The merged map may contain symbols with an address of 0, e.g.
-        * Using_Versions.  These give incorrect results for low addresses in
-        * map_address, such addresses map to "Using_Versions+xxx".  Remove
-        * any addresses below (arbitrary) 4096 from the merged map.  AFAIK,
-        * Linux does not use the first page on any arch.
-        */
-       for (i = 0; i < ss_merged.used; ++i) {
-               if ((ss_merged.symbol+i)->address < 4096)
-                       (ss_merged.symbol+i)->keep = 0;
-               else
-                       break;
-       }
-       if (i)
-               ss_sort_atn(&ss_merged);        /* remove dropped variables */
-}
diff --git a/scripts/ksymoops/misc.c b/scripts/ksymoops/misc.c
deleted file mode 100644 (file)
index 7876f7e..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
-       misc.c.
-
-       Miscellaneous routines for ksymoops.
-
-       Copyright Keith Owens <kaos@ocs.com.au>.
-       Released under the GNU Public Licence, Version 2.
-
-       Tue Nov  3 02:31:01 EST 1998
-       Version 0.6
-       Convert from a.out to bfd, using same format as ksymoops.
-
-       Wed Oct 28 13:47:23 EST 1998
-       Version 0.4
-       Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-void malloc_error(const char *msg)
-{
-       fprintf(stderr, "%s: fatal malloc error for %s\n", prefix, msg);
-       exit(2);
-}
-
-/* Format an address with the correct number of leading zeroes */
-const char *format_address(elf_addr_t address)
-{
-       /* Well oversized */
-       static char format[10], text[200];
-       if (!*format)
-               snprintf(format, sizeof(format), "%%0%dlx",
-                       2*sizeof(address));
-       snprintf(text, sizeof(text), format, address);
-       return(text);
-}
-
-/* Find the full pathname of a program.  Code heavily based on
- * glibc-2.0.5/posix/execvp.c.
- */
-char *find_fullpath(const char *program)
-{
-       char *fullpath = NULL;
-       char *path, *p;
-       size_t len;
-       static const char procname[] = "find_fullpath";
-
-       /* Don't search when it contains a slash.  */
-       if (strchr(program, '/')) {
-               if (!(fullpath = strdup(program)))
-                       malloc_error(procname);
-               if (debug > 1)
-                       fprintf(stderr, "DEBUG: %s %s\n", procname, fullpath);
-               return(fullpath);
-       }
-
-       path = getenv ("PATH");
-       if (!path) {
-               /* There is no `PATH' in the environment.  The default search
-                  path is the current directory followed by the path `confstr'
-                  returns for `_CS_PATH'.
-                */
-               len = confstr(_CS_PATH, (char *) NULL, 0);
-               if (!(path = malloc(1 + len)))
-                       malloc_error(procname);
-               path[0] = ':';
-               confstr(_CS_PATH, path+1, len);
-       }
-
-       len = strlen(program) + 1;
-       if (!(fullpath = malloc(strlen(path) + len)))
-               malloc_error(procname);
-       p = path;
-       do {
-               path = p;
-               p = strchr(path, ':');
-               if (p == NULL)
-                       p = strchr(path, '\0');
-
-               /* Two adjacent colons, or a colon at the beginning or the end
-                * of `PATH' means to search the current directory.
-                */
-               if (p == path)
-                       memcpy(fullpath, program, len);
-               else {
-                       /* Construct the pathname to try.  */
-                       memcpy(fullpath, path, p - path);
-                       fullpath[p - path] = '/';
-                       memcpy(&fullpath[(p - path) + 1], program, len);
-               }
-
-               /* If we have execute access, assume this is the program. */
-               if (access(fullpath, X_OK) == 0) {
-                       if (debug > 1)
-                               fprintf(stderr, "DEBUG: %s %s\n",
-                                       procname, fullpath);
-                       return(fullpath);
-               }
-       } while (*p++ != '\0');
-
-       fprintf(stderr, "Error: %s %s could not find executable %s\n",
-               prefix, procname, program);
-       ++errors;
-       return(NULL);
-}
diff --git a/scripts/ksymoops/object.c b/scripts/ksymoops/object.c
deleted file mode 100644 (file)
index 7a44e4c..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
-       object.c.
-
-       object handling routines for ksymoops.  Read modules, vmlinux, etc. 
-
-       Copyright Keith Owens <kaos@ocs.com.au>.
-       Released under the GNU Public Licence, Version 2.
-
-       Wed Oct 28 13:47:23 EST 1998
-       Version 0.4
-       Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-#include <string.h>
-#include <sys/stat.h>
-
-/* Extract all symbols definitions from an object using nm */
-static void read_nm_symbols(SYMBOL_SET *ss, const char *file)
-{
-       FILE *f;
-       char *cmd, *line = NULL, **string = NULL;
-       int i, size = 0;
-       static char const procname[] = "read_nm_symbols";
-
-       if (!regular_file(file, procname))
-               return;
-
-       cmd = malloc(strlen(path_nm)+strlen(file)+2);
-       if (!cmd)
-               malloc_error("nm command");
-       strcpy(cmd, path_nm);
-       strcat(cmd, " ");
-       strcat(cmd, file);
-       if (debug > 1)
-               fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
-       if (!(f = popen_local(cmd, procname)))
-               return;
-       free(cmd);
-
-       while (fgets_local(&line, &size, f, procname)) {
-               i = regexec(&re_nm, line, re_nm.re_nsub+1, re_nm_pmatch, 0);
-               if (debug > 3)
-                       fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-               if (i == 0) {
-                       re_strings(&re_nm, line, re_nm_pmatch, &string);
-                       add_symbol(ss, string[1], *string[2], 1, string[3]);
-               }
-       }
-
-       pclose_local(f, procname);
-       re_strings_free(&re_nm, &string);
-       free(line);
-       if (debug > 1)
-               fprintf(stderr,
-                       "DEBUG: %s %s used %d out of %d entries\n",
-                       procname, ss->source, ss->used, ss->alloc);
-}
-
-/* Read the symbols from vmlinux */
-void read_vmlinux(const char *vmlinux)
-{
-       if (!vmlinux)
-               return;
-       ss_init(&ss_vmlinux, "vmlinux");
-       read_nm_symbols(&ss_vmlinux, vmlinux);
-       if (ss_vmlinux.used) {
-               ss_sort_na(&ss_vmlinux);
-               extract_Version(&ss_vmlinux);
-       }
-       else {
-               fprintf(stderr,
-                       "Warning, no kernel symbols in vmlinux, is %s a valid "
-                       "vmlinux file?\n",
-                       vmlinux);
-               ++warnings;
-       }
-}
-
-
-/* Read the symbols from one object (module) */
-void read_object(const char *object, int i)
-{
-       ss_init(ss_object+i, object);
-       read_nm_symbols(ss_object+i, object);
-       if ((ss_object+i)->used) {
-               ss_sort_na(ss_object+i);
-               extract_Version(ss_object+i);
-       }
-       else {
-               fprintf(stderr, "Warning, no symbols in %s\n", object);
-               ++warnings;
-       }
-}
-
-/* Add a new entry to the list of objects */
-static void add_ss_object(const char *file)
-{
-       ++ss_objects;
-       ss_object = realloc(ss_object, ss_objects*sizeof(*ss_object));
-       if (!ss_object)
-               malloc_error("realloc ss_object");
-       ss_init(ss_object+ss_objects-1, file);
-}
-
-/* Run a directory and its subdirectories, looking for *.o files */
-static void find_objects(const char *dir)
-{
-       FILE *f;
-       char *cmd, *line = NULL;
-       int size = 0, files = 0;
-       static char const procname[] = "find_objects";
-       static char const options[] = " -follow -name '*.o' -print";
-
-       cmd = malloc(strlen(path_find)+1+strlen(dir)+strlen(options)+1);
-       if (!cmd)
-               malloc_error("find command");
-       strcpy(cmd, path_find);
-       strcat(cmd, " ");
-       strcat(cmd, dir);
-       strcat(cmd, options);
-       if (debug > 1)
-               fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
-       if (!(f = popen_local(cmd, procname)))
-               return;
-       free(cmd);
-
-       while (fgets_local(&line, &size, f, procname)) {
-               if (debug > 1)
-                       fprintf(stderr, "DEBUG: %s - %s\n", procname, line);
-               add_ss_object(line);
-               ++files;
-       }
-
-       pclose_local(f, procname);
-       if (!files) {
-               fprintf(stderr,
-                       "Warning: no *.o files in %s.  "
-                       "Is %s a valid module directory?\n",
-                       dir, dir);
-               ++warnings;
-       }
-}
-
-/* Take the user supplied list of objects which can include directories.
- * Expand directories into any *.o files.  The results are stored in
- * ss_object, leaving the user supplied options untouched.
- */
-void expand_objects(char * const *object, int objects)
-{
-       struct stat statbuf;
-       int i;
-       const char *file;
-       static char const procname[] = "expand_objects";
-
-       for (i = 0; i < objects; ++i) {
-               file = object[i];
-               if (debug > 1)
-                       fprintf(stderr, "DEBUG: %s checking '%s' - ",
-                               procname, file);
-               if (!stat(file, &statbuf) && S_ISDIR(statbuf.st_mode)) {
-                       if (debug > 1)
-                               fprintf(stderr, "directory, expanding\n");
-                       find_objects(file);
-               }
-               else {
-                       if (debug > 1)
-                               fprintf(stderr, "not directory\n");
-                       add_ss_object(file);
-               }
-       }
-}
-
-/* Map a symbol type to a section code. 0 - text, 1 - data, 2 - read only data,
- * 3 - C (cannot relocate), 4 - the rest.
- */
-static int section(char type)
-{
-       switch (type) {
-       case 'T':
-       case 't':
-               return 0;
-       case 'D':
-       case 'd':
-               return 1;
-       case 'R':
-       case 'r':
-               return 2;
-       case 'C':
-               return 3;
-       default:
-               return 4;
-       }
-}
-
-/* Given ksyms module data which has a related object, create a copy of the
- * object data, adjusting the offsets to match where the module was loaded.
- */
-SYMBOL_SET *adjust_object_offsets(SYMBOL_SET *ss)
-{
-       int i;
-       elf_addr_t adjust[] = {0, 0, 0, 0, 0};
-       SYMBOL *sk, *so;
-       SYMBOL_SET *ssc;
-
-       if (debug > 1)
-               fprintf(stderr,
-                       "DEBUG: adjust_object_offsets %s\n", ss->source);
-
-       ssc = ss_copy(ss->related);
-
-       /* For common symbols, calculate the adjustment */
-       for (i = 0; i < ss->used; ++i) {
-               sk = ss->symbol+i;
-               if ((so = find_symbol_name(ssc, sk->name, NULL)))
-                       adjust[section(so->type)] = sk->address - so->address;
-       }
-       for (i = 0; i < ssc->used; ++i) {
-               so = ssc->symbol+i;
-               /* Type C does not relocate well, silently ignore */
-               if (so->type != 'C' && adjust[section(so->type)])
-                       so->address += adjust[section(so->type)];
-               else
-                       so->keep = 0;  /* do not merge into final map */
-       }
-
-       ss->related = ssc;      /* map using adjusted copy */
-       return(ssc);
-}
diff --git a/scripts/ksymoops/oops.c b/scripts/ksymoops/oops.c
deleted file mode 100644 (file)
index 61107b1..0000000
+++ /dev/null
@@ -1,1377 +0,0 @@
-/*
-       oops.c.
-
-       Oops processing for ksymoop.
-
-       Copyright Keith Owens <kaos@ocs.com.au>.
-       Released under the GNU Public Licence, Version 2.
-       
-       Sun Jan  7 12:56:12 CET 1999
-       Added SPARC64 support and some SPARC hacks by "Jakub Jelinek"
-       <jj@ultra.linux.cz>
-
-       Mon Jan  4 08:47:55 EST 1999
-       Version 0.6d
-       Add ARM support.
-
-       Thu Nov 26 16:37:46 EST 1998
-       Version 0.6c
-       Typo in oops_code.
-       Add -c option.
-
-       Tue Nov  3 23:33:04 EST 1998
-       Version 0.6a
-       Performance inprovements.
-
-       Tue Nov  3 02:31:01 EST 1998
-       Version 0.6
-       Oops file must be regular.
-       Add "invalid operand" to Oops_print.
-       Minor adjustment to re for ppc.
-       Minor adjustment to re for objdump lines with <_EIP+xxx>.
-       Convert from a.out to bfd, using same format as ksymoops.
-       Added MIPS.
-       PPC handling based on patches by "Ryan Nielsen" <ran@krazynet.com>
-
-       Wed Oct 28 13:47:23 EST 1998
-       Version 0.4
-       Split into seperate sources.
- */
-
-#include "ksymoops.h"
-#include <bfd.h>
-#include <ctype.h>
-#include <errno.h>
-#include <malloc.h>
-#include <memory.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-enum oops_arch {
-       OOPS_NOARCH,
-       OOPS_I386,
-       OOPS_SPARC,
-       OOPS_SPARC64,
-       OOPS_ARM,
-       OOPS_ALPHA,
-       OOPS_MIPS,
-       OOPS_PPC,
-       OOPS_M68K
-} oops_arch;
-
-char *eip_names[] = { "IP", "EIP", "PC", "PC", "PC", "PC", "PC", "NIP", "PC" };
-
-/* Error detected by bfd */
-static void Oops_bfd_perror(const char *msg)
-{
-       fprintf(stderr, "Error ");
-       bfd_perror(msg);
-       ++errors;
-}
-
-/* Safest way to get correct output bfd format is to copy ksymoops' format. */
-static int Oops_copy_bfd_format(bfd **ibfd, bfd **obfd, asection **isec,
-                               const char *file)
-{
-       char *me, **matches, **match;
-
-       if (!(*obfd = bfd_openw(file, NULL))) {
-               Oops_bfd_perror(file);
-               return(0);
-       }
-
-       me = find_fullpath(prefix);
-       if (!me)
-               return(0);
-
-       if (!(*ibfd = bfd_openr(me, NULL))) {
-               Oops_bfd_perror(me);
-               return(0);
-       }
-       free(me);       /* Who is Tommy? */
-
-       if (!bfd_check_format_matches(*ibfd, bfd_object, &matches)) {
-               Oops_bfd_perror(me);
-               if (bfd_get_error() == bfd_error_file_ambiguously_recognized) {
-                       fprintf(stderr, "Matching formats:");
-                       match = matches;
-                       while (*match)
-                               fprintf(stderr, " %s", *match++);
-                       fprintf(stderr, "\n");
-                       free(matches);
-               }
-               return(0);
-       }
-
-       if (!(*isec = bfd_get_section_by_name(*ibfd, ".text"))) {
-               Oops_bfd_perror("get_section");
-               return(0);
-       }
-
-       bfd_set_format(*obfd, bfd_object);
-       bfd_set_arch_mach(*obfd, bfd_get_arch(*ibfd), bfd_get_mach(*ibfd));
-
-       if (!bfd_set_file_flags(*obfd, bfd_get_file_flags(*ibfd))) {
-               Oops_bfd_perror("set_file_flags");
-               return(0);
-       }
-
-       return(1);
-}
-
-/* Write the code values to a file using bfd. */
-static int Oops_write_bfd_data(bfd *ibfd, bfd *obfd, asection *isec,
-                              const char *code, int size)
-{
-       asection *osec;
-       asymbol *osym;
-
-       if (!bfd_set_start_address(obfd, 0)) {
-               Oops_bfd_perror("set_start_address");
-               return(0);
-       }
-       if (!(osec = bfd_make_section(obfd, ".text"))) {
-               Oops_bfd_perror("make_section");
-               return(0);
-       }
-       if (!bfd_set_section_flags(obfd, osec, 
-               bfd_get_section_flags(ibfd, isec))) {
-               Oops_bfd_perror("set_section_flags");
-               return(0);
-       }
-       if (!bfd_set_section_alignment(obfd, osec, 
-               bfd_get_section_alignment(ibfd, isec))) {
-               Oops_bfd_perror("set_section_alignment");
-               return(0);
-       }
-       osec->output_section = osec;
-       if (!(osym = bfd_make_empty_symbol(obfd))) {
-               Oops_bfd_perror("make_empty_symbol");
-               return(0);
-       }
-       osym->name = "_EIP";
-       osym->section = osec;
-       osym->flags = BSF_GLOBAL;
-       osym->value = 0;
-       if (!bfd_set_symtab(obfd, &osym, 1)) {
-               Oops_bfd_perror("set_symtab");
-               return(0);
-       }
-       if (!bfd_set_section_size(obfd, osec, size)) {
-               Oops_bfd_perror("set_section_size");
-               return(0);
-       }
-       if (!bfd_set_section_vma(obfd, osec, 0)) {
-               Oops_bfd_perror("set_section_vma");
-               return(0);
-       }
-       if (!bfd_set_section_contents(obfd, osec, (PTR) code, 0, size)) {
-               Oops_bfd_perror("set_section_contents");
-               return(0);
-       }
-       if (!bfd_close(obfd)) {
-               Oops_bfd_perror("close(obfd)");
-               return(0);
-       }
-       if (!bfd_close(ibfd)) {
-               Oops_bfd_perror("close(ibfd)");
-               return(0);
-       }
-       return 1;
-}
-
-/* Write the Oops code to a temporary file with suitable header and trailer. */
-static char *Oops_code_to_file(const char *code, int size)
-{
-       char *file;
-       bfd *ibfd, *obfd;
-       asection *isec;
-
-       bfd_init();
-       file = tmpnam(NULL);
-       if (!Oops_copy_bfd_format(&ibfd, &obfd, &isec, file))
-               return(NULL);
-       if (!Oops_write_bfd_data(ibfd, obfd, isec, code, size))
-               return(NULL);
-       return(file);
-}
-
-/* Run objdump against the binary Oops code */
-static FILE *Oops_objdump(const char *file)
-{
-       char *cmd;
-       FILE *f;
-       static char const options[] = "-dhf ";
-       static char const procname[] = "Oops_objdump";
-
-       cmd = malloc(strlen(path_objdump)+1+13+strlen(options)+strlen(file)+1);
-       if (!cmd)
-               malloc_error(procname);
-       strcpy(cmd, path_objdump);
-       strcat(cmd, " ");
-       if (oops_arch == OOPS_SPARC64)
-               strcat(cmd, "-m sparc:v9a ");
-       strcat(cmd, options);
-       strcat(cmd, file);
-       if (debug > 1)
-               fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
-       f = popen_local(cmd, procname);
-       free(cmd);
-       return(f);
-}
-
-/* Process one code line from objdump, ignore everything else */
-static void Oops_decode_one(SYMBOL_SET *ss, const char *line, elf_addr_t eip,
-                           int adjust)
-{
-       int i, j;
-       elf_addr_t address, eip_relative;
-       char *line2, *map, **string = NULL, *p;
-       static regex_t     re_Oops_objdump;
-       static regmatch_t *re_Oops_objdump_pmatch;
-       static char const procname[] = "Oops_decode_one";
-
-       /* objdump output.  Optional whitespace, hex digits, optional
-        * ' <_EIP+offset>', ':'.  The '+offset' after _EIP is also optional.
-        * Older binutils output 'xxxxxxxx <_EIP+offset>:', newer versions do
-        * '00000000 <_EIP>:' first followed by '      xx:' lines.
-        *
-        * Just to complicate things even more, objdump recognises jmp, call,
-        * etc., converts the code to something like this :-
-        * "   f: e8 32 34 00 00  call   3446 <_EIP+0x3446>"
-        * Recognise this and append the eip adjusted address, followed by the
-        * map_address text for that address.
-        *
-        * With any luck, objdump will take care of all such references which
-        * makes this routine architecture insensitive.  No need to test for
-        * i386 jmp, call or m68k swl etc.
-        */
-       re_compile(&re_Oops_objdump,
-                       "^[ \t]*"
-                       "([0-9a-fA-F]+)"                                /* 1 */
-                       "( <_EIP[^>]*>)?"                               /* 2 */
-                       ":"
-                       "("                                             /* 3 */
-                       ".* +"
-                       "(0?x?[0-9a-fA-F]+ +)"                          /* 4 */
-                       "<_EIP\\+0?x?([0-9a-fA-F]+)>[ \t]*$"            /* 5 */
-                       ")?"
-                       ".*"
-                       ,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_objdump_pmatch);
-
-       i = regexec(&re_Oops_objdump, line, re_Oops_objdump.re_nsub+1,
-               re_Oops_objdump_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-       if (i != 0)
-               return;
-
-       re_strings(&re_Oops_objdump, line, re_Oops_objdump_pmatch, &string);
-       errno = 0;
-       address = strtoul(string[1], NULL, 16);
-       if (errno) {
-               fprintf(stderr,
-                       "%s Invalid hex value in objdump line, "
-                       "treated as zero - '%s'\n"
-                       "  objdump line '%s'\n",
-                       procname, string[1], line);
-               perror(" ");
-               ++errors;
-               address = 0;
-       }
-       address += eip + adjust;
-       if (string[5]) {
-               /* EIP relative data to be adjusted */
-               errno = 0;
-               eip_relative = strtoul(string[5], NULL, 16);
-               if (errno) {
-#ifdef __sparc__
-                       /* Try strtoull also, e.g. sparc binutils print <_PC+0xfffffffffffffd58> */
-                       errno = 0;
-                       eip_relative = strtoull(string[5], NULL, 16);
-#endif
-                       if (errno) {
-                               fprintf(stderr,
-                                       "%s Invalid hex value in objdump line, "
-                                       "treated as zero - '%s'\n"
-                                       "  objdump line '%s'\n",
-                                       procname, string[5], line);
-                               perror(" ");
-                               ++errors;
-                               eip_relative = 0;
-                       }
-               }
-               eip_relative += eip + adjust;
-               map = map_address(&ss_merged, eip_relative);
-               /* new text is original line, eip_relative in hex, map text */
-               j = strlen(line);
-               if (string[4])
-                       j = re_Oops_objdump_pmatch[4].rm_so;
-               i = j+1+2*sizeof(eip_relative)+1+strlen(map)+1;
-               line2 = malloc(i + 5);
-               if (!line2)
-                       malloc_error(procname);
-               snprintf(line2, i, "%.*s %s %s",
-                       j, line, format_address(eip_relative), map);
-       } else {
-               line2 = malloc(strlen(line) + 6);
-               if (!line2)
-                       malloc_error(procname);
-               strcpy(line2, line);
-       }
-       if (oops_arch != OOPS_I386) {
-               p = line2;
-               while ((p = strstr(p, "_EIP"))) {
-                       int l = strlen(eip_names[oops_arch]);
-                       memcpy(p + 1, eip_names[oops_arch], l);
-                       if (l < 3)
-                               strcpy(p + 1 + l, p + 4);
-                       p += 1 + l;
-               }
-       }
-       if (address == eip)
-               strcat(line2, " <===");                 /* This makes it easier to locate visually the
-                                                          offending instruction */
-       add_symbol_n(ss, address, 'C', 1, line2);       /* as is */
-       free(line2);
-       re_strings_free(&re_Oops_objdump, &string);
-}
-
-/* Maximum number of code bytes to process.  It needs to be a multiple of 2 for
- * code_byte (-c) swapping.  Sparc and alpha dump 36 bytes so use 64.
- */
-#define CODE_SIZE 64
-
-/******************************************************************************/
-/*                     Start architecture sensitive code                      */
-/******************************************************************************/
-
-/* Extract the hex values from the Code: line and convert to binary */
-static int Oops_code_values(const unsigned char* code_text, char *code,
-                           int *adjust, char ***string, int string_max,
-                           int code_bytes)
-{
-       int byte = 0, i, l;
-       unsigned long c;
-       char *value;
-       const char *p;
-       static regex_t     re_Oops_code_value;
-       static regmatch_t *re_Oops_code_value_pmatch;
-       static const char procname[] = "Oops_code_values";
-
-       /* Given by re_Oops_code: code_text is a message (e.g. "general
-        * protection") or one or more hex fields separated by space or tab.
-        * Some architectures bracket the current instruction with '<'
-        * and '>', others use '(' and ')'.  The first character is
-        * nonblank.
-        */
-       if (!isxdigit(*code_text)) {
-               fprintf(stderr,
-                       "Warning, Code looks like message, not hex digits.  "
-                       "No disassembly attempted.\n");
-               ++warnings;
-               return(0);
-       }
-       memset(code, '\0', CODE_SIZE);
-       p = code_text;
-       *adjust = 0;    /* EIP points to code byte 0 */
-
-       /* Code values.  Hex values separated by white space.  On sparc, the
-        * current instruction is bracketed in '<' and '>'.
-        */
-       re_compile(&re_Oops_code_value,
-                       "^"
-                       "([<(]?)"                                       /* 1 */
-                       "([0-9a-fA-F]+)"                                /* 2 */
-                       "[>)]?"
-                       "[ \t]*"
-                       ,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_code_value_pmatch);
-
-       re_string_check(re_Oops_code_value.re_nsub+1, string_max, procname);
-       while (regexec(&re_Oops_code_value, p, re_Oops_code_value.re_nsub+1,
-                       re_Oops_code_value_pmatch, 0) == 0) {
-               re_strings(&re_Oops_code_value, p,
-                       re_Oops_code_value_pmatch, string);
-               if (byte >= CODE_SIZE)
-                       break;
-               errno = 0;
-               value = (*string)[2];
-               c = strtoul(value, NULL, 16);
-               if (errno) {
-                       fprintf(stderr,
-                               "%s Invalid hex value in code_value line, "
-                               "treated as zero - '%s'\n"
-                               "  code_value line '%s'\n",
-                               procname, value, code_text);
-                       perror(" ");
-                       ++errors;
-                       c = 0;
-               }
-               if ((*string)[1] && *((*string)[1]))
-                       *adjust = -byte;        /* this byte is EIP */
-               /* i386 - 2 byte code, m68k - 4 byte, sparc - 8 byte.
-                * On some architectures Code: is a stream of bytes, on some it
-                * is a stream of shorts, on some it is a stream of ints.
-                * Consistent we're not!
-                */
-               l = strlen(value);
-               if (l%2) {
-                       fprintf(stderr,
-                               "%s invalid value 0x%s in Code line, not a "
-                               "multiple of 2 digits, value ignored\n",
-                               procname, value);
-                       ++errors;
-               }
-               else while (l) {
-                       if (byte >= CODE_SIZE) {
-                               fprintf(stderr,
-                                       "%s Warning: extra values in Code "
-                                       "line, ignored - '%s'\n",
-                                       procname, value);
-                               ++warnings;
-                               break;
-                       }
-                       l -= 2;
-                       code[byte++] = (c >> l*4) & 0xff;
-                       value += 2;
-               }
-               p += re_Oops_code_value_pmatch[0].rm_eo;
-       }
-
-       if (*p) {
-               fprintf(stderr,
-                       "Warning garbage '%s' at end of code line ignored "
-                       "by %s\n",
-                       p, procname);
-               ++warnings;
-       }
-
-       /* The code_bytes parameter says how many readable bytes form a single
-        * code unit in machine terms.  -c 1 says that the text is already in
-        * machine order, -c 2 (4, 8) says each chunk of 2 (4, 8) bytes must be
-        * swapped to get back to machine order.  Which end is up?
-        */
-       if (code_bytes != 1) {
-               if (byte % code_bytes) {
-                       fprintf(stderr,
-                               "Warning: the number of code bytes (%d) is not "
-                               "a multiple of -c (%d)\n"
-                               "Byte swapping may not give sensible results\n",
-                               byte, code_bytes);
-                       ++warnings;
-               }
-               for (l = 0; l < byte; l+= code_bytes) {
-                       for (i = 0; i < code_bytes/2; ++i) {
-                               c = code[l+i];
-                               code[l+i] = code[l+code_bytes-i-1];
-                               code[l+code_bytes-i-1] = c;
-                       }
-               }
-       }
-
-       return(1);
-}
-
-/* Look for the EIP: line, returns start of the relevant hex value */
-static char *Oops_eip(const char *line, char ***string, int string_max)
-{
-       int i;
-       static regex_t     re_Oops_eip_sparc;
-       static regmatch_t *re_Oops_eip_sparc_pmatch;
-       static regex_t     re_Oops_eip_sparc64;
-       static regmatch_t *re_Oops_eip_sparc64_pmatch;
-       static regex_t     re_Oops_eip_ppc;
-       static regmatch_t *re_Oops_eip_ppc_pmatch;
-       static regex_t     re_Oops_eip_mips;
-       static regmatch_t *re_Oops_eip_mips_pmatch;
-       static regex_t     re_Oops_eip_other;
-       static regmatch_t *re_Oops_eip_other_pmatch;
-       static const char procname[] = "Oops_eip";
-       
-       /* Oops 'EIP:' line for sparc, actually PSR followed by PC */
-       re_compile(&re_Oops_eip_sparc,
-                       "^PSR: [0-9a-fA-F]+ PC: " UNBRACKETED_ADDRESS,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_eip_sparc_pmatch);
-
-       i = regexec(&re_Oops_eip_sparc, line, re_Oops_eip_sparc.re_nsub+1,
-               re_Oops_eip_sparc_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec sparc %d\n", procname, i);
-       if (i == 0) {
-               re_string_check(re_Oops_eip_sparc.re_nsub+1, string_max,
-                       procname);
-               re_strings(&re_Oops_eip_sparc, line, re_Oops_eip_sparc_pmatch,
-                       string);
-               oops_arch = OOPS_SPARC;
-               return((*string)[re_Oops_eip_sparc.re_nsub]);
-       }
-
-       /* Oops 'EIP:' line for sparc64, actually TSTATE followed by TPC */
-       re_compile(&re_Oops_eip_sparc64,
-                       "^TSTATE: [0-9a-fA-F]{16} TPC: " UNBRACKETED_ADDRESS,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_eip_sparc64_pmatch);
-
-       re_string_check(re_Oops_eip_sparc64.re_nsub+1, string_max, procname);
-       i = regexec(&re_Oops_eip_sparc64, line, re_Oops_eip_sparc64.re_nsub+1,
-               re_Oops_eip_sparc64_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec sparc64 %d\n", procname, i);
-       if (i == 0) {
-               re_strings(&re_Oops_eip_sparc64, line, re_Oops_eip_sparc64_pmatch,
-                       string);
-               oops_arch = OOPS_SPARC64;
-               return((*string)[re_Oops_eip_sparc64.re_nsub]);
-       }
-
-       /* Oops 'EIP:' line for PPC, all over the place */
-       re_compile(&re_Oops_eip_ppc,
-                       "("
-                         "(kernel pc )"
-                         "|(trap at PC: )"
-                         "|(bad area pc )"
-                         "|(NIP: )"
-                       ")"
-                       UNBRACKETED_ADDRESS,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_eip_ppc_pmatch);
-
-       i = regexec(&re_Oops_eip_ppc, line, re_Oops_eip_ppc.re_nsub+1,
-               re_Oops_eip_ppc_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec ppc %d\n", procname, i);
-       if (i == 0) {
-               re_string_check(re_Oops_eip_ppc.re_nsub+1, string_max,
-                       procname);
-               re_strings(&re_Oops_eip_ppc, line, re_Oops_eip_ppc_pmatch,
-                       string);
-               oops_arch = OOPS_PPC;
-               return((*string)[re_Oops_eip_ppc.re_nsub]);
-       }
-
-       /* Oops 'EIP:' line for MIPS, epc, optional white space, ':',
-        * optional white space, unbracketed address.
-        */
-       re_compile(&re_Oops_eip_mips,
-                       "^(epc[ \t]*:+[ \t]*)"
-                       UNBRACKETED_ADDRESS,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_eip_mips_pmatch);
-
-       i = regexec(&re_Oops_eip_mips, line, re_Oops_eip_mips.re_nsub+1,
-               re_Oops_eip_mips_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec mips %d\n", procname, i);
-       if (i == 0) {
-               re_string_check(re_Oops_eip_mips.re_nsub+1, string_max,
-                       procname);
-               re_strings(&re_Oops_eip_mips, line, re_Oops_eip_mips_pmatch,
-                       string);
-               oops_arch = OOPS_MIPS;
-               return((*string)[re_Oops_eip_mips.re_nsub]);
-       }
-
-       /* Oops 'EIP:' line for other architectures */
-       re_compile(&re_Oops_eip_other,
-                       "^("
-       /* i386 */      "(EIP:[ \t]+.*)"
-       /* m68k */      "|(PC[ \t]*=[ \t]*)"
-       /* ARM */       "|(pc *: *)"
-                       ")"
-                       BRACKETED_ADDRESS
-                       ,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_eip_other_pmatch);
-
-       i = regexec(&re_Oops_eip_other, line, re_Oops_eip_other.re_nsub+1,
-               re_Oops_eip_other_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec other %d\n", procname, i);
-       if (i == 0) {
-               re_string_check(re_Oops_eip_other.re_nsub+1, string_max,
-                       procname);
-               re_strings(&re_Oops_eip_other, line, re_Oops_eip_other_pmatch,
-                       string);
-               oops_arch = OOPS_I386;
-               return((*string)[re_Oops_eip_other.re_nsub]);
-       }
-       return(NULL);
-}
-
-/* Set the eip from the EIP line */
-static void Oops_set_eip(const char *value, elf_addr_t *eip, SYMBOL_SET *ss)
-{
-       static const char procname[] = "Oops_set_eip";
-       char buf[10];
-       errno = 0;
-       *eip = strtoul(value, NULL, 16);
-       if (errno) {
-               fprintf(stderr,
-                       "%s Invalid hex value in EIP line, ignored - '%s'\n",
-                       procname, value);
-               perror(" ");
-               ++errors;
-               *eip = 0;
-       }
-       sprintf(buf, ">>%s:", eip_names[oops_arch]);
-       add_symbol_n(ss, *eip, 'E', 1, buf);
-}
-
-/* Look for the MIPS ra line, returns start of the relevant hex value */
-static char *Oops_ra(const char *line, char ***string, int string_max)
-{
-       int i;
-       static regex_t     re_Oops_ra;
-       static regmatch_t *re_Oops_ra_pmatch;
-       static const char procname[] = "Oops_ra";
-
-       /* Oops 'ra:' line for MIPS, ra, optional white space, one or
-        * more '=', optional white space, unbracketed address.
-        */
-       re_compile(&re_Oops_ra,
-                       "(ra[ \t]*=+[ \t]*)"
-                       UNBRACKETED_ADDRESS,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_ra_pmatch);
-
-       i = regexec(&re_Oops_ra, line, re_Oops_ra.re_nsub+1,
-               re_Oops_ra_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-       if (i == 0) {
-               re_string_check(re_Oops_ra.re_nsub+1, string_max, procname);
-               re_strings(&re_Oops_ra, line, re_Oops_ra_pmatch,
-                       string);
-               return((*string)[re_Oops_ra.re_nsub]);
-       }
-       return(NULL);
-}
-
-/* Set the MIPS ra from the ra line */
-static void Oops_set_ra(const char *value, SYMBOL_SET *ss)
-{
-       static const char procname[] = "Oops_set_ra";
-       elf_addr_t ra;
-       errno = 0;
-       ra = strtoul(value, NULL, 16);
-       if (errno) {
-               fprintf(stderr,
-                       "%s Invalid hex value in ra line, ignored - '%s'\n",
-                       procname, value);
-               perror(" ");
-               ++errors;
-               ra = 0;
-       }
-       add_symbol_n(ss, ra, 'R', 1, ">>RA :");
-}
-
-/* Look for the SPARC o7/i7 registers line, returns start of the relevant hex value */
-static char *Oops_oi7(const char *line, char ***string, int string_max)
-{
-       int i;
-       static regex_t     re_Oops_oi7;
-       static regmatch_t *re_Oops_oi7_pmatch;
-       static const char procname[] = "Oops_oi7";
-
-       re_compile(&re_Oops_oi7,
-                       "^[io][04]: [0-9a-fA-F iosp:]+ ([io]7|ret_pc): "
-                       UNBRACKETED_ADDRESS,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_oi7_pmatch);
-
-       re_string_check(re_Oops_oi7.re_nsub+1, string_max, procname);
-       i = regexec(&re_Oops_oi7, line, re_Oops_oi7.re_nsub+1,
-               re_Oops_oi7_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-       if (i == 0) {
-               re_strings(&re_Oops_oi7, line, re_Oops_oi7_pmatch,
-                       string);
-               return((*string)[re_Oops_oi7.re_nsub]);
-       }
-       return(NULL);
-}
-
-/* Set the SPARC o7/i7 from the oi7 line */
-static void Oops_set_oi7(const char *value, char ***string, SYMBOL_SET *ss)
-{
-       static const char procname[] = "Oops_set_oi7";
-       elf_addr_t oi7;
-       int o7 = 1;
-       errno = 0;
-       oi7 = strtoul(value, NULL, 16);
-       if ((*string)[1] && !strcmp((*string)[1], "i7"))
-               o7 = 0;
-       if (errno) {
-               fprintf(stderr,
-                       "%s Invalid hex value in oi7 line, ignored - '%s'\n",
-                       procname, value);
-               perror(" ");
-               ++errors;
-               oi7 = 0;
-       }
-       add_symbol_n(ss, oi7, 'O', 1, o7 ? ">>O7:" : ">>I7:");
-}
-
-/* Look for the SPARC register dump lines end */
-static int Oops_sparc_regdump(const char *line)
-{
-       int i;
-       static regex_t     re_Oops_sparc_regdump;
-       static regmatch_t *re_Oops_sparc_regdump_pmatch;
-       static const char procname[] = "Oops_sparc_regdump";
-
-       re_compile(&re_Oops_sparc_regdump,
-                      "^(i[04]: "
-                       "|Instruction DUMP: "
-                       "|Caller\\["
-                       ")",
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_sparc_regdump_pmatch);
-
-       i = regexec(&re_Oops_sparc_regdump, line, re_Oops_sparc_regdump.re_nsub+1,
-               re_Oops_sparc_regdump_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-       if (i == 0)
-               return 1;
-       return 0;
-}
-
-
-/* Look for the Trace multilines :(.  Returns start of addresses. */
-static const char *Oops_trace(const char *line, char ***string, int string_max)
-{
-       int i;
-       const char *start = NULL;
-       static int trace_line = 0;
-       static regex_t     re_Oops_trace;
-       static regmatch_t *re_Oops_trace_pmatch;
-       static const char procname[] = "Oops_trace";
-
-       /* ppc is different, not a bracketed address, just an address */
-       /* ARM is different, two bracketed addresses on each line */
-
-       /* Oops 'Trace' lines */
-       re_compile(&re_Oops_trace,
-                       "^("                                    /*  1 */
-                       "(Call Trace: )"                        /*  2 */
-       /* alpha */     "|(Trace: )"                            /*  3 */
-       /* various */   "|(" BRACKETED_ADDRESS ")"              /* 4,5*/
-       /* ppc */       "|(Call backtrace:)"                    /*  6 */
-       /* ppc */       "|(" UNBRACKETED_ADDRESS ")"            /* 7,8*/
-       /* ARM */       "|(Function entered at (" BRACKETED_ADDRESS "))"        /* 9,10,11 */
-       /* sparc */
-       /* sparc64 */   "|(Caller\\[" UNBRACKETED_ADDRESS "\\])"/*12,13*/
-                       ")",
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_trace_pmatch);
-
-       i = regexec(&re_Oops_trace, line, re_Oops_trace.re_nsub+1,
-               re_Oops_trace_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-       if (i == 0) {
-#undef MATCHED
-#define MATCHED(n) (re_Oops_trace_pmatch[n].rm_so != -1)
-               if (MATCHED(2) || MATCHED(3)) {
-                       trace_line = 1;
-                       start = line + re_Oops_trace_pmatch[0].rm_eo;
-               }
-               else if (MATCHED(6)) {
-                       trace_line = 2;         /* ppc */
-                       start = line + re_Oops_trace_pmatch[0].rm_eo;
-               }
-               else if (trace_line == 1 && MATCHED(5))
-                       start = line + re_Oops_trace_pmatch[5].rm_so;
-               else if (trace_line == 2 && MATCHED(8)) /* ppc */
-                       start = line + re_Oops_trace_pmatch[8].rm_so;
-               else if (MATCHED(10)){
-                       trace_line = 1;         /* ARM */
-                       start = line + re_Oops_trace_pmatch[10].rm_so;
-               } else if (MATCHED(12)) {
-                       trace_line = 0;         /* sparc, sparc64 */
-                       start = line + re_Oops_trace_pmatch[13].rm_so;
-                       return start;
-               } else
-                       trace_line = 0;
-       }
-       else
-               trace_line = 0;
-       if (trace_line)
-               return(start);
-       return(NULL);
-}
-
-/* Process a trace call line, extract addresses */
-static void Oops_trace_line(const char *line, const char *p, SYMBOL_SET *ss)
-{
-       char **string = NULL;
-       regex_t *pregex;
-       regmatch_t *pregmatch;
-       static const char procname[] = "Oops_trace_line";
-
-       /* ppc does not bracket its addresses */
-       if (isxdigit(*p)) {
-               pregex = &re_unbracketed_address;
-               pregmatch = re_unbracketed_address_pmatch;
-       }
-       else {
-               pregex = &re_bracketed_address;
-               pregmatch = re_bracketed_address_pmatch;
-       }
-
-       /* Loop over [un]?bracketed addresses */
-       while (1) {
-               if (regexec(pregex, p, pregex->re_nsub+1, pregmatch, 0) == 0) {
-                       re_strings(pregex, p, pregmatch, &string);
-                       add_symbol(ss, string[1], 'T', 1, "Trace:");
-                       p += pregmatch[0].rm_eo;
-               }
-               else if (strncmp(p, "from ", 5) == 0)
-                       p += 5;         /* ARM does "address from address" */
-               else
-                       break;
-       }
-
-       if (*p && !strcmp(p, "...")) {
-               fprintf(stderr,
-                       "Warning garbage '%s' at end of trace line ignored "
-                       "by %s\n",
-                       p, procname);
-               ++warnings;
-       }
-       re_strings_free(pregex, &string);
-}
-
-/* Do pattern matching to decide if the line should be printed.  When reading a
- * syslog containing multiple Oops, you need the intermediate data (registers,
- * tss etc.) to go with the decoded text.  Sets text to the start of the useful
- * text, after any prefix.  Note that any leading white space is treated as part
- * of the prefix, later routines do not see any indentation.
- *
- * Note: If a line is not printed, it will not be scanned for any other text.
- */
-static int Oops_print(const char *line, const char **text, char ***string,
-                     int string_max)
-{
-       int i, print = 0;
-       static int stack_line = 0, trace_line = 0;
-       static regex_t     re_Oops_prefix;
-       static regmatch_t *re_Oops_prefix_pmatch;
-       static regex_t     re_Oops_print_s;
-       static regmatch_t *re_Oops_print_s_pmatch;
-       static regex_t     re_Oops_print_a;
-       static regmatch_t *re_Oops_print_a_pmatch;
-       static const char procname[] = "Oops_print";
-
-       *text = line;
-
-       /* Lines to be ignored.  For some reason the "amuse the user" print in
-        * some die_if_kernel routines causes regexec to run very slowly.
-        */
-
-       if (strstr(*text, "\\|/ ____ \\|/")  ||
-           strstr(*text, "\"@'/ ,. \\`@\"") ||
-           strstr(*text, "/_| \\__/ |_\\")  ||
-           strstr(*text, "   \\__U_/"))
-               return(1);      /* print but avoid regexec */
-
-       /* Prefixes to be ignored */
-       re_compile(&re_Oops_prefix,
-                       "^("                    /* start of line */
-                       "([^ ]{3} [ 0-9][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} "
-                         "[^ ]+ kernel: +)"    /* syslogd */
-                       "|(<[0-9]+>)"           /* kmsg */
-                       "|([ \t]+)"             /* leading white space */
-                       ")+"                    /* any prefixes, in any order */
-                       ,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_prefix_pmatch);
-
-       i = regexec(&re_Oops_prefix, *text, re_Oops_prefix.re_nsub+1,
-               re_Oops_prefix_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec prefix %d\n", procname, i);
-       if (i == 0)
-               *text += re_Oops_prefix_pmatch[0].rm_eo;  /* step over prefix */
-
-
-       /* Lots of possibilities.  Expand as required for all architectures.
-        *
-        * Trial and error shows that regex does not like a lot of sub patterns
-        * that start with "^".  So split the patterns into two groups, one set
-        * must appear at the start of the line, the other set can appear
-        * anywhere.
-        */
-
-       /* These patterns must appear at the start of the line, after stripping
-        * the prefix above.
-        *
-        * The order below is required to handle multiline outupt.
-        * string 2 is defined if the text is 'Stack from '.
-        * string 3 is defined if the text is 'Stack: '.
-        * string 4 is defined if the text might be a stack continuation.
-        * string 5 is defined if the text is 'Call Trace: '.
-        * string 6 is defined if the text might be a trace continuation.
-        * string 7 is the address part of the BRACKETED_ADDRESS.
-        *
-        * string 8 is defined if the text contains a version number.  No Oops
-        * report contains this as of 2.1.125 but IMHO it should be added.  If
-        * anybody wants to print a VERSION_nnnn line in their Oops, this code
-        * is ready.
-        *
-        * string 9 is defined if the text is 'Trace: ' (alpha).
-        * string 10 is defined if the text is 'Call backtrace:' (ppc).
-        */
-       re_compile(&re_Oops_print_s,
-       /* arch type */                                     /* Required order */
-                       "^("                                            /*  1 */
-       /* i386 */      "(Stack: )"                                     /*  2 */
-       /* m68k */      "|(Stack from )"                                /*  3 */
-       /* various */   "|([0-9a-fA-F]{4,})"                            /*  4 */
-       /* various */   "|(Call Trace: )"                               /*  5 */
-       /* various */   "|(" BRACKETED_ADDRESS ")"                      /* 6,7*/
-       /* various */   "|(Version_[0-9]+)"                             /*  8 */
-       /* alpha */     "|(Trace: )"                                    /*  9 */
-       /* ppc */       "|(Call backtrace:)"                            /* 10 */
-
-                       /* order does not matter from here on */
-       
-       /* various */   "|(Process .*stackpage=)"
-       /* various */   "|(Call Trace:[ \t])"
-       /* various */   "|(Code *:[ \t])"
-       /* various */   "|(Kernel panic)"
-       /* various */   "|(In swapper task)"
-
-       /* i386 2.0 */  "|(Corrupted stack page)"
-       /* i386 */      "|(invalid operand: )"
-       /* i386 */      "|(Oops: )"
-       /* i386 */      "|(Cpu: +[0-9])"
-       /* i386 */      "|(current->tss)"
-       /* i386 */      "|(\\*pde +=)"
-       /* i386 */      "|(EIP: )"
-       /* i386 */      "|(EFLAGS: )"
-       /* i386 */      "|(eax: )"
-       /* i386 */      "|(esi: )"
-       /* i386 */      "|(ds: )"
-
-       /* m68k */      "|(pc[:=])"
-       /* m68k */      "|(68060 access)"
-       /* m68k */      "|(Exception at )"
-       /* m68k */      "|(d[04]: )"
-       /* m68k */      "|(Frame format=)"
-       /* m68k */      "|(wb [0-9] stat)"
-       /* m68k */      "|(push data: )"
-       /* m68k */      "|(baddr=)"
-       /* any other m68K lines to print? */
-
-       /* alpha */     "|(Bad unaligned kernel)"
-       /* alpha */     "|(Forwarding unaligned exception)"
-       /* alpha */     "|(: unhandled unaligned exception)"
-       /* alpha */     "|(<sc)"
-       /* alpha */     "|(pc *=)"
-       /* alpha */     "|(r[0-9]+ *=)"
-       /* alpha */     "|(gp *=)"
-       /* any other alpha lines to print? */
-
-       /* sparc */     "|(tsk->)"
-       /* sparc */     "|(PSR: )"
-       /* sparc */     "|([goli][04]: )"
-       /* sparc */     "|(Instruction DUMP: )"
-       /* sparc */     "|(Caller\\[)"
-       /* any other sparc lines to print? */
-       
-       /* sparc64 */   "|(TSTATE: )"
-       /* any other sparc64 lines to print? */
-
-       /* ppc */       "|(MSR: )"
-       /* ppc */       "|(TASK = )"
-       /* ppc */       "|(last math )"
-       /* ppc */       "|(GPR[0-9]+: )"
-       /* any other ppc lines to print? */
-
-       /* MIPS */      "|(\\$[0-9 ]+:)"
-       /* MIPS */      "|(epc )"
-       /* MIPS */      "|(Status:)"
-       /* MIPS */      "|(Cause :)"
-       /* any other MIPS lines to print? */
-
-       /* ARM */       "|(Backtrace:)"
-       /* ARM */       "|(Function entered at)"
-       /* ARM */       "|(\\*pgd =)"
-       /* ARM */       "|(Internal error)"
-       /* ARM */       "|(pc :)"
-       /* ARM */       "|(sp :)"
-       /* ARM */       "|(r[0-9][0-9 ]:)"
-       /* ARM */       "|(Flags:)"
-       /* ARM */       "|(Control:)"
-       /* any other ARM lines to print? */
-
-                       ")",
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_print_s_pmatch);
-
-       i = regexec(&re_Oops_print_s, *text, re_Oops_print_s.re_nsub+1,
-               re_Oops_print_s_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec start %d\n", procname, i);
-       print = 0;
-       if (i == 0) {
-#undef MATCHED
-#define MATCHED(n) (re_Oops_print_s_pmatch[n].rm_so != -1)
-               print = 1;
-               /* Handle multiline messages, messy */
-               if (!MATCHED(2) && !MATCHED(3) && !MATCHED(4))
-                       stack_line = 0;
-               else if (MATCHED(2) || MATCHED(3))
-                       stack_line = 1;
-               else if (stack_line && !MATCHED(4)) {
-                       print = 0;
-                       stack_line = 0;
-               }
-               if (!MATCHED(5) && !MATCHED(6) && !MATCHED(9) && !MATCHED(10))
-                       trace_line = 0;
-               else if (MATCHED(5) || MATCHED(9) || MATCHED(10))
-                       trace_line = 1;
-               else if (stack_line && !MATCHED(6)) {
-                       print = 0;
-                       trace_line = 0;
-               }
-               /* delay splitting into strings until we really them */
-               if (MATCHED(8)) {
-                       re_string_check(re_Oops_print_s.re_nsub+1, string_max,
-                               procname);
-                       re_strings(&re_Oops_print_s, *text,
-                               re_Oops_print_s_pmatch,
-                               string);
-                       add_Version((*string)[8]+8, "Oops");
-               }
-       }
-
-       /* These patterns can appear anywhere in the line, after stripping
-        * the prefix above.
-        */
-       re_compile(&re_Oops_print_a,
-       /* arch type */
-
-       /* various */   "(Unable to handle kernel)"
-       /* various */   "|(Aiee)"      /* anywhere in text is a bad sign (TM) */
-       /* various */   "|(die_if_kernel)"      /* ditto */
-
-       /* alpha */     "|(\\([0-9]\\): Oops )"
-       /* alpha */     "|(: memory violation)"
-       /* alpha */     "|(: Exception at)"
-       /* alpha */     "|(: Arithmetic fault)"
-       /* alpha */     "|(: Instruction fault)"
-       /* alpha */     "|(: arithmetic trap)"
-       /* alpha */     "|(: unaligned trap)"
-
-       /* sparc      die_if_kernel has no fixed text, identify by (pid): text.
-        *            Somebody has been playful with the texts.
-        *
-        *            Alas adding this next pattern increases run time by 15% on
-        *            its own!  It would be considerably faster if sparc had
-        *            consistent error texts.
-        */
-       /* sparc */     "|("
-                          "\\([0-9]+\\): "
-                          "("
-                            "(Whee)"
-                            "|(Oops)"
-                            "|(Kernel)"
-                            "|(Penguin)"
-                            "|(Too many Penguin)"
-                            "|(BOGUS)"
-                          ")"
-                        ")"
-
-       /* ppc */       "|(kernel pc )"
-       /* ppc */       "|(trap at PC: )"
-       /* ppc */       "|(bad area pc )"
-       /* ppc */       "|(NIP: )"
-
-       /* MIPS */      "|( ra *=)"
-
-                       ")",
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_print_a_pmatch);
-
-       i = regexec(&re_Oops_print_a, *text, re_Oops_print_a.re_nsub+1,
-               re_Oops_print_a_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec anywhere %d\n", procname, i);
-       if (i == 0)
-               print = 1;
-
-       return(print);
-}
-
-/* Look for the Code: line.  Returns start of the code bytes. */
-static const char *Oops_code(const char *line, char ***string, int string_max)
-{
-       int i;
-       static regex_t     re_Oops_code;
-       static regmatch_t *re_Oops_code_pmatch;
-       static const char procname[] = "Oops_code";
-
-       /* Oops 'Code: ' hopefully followed by at least one hex code.  sparc
-        * brackets the PC in '<' and '>'.  ARM brackets the PC in '(' and ')'.
-        */
-       re_compile(&re_Oops_code,
-                       "^("                                            /*  1 */
-       /* sparc */       "(Instruction DUMP)"                          /*  2 */
-       /* various */     "|(Code *)"                                   /*  3 */
-                       ")"
-                       ":[ \t]+"
-                       "("                                             /*  4 */
-                         "(general protection.*)"
-                         "|(<[0-9]+>)"
-                         "|(([<(]?[0-9a-fA-F]+[>)]?[ \t]+)+[<(]?[0-9a-fA-F]+[>)]?)"
-                       ")"
-                       "(.*)$"                         /* trailing garbage */
-                       ,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_code_pmatch);
-
-       i = regexec(&re_Oops_code, line, re_Oops_code.re_nsub+1,
-               re_Oops_code_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-       if (i == 0) {
-               re_string_check(re_Oops_code.re_nsub+1, string_max, procname);
-               re_strings(&re_Oops_code, line, re_Oops_code_pmatch,
-                       string);
-               if ((*string)[re_Oops_code.re_nsub] &&
-                   *((*string)[re_Oops_code.re_nsub])) {
-                       fprintf(stderr,
-                               "Warning: trailing garbage ignored on Code: "
-                               "line\n"
-                               "  Text: '%s'\n"
-                               "  Garbage: '%s'\n",
-                               line, (*string)[re_Oops_code.re_nsub]);
-                       ++warnings;
-               }
-               return((*string)[4]);
-       }
-       return(NULL);
-}
-
-/******************************************************************************/
-/*                      End architecture sensitive code                       */
-/******************************************************************************/
-
-/* Decode the Oops Code: via objdump*/
-static void Oops_decode(const unsigned char* code_text, elf_addr_t eip,
-                       SYMBOL_SET *ss, char ***string, int string_max,
-                       int code_bytes)
-{
-       FILE *f;
-       char *file, *line = NULL, code[CODE_SIZE];
-       int size = 0, adjust;
-       static char const procname[] = "Oops_decode";
-
-       if (debug)
-               fprintf(stderr, "DEBUG: %s\n", procname);
-       /* text to binary */
-       if (!Oops_code_values(code_text, code, &adjust, string, string_max,
-               code_bytes))
-               return;
-       /* binary to same format as ksymoops */
-       if (!(file = Oops_code_to_file(code, CODE_SIZE)))
-               return;
-       /* objdump the pseudo object */
-       if (!(f = Oops_objdump(file)))  
-               return;
-       while (fgets_local(&line, &size, f, procname)) {
-               if (debug > 1)
-                       fprintf(stderr, "DEBUG: %s - %s\n", procname, line);
-               Oops_decode_one(ss, line, eip, adjust);
-       }
-       pclose_local(f, procname);      /* opened in Oops_objdump */
-       free(line);
-       if (unlink(file)) {
-               fprintf(stderr, "%s could not unlink %s", prefix, file);
-               perror(" ");
-       }
-}
-
-/* Reached the end of an Oops report, format the extracted data. */
-static void Oops_format(const SYMBOL_SET *ss_format)
-{
-       int i;
-       SYMBOL *s;
-       static const char procname[] = "Oops_format";
-
-       if (debug)
-               fprintf(stderr, "DEBUG: %s\n", procname);
-
-       compare_Version();      /* Oops might have a version one day */
-       printf("\n");
-       for (s = ss_format->symbol, i = 0; i < ss_format->used; ++i, ++s) {
-               /* For type C data, print Code:, address, map, "name" (actually
-                * the text of an objdump line).  For other types print name,
-                * address, map.
-                */
-               if (s->type == 'C')
-                       printf("Code:  %s %-30s %s\n",
-                               format_address(s->address),
-                               map_address(&ss_merged, s->address),
-                               s->name);
-               else
-                       printf("%s %s %s\n",
-                               s->name,
-                               format_address(s->address),
-                               map_address(&ss_merged, s->address));
-       }
-       printf("\n");
-}
-
-/* Select next Oops input file */
-static FILE *Oops_next_file(int *filecount, char * const **filename)
-{
-       static FILE *f = NULL;
-       static const char procname[] = "Oops_next_file";
-       static int first_file = 1;
-
-       if (first_file) {
-               f = stdin;
-               first_file = 0;
-       }
-       while (*filecount) {
-               if (f)
-                       fclose_local(f, procname);
-               f = NULL;
-               if (regular_file(**filename, procname))
-                       f = fopen_local(**filename, "r", procname);
-               if (f) {
-                       if (debug)
-                               fprintf(stderr,
-                                       "DEBUG: reading Oops report "
-                                       "from %s\n", **filename);
-               }
-               ++*filename;
-               --*filecount;
-               if (f)
-                       return(f);
-       }
-       return(f);
-}
-
-/* Read the Oops report */
-#define MAX_STRINGS 300        /* Maximum strings in any Oops re */
-int Oops_read(int filecount, char * const *filename, int code_bytes,
-             int one_shot)
-{
-       char *line = NULL, **string = NULL;
-       const char *start, *text;
-       int i, size = 0, lineno = 0, lastprint = 0, print = 0;
-       elf_addr_t eip = 0;
-       int sparc_regdump = 0;
-       FILE *f;
-       SYMBOL_SET ss_format;
-       static const char procname[] = "Oops_read";
-
-       ss_init(&ss_format, "Oops log data");
-
-       if (!filecount && isatty(0))
-               printf("Reading Oops report from the terminal\n");
-
-       string = malloc(MAX_STRINGS*sizeof(*string));
-       if (!string)
-               malloc_error(procname);
-       memset(string, '\0', MAX_STRINGS*sizeof(*string));
-
-       do {
-               if (!(f = Oops_next_file(&filecount, &filename)))
-                       continue;
-               while (fgets_local(&line, &size, f, procname)) {
-                       if (debug > 2)
-                               fprintf(stderr,
-                                       "DEBUG: %s - %s\n", procname, line);
-                       ++lineno;
-                       print = Oops_print(line, &text, &string, MAX_STRINGS);
-                       if (Oops_sparc_regdump (text)) {
-                               sparc_regdump = 1;
-                       } else {
-                               if ((oops_arch == OOPS_SPARC || 
-                                    oops_arch == OOPS_SPARC64) &&
-                                   sparc_regdump && ss_format.used) {
-                                       Oops_format(&ss_format);
-                                       ss_free(&ss_format);
-                               }
-                               sparc_regdump = 0;
-                       }
-                       if (print) {
-                               puts(line);
-                               lastprint = lineno;
-                               if ((start = Oops_eip(text,
-                                       &string, MAX_STRINGS)))
-                                       Oops_set_eip(start, &eip, &ss_format);
-                               if ((start = Oops_ra(text,
-                                       &string, MAX_STRINGS)))
-                                       Oops_set_ra(start, &ss_format);
-                               if ((start = Oops_oi7(text,
-                                       &string, MAX_STRINGS)))
-                                       Oops_set_oi7(start, &string, 
-                                               &ss_format);
-                               if ((start = Oops_trace(text,
-                                       &string, MAX_STRINGS)))
-                                       Oops_trace_line(text, start,
-                                               &ss_format);
-                               if ((start = Oops_code(text,
-                                       &string, MAX_STRINGS))) {
-                                       Oops_decode(start, eip, &ss_format,
-                                               &string, MAX_STRINGS,
-                                               code_bytes);
-                                       Oops_format(&ss_format);
-                                       ss_free(&ss_format);
-                                       if (one_shot)
-                                               return(0);
-                               }
-                       }
-                       /* More than 5 (arbitrary) lines which were not printed
-                        * and there is some saved data, assume we missed the
-                        * Code: line.
-                        */
-                       if (ss_format.used && lineno > lastprint+5) {
-                               fprintf(stderr,
-                                       "Warning, Code line not seen, dumping "
-                                       "what data is available\n");
-                               ++warnings;
-                               Oops_format(&ss_format);
-                               ss_free(&ss_format);
-                               if (one_shot)
-                                       return(0);
-                       }
-               }
-               if (ss_format.used) {
-                       if ((oops_arch != OOPS_SPARC &&
-                            oops_arch != OOPS_SPARC64) || !sparc_regdump) {
-                               fprintf(stderr,
-                                       "Warning, Code line not seen, dumping "
-                                       "what data is available\n");
-                               ++warnings;
-                       }
-                       Oops_format(&ss_format);
-                       ss_free(&ss_format);
-                       if (one_shot)
-                               return(0);
-               }
-       } while (filecount != 0);
-
-       for (i = 0; i < sizeof(string); ++i) {
-               free(string[i]);
-               string[i] = NULL;
-       }
-       free(line);
-       if (one_shot)
-               return(3);      /* one shot mode, end of input, no data */
-       return(0);
-}
diff --git a/scripts/ksymoops/re.c b/scripts/ksymoops/re.c
deleted file mode 100644 (file)
index 9c65832..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
-       re.c.
-
-       Regular expression processing for ksymoops.
-
-       Copyright Keith Owens <kaos@ocs.com.au>.
-       Released under the GNU Public Licence, Version 2.
-
-       Tue Nov  3 02:31:01 EST 1998
-       Version 0.6
-       PPC trace addresses are not bracketed, add new re.
-
-       Wed Oct 28 13:47:23 EST 1998
-       Version 0.4
-       Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-#include <string.h>
-
-/* Compile a regular expression */
-void re_compile(regex_t *preg, const char *regex, int cflags,
-               regmatch_t **pmatch)
-{
-       int i, l;
-       char *p;
-       static char const procname[] = "re_compile";
-
-       if (preg->re_nsub)
-               return;         /* already compiled */
-
-       if (debug)
-               fprintf(stderr, "DEBUG: %s '%s'", procname, regex);
-       if ((i = regcomp(preg, regex, cflags))) {
-               l = regerror(i, preg, NULL, 0);
-               ++l;    /* doc is ambiguous, be safe */
-               p = malloc(l);
-               if (!p)
-                       malloc_error("regerror text");
-               regerror(i, preg, p, l);
-               fprintf(stderr,
-                       "%s: fatal %s error on '%s' - %s\n",
-                       prefix, procname, regex, p);
-               exit(2);
-       }
-       if (debug)
-               fprintf(stderr, " %d sub expression(s)\n", preg->re_nsub);
-       /* [0] is entire match, [1] is first substring */
-       *pmatch = malloc((preg->re_nsub+1)*sizeof(**pmatch));
-       if (!*pmatch)
-               malloc_error("pmatch");
-
-}
-
-/* Compile common regular expressions */
-void re_compile_common(void)
-{
-
-       /* nm: address, type, symbol */
-       re_compile(&re_nm,
-               "^([0-9a-fA-F]{4,}) +([^ ]) +([^ ]+)$",
-               REG_NEWLINE|REG_EXTENDED,
-               &re_nm_pmatch);
-
-       /* bracketed address preceded by optional white space */
-       re_compile(&re_bracketed_address,
-               "^[ \t]*" BRACKETED_ADDRESS,
-               REG_NEWLINE|REG_EXTENDED,
-               &re_bracketed_address_pmatch);
-
-       /* unbracketed address preceded by optional white space */
-       re_compile(&re_unbracketed_address,
-               "^[ \t*]*" UNBRACKETED_ADDRESS,
-               REG_NEWLINE|REG_EXTENDED,
-               &re_unbracketed_address_pmatch);
-
-}
-
-/* Split text into the matching re substrings - Perl is so much easier :).
- * Each element of *string is set to a malloced copy of the substring or
- * NULL if the substring did not match (undef).  A zero length substring match
- * is represented by a zero length **string.
- */
-void re_strings(regex_t *preg, const char *text, regmatch_t *pmatch,
-               char ***string)
-{
-       int i;
-       if (!*string) {
-               *string = malloc((preg->re_nsub+1)*sizeof(**string));
-               if (!*string)
-                       malloc_error("re_strings base");
-               for (i = 0; i < preg->re_nsub+1; ++i)
-                       (*string)[i] = NULL;
-       }
-       for (i = 0; i < preg->re_nsub+1; ++i) {
-               if (debug > 4)
-                       fprintf(stderr,
-                               "DEBUG: re_string %d offsets %d %d",
-                               i, pmatch[i].rm_so, pmatch[i].rm_eo);
-               if (pmatch[i].rm_so == -1) {
-                       /* no match for this sub expression */
-                       free((*string)[i]);
-                       (*string)[i] = NULL;
-                       if (debug > 4)
-                               fprintf(stderr, " (undef)\n");
-               }
-               else {
-                       int l = pmatch[i].rm_eo - pmatch[i].rm_so + 1;
-                       char *p;
-                       p = malloc(l);
-                       if (!p)
-                               malloc_error("re_strings");
-                       strncpy(p, text+pmatch[i].rm_so, l-1);
-                       *(p+l-1) = '\0';
-                       (*string)[i] = p;
-                       if (debug > 4)
-                               fprintf(stderr, " '%s'\n", p);
-               }
-       }
-}
-
-/* Free the matching re substrings */
-void re_strings_free(const regex_t *preg, char ***string)
-{
-       if (*string) {
-               int i;
-               for (i = 0; i < preg->re_nsub+1; ++i)
-                       free((*string)[i]);
-               free(*string);
-               *string = NULL;
-       }
-}
-
-/* Check that there are enough strings for an re */
-void re_string_check(int need, int available, const char *msg)
-{
-       if (need > available) {
-               fprintf(stderr,
-                       "%s: fatal not enough re_strings in %s.  "
-                       "Need %d, available %d\n",
-                       prefix, msg, need, available);
-               exit(2);
-       }
-}
diff --git a/scripts/ksymoops/symbol.c b/scripts/ksymoops/symbol.c
deleted file mode 100644 (file)
index 5c66cc9..0000000
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
-       symbol.c.
-
-       Symbol handling routines for ksymoops.
-
-       Copyright Keith Owens <kaos@ocs.com.au>.
-       Released under the GNU Public Licence, Version 2.
-
-       Mon Jan  4 09:08:19 EST 1999
-       Version 0.6d
-       Cast Version to int, glibc 2.1 made elf_addr_t a long.
-
-       Tue Nov  3 02:31:01 EST 1998
-       Version 0.6
-       Fix end of code calculation.
-
-       Wed Oct 28 13:47:23 EST 1998
-       Version 0.4
-       Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <errno.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Initialise a symbol source */
-void ss_init(SYMBOL_SET *ss, const char *msg)
-{
-       memset(ss, '\0', sizeof(*ss));
-       ss->source = strdup(msg);
-       if (!ss->source)
-               malloc_error(msg);
-}
-
-/* Free dynamic data from a symbol source */
-void ss_free(SYMBOL_SET *ss)
-{
-       int i;
-       SYMBOL *s;
-       for (s = ss->symbol, i = 0; i < ss->used; ++i, ++s)
-               free(s->name);
-       free(ss->symbol);
-       free(ss->source);
-       memset(ss, '\0', sizeof(*ss));
-}
-
-/* Initialise common symbol sets */
-void ss_init_common(void)
-{
-       ss_init(&ss_Version, "Version_");
-}
-
-/* Find a symbol name in a symbol source.  Brute force ascending order search,
- * no hashing.  If start is not NULL, it contains the starting point for the
- * scan and is updated to point to the found entry.  If the entry is not found,
- * return NULL with start pointing to the next highest entry.
- * NOTE: Assumes that ss is sorted by name.
- */
-SYMBOL *find_symbol_name(const SYMBOL_SET *ss, const char *symbol, int *start)
-{
-       int i, l;
-       SYMBOL *s;
-       for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
-               if ((l = strcmp(symbol, s->name)) == 0) {
-                       if (start)
-                               *start = i;
-                       return(s);
-               }
-               if (l < 0)
-                       break;
-       }
-       if (start)
-               *start = i;
-       return NULL;
-}
-
-/* Find an address in a symbol source.  Brute force ascending order search, no
- * hashing.  If start is not NULL, it contains the starting point for the scan
- * and is updated to point to the found entry.  If the entry is not found,
- * return NULL with start pointing to the next highest entry.
- * NOTE: Assumes that ss is sorted by address.
- */
-static SYMBOL *find_symbol_address(const SYMBOL_SET *ss,
-                           const elf_addr_t address, int *start)
-{
-       int i;
-       SYMBOL *s;
-       for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
-               if (address > s->address)
-                       continue;
-               else if (address == s->address) {
-                       if (start)
-                               *start = i;
-                       return(s);
-               }
-               else
-                       break;
-       }
-       if (start)
-               *start = i;
-       return NULL;
-}
-
-/* Add a symbol to a symbol set, address in binary */
-void add_symbol_n(SYMBOL_SET *ss, const elf_addr_t address,
-                 const char type, const char keep, const char *symbol)
-{
-       int i;
-       char **string = NULL;
-       SYMBOL *s;
-       static regex_t     re_symbol_ver;
-       static regmatch_t *re_symbol_ver_pmatch;
-       static const char procname[] = "add_symbol_n";
-
-       /* Strip out any trailing symbol version _Rxxxxxxxx. */
-       re_compile(&re_symbol_ver,
-               "^(.*)_R[0-9a-fA-F]{8,}$",
-               REG_NEWLINE|REG_EXTENDED,
-               &re_symbol_ver_pmatch);
-
-       i = regexec(&re_symbol_ver, symbol,
-                   re_symbol_ver.re_nsub+1, re_symbol_ver_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-       if (i == 0)
-               re_strings(&re_symbol_ver, symbol, re_symbol_ver_pmatch,
-                       &string);
-
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s %s %s '%c' %d '%s'\n",
-                       procname, ss->source, format_address(address),
-                       type, keep, i == 0 ? string[1] : symbol);
-       if (ss->used > ss->alloc) {
-               fprintf(stderr,
-                       "%s: fatal %s ss %s used (%d) > alloc (%d)\n",
-                       procname, prefix, ss->source, ss->used, ss->alloc);
-               exit(2);
-       }
-       if (ss->used == ss->alloc) {
-               /* increase by 20% or 10, whichever is larger, arbitrary */
-               int newsize = ss->alloc*120/100;
-               if (newsize < ss->alloc+10)
-                       newsize = ss->alloc+10;
-               if (debug > 3)
-                       fprintf(stderr,
-                               "DEBUG: %s increasing %s from %d to %d "
-                               "entries\n",
-                               procname, ss->source, ss->alloc, newsize);
-               ss->symbol = realloc(ss->symbol, newsize*sizeof(*(ss->symbol)));
-               if (!ss->symbol)
-                       malloc_error("realloc ss");
-               ss->alloc = newsize;
-       }
-       s = ss->symbol+ss->used;
-       if (i == 0) {
-               s->name = string[1];
-               string[1] = NULL;       /* don't free this one */
-       }
-       else {
-               s->name = strdup(symbol);
-               if (!s->name)
-                       malloc_error("strdup symbol");
-       }
-       s->type = type;
-       s->keep = keep;
-       s->address = address;
-       ++ss->used;
-       re_strings_free(&re_symbol_ver, &string);
-}
-
-/* Add a symbol to a symbol set, address in character */
-void add_symbol(SYMBOL_SET *ss, const char *address, const char type,
-               const char keep, const char *symbol)
-{
-       elf_addr_t a;
-       static char const procname[] = "add_symbol";
-       errno = 0;
-       a = strtoul(address, NULL, 16);
-       if (errno) {
-               fprintf(stderr,
-                       "%s: %s address '%s' is in error",
-                       prefix, procname, address);
-               perror(" ");
-               ++errors;
-       }
-       add_symbol_n(ss, a, type, 1, symbol);
-}
-
-/* Map an address to symbol, offset and length, address in binary */
-char *map_address(const SYMBOL_SET *ss, const elf_addr_t address)
-{
-       int i = 0, l;
-       SYMBOL *s;
-       static char *map = NULL;
-       static int size = 0;
-       static const char procname[] = "map_address_n";
-
-       if (debug > 2)
-               fprintf(stderr, "DEBUG: %s %s %s\n",
-                       procname, ss->source, format_address(address));
-       s = find_symbol_address(ss, address, &i);
-       if (!s && --i >= 0)
-               s = ss->symbol+i;       /* address is between s and s+1 */
-                       
-       /* Extra map text is always < 100 bytes */
-       if (s)
-               l = strlen(s->name) + 100;
-       else
-               l = 100;
-       if (l > size) {
-               map = realloc(map, l);
-               if (!map)
-                       malloc_error(procname);
-               size = l;
-       }
-       if (!s) {
-               if (ss->used == 0)
-                       snprintf(map, size, "No symbols available");
-               else
-                       snprintf(map, size, "Before first symbol");
-       }
-       else if ((i+1) >= ss->used) {
-               /* Somewhere past last symbol.  Length of last section of code
-                * is unknown, arbitrary cutoff at 32K.
-                */
-               elf_addr_t offset = address - s->address;
-               if (offset > 32768)
-                       snprintf(map, size, "<END_OF_CODE+%lx/????>", offset);
-               else
-                       snprintf(map, size, "<%s+%lx/????>", s->name, offset);
-       }
-       else
-               snprintf(map, size,
-                       "<%s+%lx/%lx>",
-                       s->name, address - s->address,
-                       (s+1)->address - s->address);
-       return(map);
-}
-
-/* After sorting, obsolete symbols are at the top.  Delete them. */
-static void ss_compress(SYMBOL_SET *ss)
-{
-       int i, j;
-       SYMBOL *s;
-       static const char procname[] = "ss_compress";
-
-       if (debug > 1)
-               fprintf(stderr, "DEBUG: %s on table %s, before %d ",
-                       procname, ss->source, ss->used);
-       for (i = 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
-               if (!s->keep) {
-                       for (j = i; j < ss->used; ++j, ++s) {
-                               if (s->keep) {
-                                       fprintf(stderr,
-                                               "%s: fatal %s table %s is not "
-                                               "sorted\n",
-                                               prefix, procname, ss->source);
-                                       exit(2);
-                               }
-                       }
-                       break;
-               }
-       }
-       for (j = i, s = ss->symbol+j; j < ss->used; ++j, ++s)
-               free(s->name);
-       ss->used = i;
-       if (debug > 1)
-               fprintf(stderr, "after %d\n", ss->used);
-}
-
-static int ss_compare_atn(const void *a, const void *b)
-{
-       SYMBOL *c = (SYMBOL *) a;
-       SYMBOL *d = (SYMBOL *) b;
-       int i;
-
-       /* obsolete symbols to the top */
-       if (c->keep != d->keep)
-               return(d->keep - c->keep);
-       if (c->address > d->address)
-               return(1);
-       if (c->address < d->address)
-               return(-1);
-       if (c->type > d->type)
-               return(1);
-       if (c->type < d->type)
-               return(-1);
-       if ((i = strcmp(c->name, d->name)))
-               return(i);
-       return(0);
-}
-
-/* Sort a symbol set by address, type and name */
-void ss_sort_atn(SYMBOL_SET *ss)
-{
-       if (debug)
-               fprintf(stderr, "DEBUG: sorting symbols for %s (atn)\n",
-                       ss->source);
-       qsort((char *) ss->symbol, (unsigned) ss->used,
-               sizeof(*(ss->symbol)), ss_compare_atn);
-       ss_compress(ss);
-}
-
-static int ss_compare_na(const void *a, const void *b)
-{
-       SYMBOL *c = (SYMBOL *) a;
-       SYMBOL *d = (SYMBOL *) b;
-       int i;
-
-       /* obsolete symbols to the top */
-       if (c->keep != d->keep)
-               return(d->keep - c->keep);
-       if ((i = strcmp(c->name, d->name)))
-               return(i);
-       if (c->address > d->address)
-               return(1);
-       if (c->address < d->address)
-               return(-1);
-       return(0);
-}
-
-/* Sort a symbol set by name and address, drop duplicates.  There should be
- * no duplicates but I have seen duplicates in ksyms on 2.0.35.
- */
-void ss_sort_na(SYMBOL_SET *ss)
-{
-       int i;
-       SYMBOL *s;
-       if (debug)
-               fprintf(stderr, "DEBUG: sorting symbols for %s (na)\n",
-                       ss->source);
-       qsort((char *) ss->symbol, (unsigned) ss->used,
-               sizeof(*(ss->symbol)), ss_compare_na);
-       ss_compress(ss);
-       s = ss->symbol;
-       for (i = 0; i < ss->used-1; ++i) {
-               if (strcmp(s->name, (s+1)->name) == 0 &&
-                   s->address == (s+1)->address) {
-                       if (s->type != ' ')
-                               (s+1)->keep = 0;
-                       else
-                               s->keep = 0;
-               }
-               ++s;
-       }
-       qsort((char *) ss->symbol, (unsigned) ss->used,
-               sizeof(*(ss->symbol)), ss_compare_na);
-       ss_compress(ss);
-}
-
-/* Copy a symbol set, including all its strings */
-SYMBOL_SET *ss_copy(const SYMBOL_SET *ss)
-{
-       SYMBOL_SET *ssc;
-       if (debug > 3)
-               fprintf(stderr,
-                       "DEBUG: ss_copy %s\n", ss->source);
-       ssc = malloc(sizeof(*ssc));
-       if (!ssc)
-               malloc_error("copy ssc");
-       ss_init(ssc, ss->source);
-       ssc->used = ss->used;
-       ssc->alloc = ss->used;  /* shrink the copy */
-       ssc->symbol = malloc(ssc->used*sizeof(*(ssc->symbol)));
-       if (!(ssc->symbol))
-               malloc_error("copy ssc symbols");
-       memcpy(ssc->symbol, ss->symbol, ssc->used*sizeof(*(ssc->symbol)));
-       return(ssc);
-}
-
-/* Convert version number to major, minor string.  */
-static const char *format_Version(elf_addr_t Version)
-{
-       static char string[12]; /* 255.255.255\0 worst case */
-       snprintf(string, sizeof(string), "%d.%d.%d",
-               (int) ((Version >> 16) & 0xff),
-               (int) ((Version >> 8) & 0xff),
-               (int) ((Version) & 0xff));
-       return(string);
-}
-
-/* Save version number.  The "address" is the version number, the "symbol" is
- * the source of the version.
- */
-void add_Version(const char *version, const char *source)
-{
-       static char const procname[] = "add_Version";
-       int i = atoi(version);
-       if (debug > 1)
-               fprintf(stderr, "DEBUG: %s %s %s %s\n",
-                       procname, source, version, format_Version(i));
-       add_symbol_n(&ss_Version, i, 'V', 1, source);
-}
-
-/* Extract Version_ number from a symbol set and save it.  */
-void extract_Version(SYMBOL_SET *ss)
-{
-       int i = 0;
-       SYMBOL *s;
-
-       s = find_symbol_name(ss, "Version_", &i);
-       if (!s && i < ss->used)
-               s = ss->symbol+i;       /* first symbol after "Version_" */
-       if (!s || strncmp(s->name, "Version_", 8))
-               return;
-       add_Version(s->name+8, ss->source);
-}
-
-/* Compare all extracted Version numbers.  Silent unless there is a problem. */
-void compare_Version(void)
-{
-       int i = 0;
-       SYMBOL *s, *s0;
-       static int prev_used = 0;
-
-       if (!ss_Version.used)
-               return;
-       /* Only check if the Version table has changed in size */
-       if (prev_used == ss_Version.used)
-               return;
-
-       ss_sort_na(&ss_Version);
-       s0 = s = ss_Version.symbol;
-       if (debug)
-               fprintf(stderr, "DEBUG: Version %s\n",
-                       format_Version(s0->address));
-       for (i = 0; i < ss_Version.used; ++i, ++s) {
-               if (s->address != s0->address) {
-                       fprintf(stderr,
-                               "Version mismatch error.  %s says %s, ",
-                               s0->name,
-                               format_Version(s0->address));
-                       fprintf(stderr,
-                               "%s says %s.  Expect lots of address "
-                               "mismatches.\n",
-                               s->name,
-                               format_Version(s->address));
-                       ++errors;
-               }
-       }
-       prev_used = ss_Version.used;
-}