]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.0pre5 2.2.0pre5
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:58 +0000 (15:17 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:17:58 +0000 (15:17 -0500)
Oh, well.. Based on what the arca-[678] patches did, there's now a pre-5
out there. Not very similar, but it should incorporate the basic idea:
namely much more aggressively asynchronous swap-outs from a process
context.
Comment away,
                Linus

176 files changed:
CREDITS
Documentation/Configure.help
Documentation/ide.txt
Documentation/kernel-docs.txt
Documentation/networking/ip-sysctl.txt
Documentation/oops-tracing.txt
Documentation/sound/AWE32
Documentation/sound/OPL3-SA2
MAINTAINERS
Makefile
arch/i386/config.in
arch/i386/kernel/ptrace.c
arch/i386/kernel/smp.c
arch/m68k/Makefile
arch/m68k/config.in
arch/m68k/kernel/m68k_defs.h
arch/m68k/kernel/m68k_ksyms.c
arch/m68k/kernel/process.c
arch/m68k/kernel/ptrace.c
arch/m68k/mac/config.c
arch/m68k/mac/debug.c
arch/m68k/mac/macboing.c
arch/m68k/mac/macints.c
arch/m68k/vmlinux.lds
arch/mips/kernel/traps.c
arch/ppc/common_defconfig
arch/ppc/defconfig
arch/ppc/kernel/process.c
arch/ppc/kernel/traps.c
arch/ppc/mm/fault.c
arch/ppc/pmac_defconfig
drivers/block/cmd640.c
drivers/block/genhd.c
drivers/block/ide-disk.c
drivers/block/ide-probe.c
drivers/block/ide-tape.c
drivers/block/ide.c
drivers/block/opti621.c
drivers/block/rz1000.c
drivers/cdrom/cdrom.c
drivers/char/cyclades.c
drivers/char/mem.c
drivers/char/serial.c
drivers/isdn/hisax/config.c
drivers/net/acenic_firmware.h
drivers/net/plip.c
drivers/net/sdla_fr.c
drivers/net/sdla_ppp.c
drivers/net/sdla_x25.c
drivers/net/tulip.c
drivers/pci/oldproc.c
drivers/scsi/README.aic7xxx
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx_proc.c
drivers/scsi/scsi.c
drivers/sound/Config.in
drivers/sound/Makefile
drivers/sound/ad1848.c
drivers/sound/dev_table.c
drivers/sound/dmasound.c
drivers/sound/es1370.c
drivers/sound/es1371.c
drivers/sound/msnd_pinnacle.c
drivers/sound/opl3sa.c
drivers/sound/opl3sa2.c
drivers/sound/pas2_card.c
drivers/sound/pas2_midi.c
drivers/sound/sb.h
drivers/sound/sb_audio.c
drivers/sound/sb_common.c
drivers/sound/sb_mixer.c
drivers/sound/sb_mixer.h
drivers/sound/sonicvibes.c
drivers/sound/sound_calls.h
drivers/sound/sound_core.c
drivers/sound/sound_firmware.c
drivers/sound/sound_syms.c
drivers/sound/wavfront.c
drivers/sound/wf_midi.c
drivers/video/atyfb.c
drivers/video/chipsfb.c
drivers/video/matroxfb.c
drivers/video/offb.c
fs/Config.in
fs/buffer.c
fs/dcache.c
fs/fat/inode.c
fs/inode.c
fs/lockd/clntlock.c
fs/nfs/inode.c
fs/ntfs/ntfsendian.h
fs/proc/array.c
fs/qnx4/symlinks.c
fs/ufs/acl.c
fs/ufs/namei.c
fs/ufs/super.c
fs/vfat/namei.c
include/asm-m68k/init.h
include/asm-m68k/resource.h
include/asm-m68k/softirq.h
include/asm-m68k/timex.h
include/asm-m68k/uaccess.h
include/linux/inetdevice.h
include/linux/ip_masq.h
include/linux/mm.h
include/linux/ntfs_fs_i.h
include/linux/pci.h
include/linux/sched.h
include/linux/sound.h
include/linux/swap.h
include/linux/sysctl.h
include/linux/wavefront.h
include/net/ipconfig.h
ipc/util.c
kernel/ksyms.c
kernel/sched.c
kernel/sysctl.c
mm/filemap.c
mm/memory.c
mm/page_alloc.c
mm/vmscan.c
net/TUNABLE
net/appletalk/ddp.c
net/ax25/af_ax25.c
net/bridge/br.c
net/ipv4/Config.in
net/ipv4/Makefile
net/ipv4/af_inet.c
net/ipv4/devinet.c
net/ipv4/fib_frontend.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/ip_fw.c
net/ipv4/ip_masq.c
net/ipv4/ip_masq_mfw.c [new file with mode: 0644]
net/ipv4/ip_masq_portfw.c
net/ipv4/ip_output.c
net/ipv4/ipconfig.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv6/af_inet6.c
net/ipx/af_ipx.c
net/ipx/af_spx.c
net/lapb/lapb_iface.c
net/socket.c
net/unix/af_unix.c
scripts/ksymoops-0.6/Makefile [deleted file]
scripts/ksymoops-0.6/README [deleted file]
scripts/ksymoops-0.6/io.c [deleted file]
scripts/ksymoops-0.6/ksymoops.c [deleted file]
scripts/ksymoops-0.6/ksymoops.h [deleted file]
scripts/ksymoops-0.6/ksyms.c [deleted file]
scripts/ksymoops-0.6/map.c [deleted file]
scripts/ksymoops-0.6/misc.c [deleted file]
scripts/ksymoops-0.6/object.c [deleted file]
scripts/ksymoops-0.6/oops.c [deleted file]
scripts/ksymoops-0.6/patches/README [deleted file]
scripts/ksymoops-0.6/patches/mips [deleted file]
scripts/ksymoops-0.6/patches/ppc [deleted file]
scripts/ksymoops-0.6/re.c [deleted file]
scripts/ksymoops-0.6/symbol.c [deleted file]
scripts/ksymoops/Makefile [new file with mode: 0644]
scripts/ksymoops/README [new file with mode: 0644]
scripts/ksymoops/io.c [new file with mode: 0644]
scripts/ksymoops/ksymoops.c [new file with mode: 0644]
scripts/ksymoops/ksymoops.h [new file with mode: 0644]
scripts/ksymoops/ksyms.c [new file with mode: 0644]
scripts/ksymoops/map.c [new file with mode: 0644]
scripts/ksymoops/misc.c [new file with mode: 0644]
scripts/ksymoops/object.c [new file with mode: 0644]
scripts/ksymoops/oops.c [new file with mode: 0644]
scripts/ksymoops/re.c [new file with mode: 0644]
scripts/ksymoops/symbol.c [new file with mode: 0644]
scripts/tkgen.c

diff --git a/CREDITS b/CREDITS
index f01f7d4d7c5c05204fb0f1a0bea76adcab2d956b..3c603eb20744ac285215f3cb44198183dc26f80a 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1150,8 +1150,8 @@ D: NTFS driver
 
 N: Mark Lord
 E: mlord@pobox.com
-D: Author of IDE driver (ide.c), hd.c support
-D: Triton Bus Master IDE driver
+D: EIDE driver, hd.c support
+D: EIDE PCI and bus-master DMA support
 D: Hard Disk Parameter (hdparm) utility
 S: 33 Ridgefield Cr
 S: Nepean, Ontario
index a370ced88791b80240986fd84ed59e996c3b6334..ed841b46451b39ff99818b84400634543b57ab5d 100644 (file)
@@ -3604,17 +3604,25 @@ CONFIG_SCSI_AHA1740
 Adaptec AIC7xxx chipset SCSI controller support
 CONFIG_SCSI_AIC7XXX
   This is support for the various aic7xxx based Adaptec SCSI
-  controllers. These include the 274x EISA cards, 284x VLB cards, 294x
-  PCI cards, 394x PCI cards, 3985 PCI card, and several versions of
-  the Adaptec built-in SCSI controllers on various PC motherboards.
+  controllers. These include the 274x EISA cards; 284x VLB cards; 2902,
+  2910, 293x, 294x, 394x, 3985 and several other PCI and motherboard based
+  SCSI controllers from Adaptec.  It does not support the AAA-13x RAID
+  controllers from Adaptec, nor will it likely ever support them.  It
+  does not support the 2920 cards from Adaptec that use the Future Domain
+  SCSI controller chip.  For those cards, you need the "Future Domain
+  16xx SCSI support" driver.
+
+  In general, if the controller is based on an Adaptec SCSI controller
+  chip from the aic777x series or the aic78xx series, it should work.  The
+  only exception is the 7810 which is specifically not supported (that's the
+  RAID controller chip on the AAA-13x cards).
+
   Information on the configuration options for this controller can be
   found by checking the help file for each of the available
-  configuration options. You also want to read
-  drivers/scsi/README.aic7xxx and the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
-  Note that the AHA2920 SCSI host adapter is *not* supported by this
-  driver; choose "Future Domain 16xx SCSI support" instead if you have
-  one of those.
+  configuration options. You should read drivers/scsi/README.aic7xxx
+  at a minimum before contacting the maintainer with any questions.  
+  The SCSI-HOWTO, available via FTP (user: anonymous) at
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO can also be of great help.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3626,15 +3634,9 @@ CONFIG_OVERRIDE_CMDS
   Say Y here if you want to override the default maximum number of
   commands that a single device on the aic7xxx controller is allowed
   to have active at one time. This option only affects tagged queueing
-  capable devices. The driver uses a "failsafe" value of 8 by default.
-  This is much lower than many devices can handle, but left in place
-  for safety's sake. If you say Y here, you can adjust the number of
-  commands per LUN with the following configuration option.
-  
-  NOTE: This does not actually enable tagged queueing on any
-  particular device. The driver has changed in this respect. Please
-  see the file drivers/scsi/README.aic7xxx for more information on how
-  to get particular devices to use tagged command queueing.
+  capable devices. The driver uses a value of 24 by default.
+  If you say Y here, you can adjust the number of commands per LUN
+  with the following configuration option.
   
   If unsure, say N.
 
@@ -3771,16 +3773,21 @@ CONFIG_SCSI_U14_34F
 
 enable elevator sorting
 CONFIG_SCSI_U14_34F_LINKED_COMMANDS
-  This is a feature of SCSI-2 which improves performance: the host
-  adapter can send a whole list of commands to a device in one
-  batch. Some SCSI devices might not implement this properly, so the
-  safe answer is N.
+  This option enables elevator sorting for all probed SCSI disks and 
+  CDROMs. It definetly reduces the average seek distance when doing
+  random seeks, but this does not necessarily results in a noticeable
+  performance improvement: your mileage may vary...
+  The safe answer is N.
 
 maximum number of queued commands
 CONFIG_SCSI_U14_34F_MAX_TAGS
-  This specifies how many SCSI commands can be maximally queued for a
-  given SCSI device. Go with the default unless you know what you're
-  doing. Minimum is 2 and maximum is 8.
+  This specifies how many SCSI commands can be maximally queued for each
+  probed SCSI device. You should reduce the default value of 8 only if
+  you have disks with buggy or limited tagged command support.
+  Minimum is 2 and maximum is 14. This value is also the window size
+  used by the elevator sorting option above.
+  The effective value used by the driver for each probed SCSI device is 
+  reported at boot time.
 
 Future Domain 16xx SCSI/AHA-2920A support
 CONFIG_SCSI_FUTURE_DOMAIN
@@ -4237,13 +4244,13 @@ CONFIG_SCSI_7000FASST
 
 EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support
 CONFIG_SCSI_EATA
-  This driver supports all the EATA/DMA-compliant SCSI host adapters
-  and does not need any BIOS32 service. DPT ISA and all EISA i/o
-  addresses are probed looking for the "EATA" signature. If you said Y
-  to "PCI BIOS support", the addresses of all the PCI SCSI controllers
-  reported by BIOS32 are probed as well. You want to read the start of
-  drivers/scsi/eata.c and the SCSI-HOWTO, available via FTP (user:
-  anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  This driver supports all the EATA/DMA-compliant SCSI host adapters.
+  DPT ISA and all EISA i/o addresses are probed looking for the "EATA"
+  signature. If you said Y to "PCI support", the addresses of all the 
+  PCI SCSI controllers reported by the PCI subsystem are probed as well.
+  You want to read the start of drivers/scsi/eata.c and the SCSI-HOWTO,
+  available via FTP (user: anonymous) at 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Note that there is also another driver for the same hardware
   available: "EATA-DMA support". You should say Y to only one of them.
@@ -4257,22 +4264,27 @@ enable tagged command queuing
 CONFIG_SCSI_EATA_TAGGED_QUEUE
   This is a feature of SCSI-2 which improves performance: the host
   adapter can send several SCSI commands to a device's queue even if
-  previous commands haven't finished yet. Some SCSI devices don't
-  implement this properly, so the safe answer is N.
+  previous commands haven't finished yet. Most EATA adapters negotiate
+  this feature automatically with the device, even if your answer is N.
+  The safe answer is N.
         
 enable elevator sorting
 CONFIG_SCSI_EATA_LINKED_COMMANDS
-  This is a feature of SCSI-2 which improves performance: the host
-  adapter can send a whole list of commands to a device in one
-  batch. Some SCSI devices might not implement this properly, so the
-  safe answer is N.
+  This option enables elevator sorting for all probed SCSI disks and 
+  CDROMs. It definetly reduces the average seek distance when doing
+  random seeks, but this does not necessarily results in a noticeable
+  performance improvement: your mileage may vary...
+  The safe answer is N.
 
 maximum number of queued commands
 CONFIG_SCSI_EATA_MAX_TAGS
-  This specifies how many SCSI commands can be maximally queued for a
-  given SCSI device. Go with the default unless you know what you're
-  doing. Minimum is 2 and maximum is 16. This number will only have an
-  effect if you said Y to "enable tagged command queuing", above.
+  This specifies how many SCSI commands can be maximally queued for each
+  probed SCSI device. You should reduce the default value of 16 only if
+  you have disks with buggy or limited tagged command support.
+  Minimum is 2 and maximum is 62. This value is also the window size
+  used by the elevator sorting option above.
+  The effective value used by the driver for each probed SCSI device is 
+  reported at boot time.
 
 NCR53c406a SCSI support
 CONFIG_SCSI_NCR53C406A
index bd7c023896bc223f84e51e8c11190f89449ee916..866a3a9097fa1a76befce7e4ca500df359970655 100644 (file)
@@ -1,9 +1,5 @@
-ide.txt -- Information regarding the Enhanced IDE drive in Linux 2.1.68+
+ide.txt -- Information regarding the Enhanced IDE drive in Linux 2.1/2.2
 ===============================================================================
-Supported by:
-       Mark Lord    <mlord@pobox.com>          -- disks, interfaces, probing
-       Gadi Oxman   <gadio@netvision.net.il>   -- tapes, disks, whatever
-       Scott Snyder <snyder@fnald0.fnal.gov>   -- cdroms, ATAPI, audio
 
    +-----------------------------------------------------------------+
    |  The hdparm utility for controlling various IDE features is     |
@@ -12,7 +8,7 @@ Supported by:
 
 See description later on below for handling BIG IDE drives with >1024 cyls.
 
-Major features of the 2.1.xx IDE driver ("NEW!" marks changes since 2.0.xx):
+Major features of the 2.1/2.2 IDE driver ("NEW!" marks changes since 2.0.xx):
 
 NEW!   - support for IDE ATAPI *floppy* drives
        - support for IDE ATAPI *tape* drives, courtesy of Gadi Oxman
@@ -69,10 +65,9 @@ NEW! - generic PCI Bus-Master DMA support
 NEW!           - works with most Pentium PCI systems, chipsets, add-on cards
 NEW!           - works with regular DMA as well as Ultra DMA
 NEW!           - automatically probes for all PCI IDE interfaces
+NEW!   - generic support for using BIOS-configured Ultra-DMA (UDMA) transfers
 
 
-For work in progress, see the comments in ide.c, ide-cd.c, triton.c, ...
-
 ***  IMPORTANT NOTICES:  BUGGY IDE CHIPSETS CAN CORRUPT DATA!!
 ***  =================
 ***  PCI versions of the CMD640 and RZ1000 interfaces are now detected
@@ -98,24 +93,26 @@ For work in progress, see the comments in ide.c, ide-cd.c, triton.c, ...
 ***  Use of the "serialize" option is no longer necessary.
 
 This is the multiple IDE interface driver, as evolved from hd.c.
-It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
+It supports up to six IDE interfaces, on one or more IRQs (usually 14 & 15).
 There can be up to two drives per interface, as per the ATA-2 spec.
 
 Primary:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
 Secondary:  ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
 Tertiary:   ide2, port 0x1e8; major=33; hde is minor=0; hdf is minor=64
 Quaternary: ide3, port 0x168; major=34; hdg is minor=0; hdh is minor=64
+fifth..     ide4, usually PCI, probed
+sixth..     ide5, usually PCI, probed
 
-To access devices on the 2nd/3rd/4th interfaces, device entries must first be
+To access devices on interfaces > ide0, device entries must first be
 created in /dev for them.  To create such entries, simply run the included
 shell script:   /usr/src/linux/scripts/MAKEDEV.ide
 
-Apparently many releases of Slackware 2.2/2.3 have incorrect entries
+Apparently many older releases of Slackware had incorrect entries
 in /dev for hdc* and hdd* -- this can also be corrected by running MAKEDEV.ide
 
-ide.c automatically probes for the standard four IDE interfaces,
+ide.c automatically probes for most IDE interfaces (including all PCI ones),
 for the drives/geometries attached to those interfaces, and for the
-IRQ numbers being used by the interfaces (normally 14, 15, 11 and 10).
+IRQ numbers being used by the interfaces (normally 14, 15 for ide0/ide1).
 
 For special cases, interfaces may be specified using kernel "command line"
 options.  For example,
@@ -179,7 +176,7 @@ Many folks have had "trouble" with cdroms because of this requirement,
 so ide.c now probes for both units, though success is more likely
 when the drive is jumpered correctly.
 
-Courtesy of Scott Snyder, the driver supports ATAPI cdrom drives
+Courtesy of Scott Snyder and others, the driver supports ATAPI cdrom drives
 such as the NEC-260 and the new MITSUMI triple/quad speed drives.
 Such drives will be identified at boot time, just like a hard disk.
 
@@ -227,8 +224,8 @@ disabled by the BIOS.
 The kernel is able to execute binaries directly off of the cdrom,
 provided it is mounted with the default block size of 1024 (as above).
 
-Please pass on any feedback on the cdrom stuff to the author & maintainer,
-Scott Snyder (snyder@fnald0.fnal.gov).
+Please pass on any feedback on any of this stuff to the maintainer,
+whose address can be found in linux/MAINTAINERS.
 
 Note that if BOTH hd.c and ide.c are configured into the kernel,
 hd.c will normally be allowed to control the primary IDE interface.
@@ -256,8 +253,7 @@ driver using the "options=" keyword to insmod, while replacing any ',' with
 
        insmod ide.o options="ide0=serialize ide2=0x1e8;0x3ee;11"
 
-mlord@pobox.com
-snyder@fnald0.fnal.gov
+
 ================================================================================
 
 Summary of ide driver parameters for kernel "command line":
@@ -307,6 +303,7 @@ Summary of ide driver parameters for kernel "command line":
                                except the cmd640.
  "idex=serialize"      : do not overlap operations on idex and ide(x^1)
  "idex=reset"          : reset interface after probe
+ "idex=dma"            : automatically configure/use DMA if possible.
 
  The following are valid ONLY on ide0,
  and the defaults for the base,ctl ports must not be altered.
@@ -319,6 +316,8 @@ Summary of ide driver parameters for kernel "command line":
  "ide0=ali14xx"                : probe/support ali14xx chipsets (ALI M1439/M1445)
  "ide0=umc8672"                : probe/support umc8672 chipsets
 
+There may be more options than shown -- use the source, Luke!
+
 Everything else is rejected with a "BAD OPTION" message.
 
 ================================================================================
@@ -488,19 +487,19 @@ My recommendations to anyone who asks about NEW systems are:
 
         - buy a motherboard that uses the Intel Triton chipset -- very common.
         - use IDE for the first two drives, placing them on separate interfaces.
+               - very fast 7200rpm drives are now available
+               (though many problems have been reported with Seagate ones).
        - place the IDE cdrom drive as slave on either interface.
         - if additional disks are to be connected, consider your needs:
                 - fileserver?  Buy a SC200 SCSI adaptor for the next few drives.
                 - personal system?  Use IDE for the next two drives.
                 - still not enough?  Keep adding SC200 SCSI cards as needed.
 
-Most manufacturers make both IDE and SCSI-2 versions of each of their drives.
-The IDE ones are usually faster and cheaper, due to the higher data transfer
-speed of PIO mode4 (ATA2), 16.6MBytes/sec versus 10Mbytes/sec for SCSI-2.
-
-In particular, I recommend Quantum FireBalls as cheap and exceptionally fast.
-The new WD1.6GB models are also cheap screamers.
-
-For really high end systems, go for fast/wide 7200rpm SCSI.  But it'll cost ya!
+Most manufacturers make both IDE and SCSI versions of each of their drives.
+The IDE ones are usually as fast and cheaper, due to lower command overhead
+and the higher data transfer speed of UDMA2.  But fast/ultrawide/superlative
+SCSI is still king of the heap, especially for servers, if you've got the bucks.
 
 mlord@pobox.com
+--
+For current maintainers of this stuff, see the linux/MAINTAINERS file.
index 3b249fc30e8db5b5004c93a0a9a882de10fdb465..a3502bfc7ea58c4c1fc1689101c672d68b1707fa 100644 (file)
@@ -28,7 +28,7 @@
    
    PLEASE, if you know any paper not listed here or write a new document,
    send me an e-mail, and I'll include a reference to it here. Any
-   corrections, ideas or comments are also wellcomed.
+   corrections, ideas or comments are also welcomed.
    
    The papers that follow are listed in no particular order. All are
    catalogued with the following fields: the document's "Title", the
index 8d2aa9eaf10d7c3d04d8995e6af3bd1b1bddc2e9..bf89a87dc92219047f973092560ad0d74950d261 100644 (file)
@@ -211,4 +211,4 @@ kuznet@ms2.inr.ac.ru
 Updated by:
 Andi Kleen
 ak@muc.de
-$Id: ip-sysctl.txt,v 1.7 1998/05/02 12:05:00 davem Exp $
+$Id: ip-sysctl.txt,v 1.8 1999/01/02 16:37:06 davem Exp $
index 349d1a05f4d979c101a6685bb14d963faebb3fe3..108c3b645b626ee708ffa911071efd6855c3c44f 100644 (file)
@@ -1,9 +1,9 @@
 Quick Summary
 -------------
 
-cd /usr/src/linux/scripts
-g++ -o ksymoops ksymoops.cc
-./ksymoops ../System.map < the_oops.txt
+cd /usr/src/linux/scripts/ksymoops
+make ksymoops
+./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
index 25e04e2096ae0a6c31935d2be33871e7a1022628..a98ebe19f53c76c038d6db2d1ff41560cf65c98c 100644 (file)
@@ -6,21 +6,20 @@ SB32.
 1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This is 
 important, because the driver works only with real Creative cards.
 
-2) If your card is NOT "Plug-n-Play" (I myself don't know Creative AWE non 
-plug'n'play cards however) then go to 5th step now. In the other case
+2) If your card is NOT "Plug-n-Play" then go to 5th step now. In the other case
 proceed to step 3.
 
 3) You should obtain isapnptools. I looked through other PnP packages 
 for Linux, but all they are either in deep unstable beta/alpha releases or 
 they are much worse than isapnptools. In my case isapnptools were included in 
-a Linux distribution (Red Hat 5.0). If you also already have them then go to 
+a Linux distribution (Red Hat 5.x). If you also already have them then go to 
 step 4.
 
-The latest copy of isapnptools-1.15 is available from 
-ftp://ftp.demon.co.uk/pub/unix/linux/utils/ (I tested isapnptools-1.15.tgz)
+The latest copy of isapnptools-1.17 is available from 
+ftp://sunsite.unc.edu/pub/Linux/system/hardware/isapnptools-1.17.tgz
 You should gunzip/untar it to something like /usr/local/ 
-(cp isapnptools-1.15.tgz /usr/local/; cd /usr/local/;
-tar -xzf isapnptools-1.15.tgz). 
+(cp isapnptools-1.17.tgz /usr/local/; cd /usr/local/;
+tar -xzf isapnptools-1.17.tgz). 
 
 Compile the package (make) and install it (make install).
 If something goes wrong check the INSTALL file in isapnptools-1.15 directory.
@@ -59,26 +58,13 @@ Gameport and StereoEnhance are not required to be inited.
 Now you can execute "isapnp /etc/isapnp.conf". No errors should be reported.
 If you correctly installed isapnptools, then isapnp will run every boot time.
 
-5) Now you should recompile the kernel. I recommend using development kernels,
-because the AWE32 driver is included in them.  ATTENTION!  In kernels 2.1.102, 
-2.1.103, 2.1.104-pre1 and 2.1.104 (not the others) the lowlevel sound driver
-is not working. You should use the patch available at 
-http://members.xoom.com/yar/history.html. If you are using stable kernel
-releases 2.0.x, then get the latest version (3.8s9) of 
-OSS/Free at ftp://ftp.4front-tech.com/ossfree/ossfree38s9-linux20x.tar.gz
-and gunzip/untar it in /usr/src/ (assuming you keep your kernel source in
-/usr/src/linux).  Then go to /usr/src/linux/ and view the README file. That
-file contains info about kernel compilation and installation.
+5) Now you should recompile the kernel.
 
 In "make (x,menu)config" select in "Sound":
 "Sound card support", "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support",
 "Generic OPL2/OPL3 FM synthesizer support" and "FM synthesizer (YM3812/OPL-3) 
 support" as <M> (module).
 
-If you use kernel version 2.0.x or version 2.1.y (y <= 2.1.104) skip substep a,
-on 2.1.105 or later go through it.
-
-substep a:
 In "make (x,menu)config" select in "Sound":
 select "OSS sound modules" as <M> (module)
 
@@ -86,23 +72,23 @@ In "Additional low level sound drivers":
 "Additional low level sound drivers", "AWE32 synth" as <M> (module).
 Select "Additional low level sound drivers" as [y] (or [*] (yes)) (If it is not
 available as [y], select it as <M> (module))
-Now recompile the kernel (make dep; make (b)zImage; make modules; 
-make modules_install), update your boot loader and boot new kernel.
 
-6) Now download awesfx program from
-http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/index.html#Latest. Compile it.
-Copy sfxload program to /bin (or /sbin if you wish). To enable AWE midi 
+Now recompile the kernel (make dep; make (b)zImage, b(z)lilo, etc...;
+make modules; make modules_install), update your boot loader (if required) and
+boot new kernel.
+
+6) If awesfx program is not included in your distribution, then download it 
+from http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/index.html#Latest.
+Compile it. Copy sfxload program to /usr/bin. To enable AWE general midi
 synthesis you should also get the sound bank file for general midi from
-http://members.xoom.com/yar/synthgm.sbk.gz. Copy it to
-/usr and gunzip it there.
+http://members.xoom.com/yar/synthgm.sbk.gz. Copy it to /usr and gunzip it there.
 
-7) Edit /etc/rc.d/rc.local, inserting at the end of the file:
+7) Edit /etc/conf.modules, inserting at the end of the file:
 
-modprobe sound
-insmod uart401
-insmod sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
-insmod awe_wave
-sfxload /usr/synthfm.sbk
+alias sound sb
+alias midi awe_wave
+post-install awe_wave /usr/bin/sfxload /usr/synthfm.sbk
+options sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
 
 (on io=0xaaa irq=b.... you should use your own settings)
 That will enable the Sound Blaster and AWE wave synthesis.
@@ -110,13 +96,16 @@ That will enable the Sound Blaster and AWE wave synthesis.
 To play midi files you should get one of these programs:
 
 Playmidi 2.4 or higher: http://playmidi.openprojects.net
-Drvmidi 4.2.b: http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/index.html#Latest
+Drvmidi: http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/index.html#Latest
 
 (These are available at all major Linux FTP sites and may already be
  in your distribution)
+Remember to use -a switch if you have playmidi as a compiled binary (ex. RPM)
 
 If something goes wrong please e-mail me. All comments and suggestions are
 welcome.
 
                            Yaroslav Rosomakho (alons55@dialup.ptt.ru)
-                                   http://members.xoom.com/yar
+                                   http://www.yar.opennet.ru
+
+Last Updated: 3Jan99
index 5a50e16365c5872e52a660d31136670eee8609ca..1e3bf058253af52bd3f62d13fc5c49896a0b2398 100644 (file)
@@ -4,7 +4,7 @@ Documentation for the OPL3-SA2, SA3, and SAx driver (opl3sa2.o)
 Scott Murray, scottm@interlog.com
 December, 1998
 
-NOTE: All trademarked terms mentioned below are properties of their
+NOTE: All trade-marked terms mentioned below are properties of their
       respective owners.
 
 This driver is for PnP soundcards based on the following Yamaha audio
@@ -14,10 +14,10 @@ YMF711 aka OPL3-SA2
 YMF715 aka OPL3-SA3
 YMF719 aka OPL3-SAx (?)
 
-I'm a little fuzzy on what is classified a SAx, as I've seen the label
-used to refer to the whole 7xx family and as a specific identifier for
-the 719 on my no-name soundcard.  To make matters worse, there seem to
-be several reversions of the 715 chipset.
+I'm a little fuzzy on what exactly is classified a SAx, as I've seen
+the label used to refer to the whole 7xx family and as a specific
+identifier for the 719 on my no-name soundcard.  To make matters
+worse, there seem to be several revisions of the 715 chipset.
 
 Anyways, all of these chipsets implement the following devices:
 
@@ -35,18 +35,20 @@ Being PnP cards, some configuration is required.  There are two ways
 of doing this.  The most common is to use the isapnptools package to
 initialize the card, and use the kernel module form of the sound
 subsystem and sound drivers.  Alternatively, some BIOS's allow manual
-configuration of installed PnP devices in the BIOS menus, which should
+configuration of installed PnP devices in a BIOS menu, which should
 allow using the non-modular sound drivers, i.e. built into the kernel.
 
 I personally use isapnp and modules, and do not have access to a PnP
 BIOS machine to test.  If you have such a beast, try building both the
-MSS driver and this driver into the kernel (appropiately configured,
-of course) and let me know if it works.  If it does not, then email me
-if you are willing to experiment in an effort to make it work.
+MSS driver and this driver into the kernel (appropriately configured,
+of course).  I have received reports of this working, so it should be
+possible for most people with PnP BIOS.  If it does not work for you,
+then email me if you are willing to experiment in an effort to make it
+work.
 
 If you are using isapnp, follow the directions in its documentation to
-produce a configuration file.  Here is the relevant excerpt for my SAx
-card from my isapnp.conf:
+produce a configuration file.  Here is the relevant excerpt I use for
+my SAx card from my isapnp.conf:
 
 (CONFIGURE YMH0800/-1 (LD 0
 
@@ -80,11 +82,11 @@ insmod ad1848
 insmod opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=7 dma=0 dma2=3
 insmod opl3 io=0x388
 
-Remeber that the opl3sa2 module's io argument is for it's own control
+Remember that the opl3sa2 module's io argument is for it's own control
 port, which handles the card's master mixer for volume (on all cards),
-and bass and treble (on SA3 and SAx).
+and bass and treble (on SA3 and SAx cards).
 
-If all goes well an you see no error messages, you should be able to
+If all goes well and you see no error messages, you should be able to
 start using the sound capabilities of your system.  If you get an
 error message while trying to insert the opl3sa2 module, then make
 sure that the values of the various arguments match what you specified
@@ -100,12 +102,28 @@ chipset than I've encountered so far.  Look for a line in the log file
 that says "opl3sa2.c: chipset version = <some number>".  If you want
 me to add support for your card, send me the number from this line and
 any information you have on the make and chipset of your sound card,
-and I may be able to work up something.  If you do not see these
-messages, and any of the other messages present in the log are not
-helpful, email me some details and I'll try my best to help.
-
-To set up automatic module loading with kmod, the kernel module loader,
-I currently use the following section in my conf.modules file:
+and I should be able to work up a permanent fix.
+
+A temporary solution is to force the driver to act as either a SA2 or
+SA3.  If you use the modular driver, this can be done with the "force"
+option.  Using "force=2" makes the driver treat your card as a SA2,
+and "force=3" makes it treat your card as a SA3.  Note that the driver
+does not really differentiate internally between the SA3 and SAx, so
+"force=3" is actually suitable for an SAx card.
+
+If you build the driver into the kernel, a similar option is
+available, "Chipset".  Setting it to 2 or 3 will yield the same result
+as the "force" option does for the module.  I recommend trying
+auto-probing first ("Chipset" equal to the default of -1) before
+forcing compatibility with a specific chipset.
+
+If you do not see the chipset version message, and none of the other
+messages present in the system log are helpful, email me some details
+and I'll try my best to help.
+
+Lastly, if you're using modules and want to set up automatic module
+loading with kmod, the kernel module loader, here is the section I
+currently use in my conf.modules file:
 
 # Sound
 alias char-major-14 opl3sa2
index f87c5df8a0bca08865c7473cd3dfe7832f78a824..179762b2e60532344d06509a996071d7edcbd7cb 100644 (file)
@@ -518,9 +518,9 @@ S:  Maintained
 
 NETWORKING [IPv4/IPv6]
 P:     David S. Miller
-M:     davem@caip.rutgers.edu
-P:     Eric Schenk
-M:     Eric.Schenk@dna.lth.se
+M:     davem@dm.cobaltmicro.com
+P:     Andi Kleen
+M:     ak@muc.de
 P:     Alexey Kuznetsov
 M:     kuznet@ms2.inr.ac.ru
 L:     netdev@roxanne.nuclecu.unam.mx
index 72c662c7e4840b3fdabce69be224baf45a1f2c63..1126e7805a2231c745fb83e85fb28644497b0dc8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 0
-EXTRAVERSION =-pre4
+EXTRAVERSION =-pre5
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index 7bb7931d5a7fb41bd9e5cc23997673eb718f420a..41267ab281353e1ae82731188faae547600e477c 100644 (file)
@@ -15,8 +15,8 @@ choice 'Processor family' \
        "386                    CONFIG_M386     \
         486/Cx486              CONFIG_M486     \
         586/K5/5x86/6x86       CONFIG_M586     \
-        Pentium/TSC            CONFIG_M586TSC  \
-        PPro/K6/6x86MX         CONFIG_M686" PPro
+        Pentium/K6/TSC         CONFIG_M586TSC  \
+        PPro/6x86MX            CONFIG_M686" PPro
 #
 # Define implied options from the CPU selection here
 #
index 46afb0e2451c587e32a5226794486f138e52d0ca..3420ef51d5ec22c191d7404fe8129a22e80cbd45 100644 (file)
@@ -67,6 +67,33 @@ static inline int put_stack_long(struct task_struct *task, int offset,
        return 0;
 }
 
+extern int _stext, _etext;
+static void print_child_state(struct task_struct *task)
+{
+       unsigned int * stack = (unsigned int *) task->tss.esp0;
+       int count = 40;
+
+       printk("Process: %s (stack=%p, task=%p)\n", task->comm, stack, task);
+       for (;;) {
+               unsigned int data;
+               if ((unsigned int) stack < (unsigned int) task)
+                       break;
+               if ((unsigned int) stack >= PAGE_SIZE + (unsigned int) task)
+                       break;
+               data = *stack;
+               stack++;
+               if (data < (unsigned long) &_stext)
+                       continue;
+               if (data >= (unsigned long) &_etext)
+                       continue;
+               printk("[<%08x>] ", data);
+               if (--count)
+                       continue;
+               break;
+       }       
+       printk("\n");
+}
+
 /*
  * This routine gets a long from any process space by following the page
  * tables. NOTE! You should check that the long isn't on a page boundary,
@@ -408,6 +435,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
        if (!(child->flags & PF_PTRACED))
                goto out;
        if (child->state != TASK_STOPPED) {
+print_child_state(child);
+goto out;
                if (request != PTRACE_KILL)
                        goto out;
        }
index 7c48420e8894e99124be90e04937b8353a44fb09..74bc5a529dd65f0bdb70a063cbebcd8f27c4b129 100644 (file)
@@ -1052,10 +1052,10 @@ static void smp_tune_scheduling (void)
         *  the cache size)
         */
 
-       if (boot_cpu_data.x86 <= 4) {
+       if (!cpu_hz) {
                /*
                 * this basically disables processor-affinity
-                * scheduling on <=i486 based SMP boards.
+                * scheduling on SMP without a TSC.
                 */
                cacheflush_time = 0;
                return;
index d74e7d1f4d654922b3496be646ea9df28345a20d..27402d0f242317e5c012937b885e9478798a7fff 100644 (file)
@@ -116,7 +116,7 @@ endif
 
 archclean:
        rm -f vmlinux.gz
-       rm -f kernel/m68k_defs.h kernel/m68k_defs.d
+       rm -f arch/m68k/kernel/m68k_defs.h arch/m68k/kernel/m68k_defs.d
 
 archmrproper:
 
index 48b70f025717836b1440e3f9047a2894783ff78b..acc4a12405461265f6e2dd56bac5b192b8c9bdae 100644 (file)
@@ -215,8 +215,8 @@ if [ "$CONFIG_APOLLO" = "y" ] ; then
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
   bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT
-  bool 'AV Macintosh onboard MACE ethernet' CONFIG_MACMACE
-  bool 'Macintosh onboard SONIC ethernet' CONFIG_MACSONIC
+#  bool 'Macintosh (AV) onboard MACE ethernet' CONFIG_MACMACE
+  bool 'Macintosh (Quadra) onboard SONIC ethernet' CONFIG_MACSONIC
 fi
 if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then
   tristate 'MVME16x Ethernet support' CONFIG_MVME16x_NET
index 992d390c75f9d12e572197056c23b84169fb1dc2..b32e6a1c99410232aac9c931e8192ddb0f2c7729 100644 (file)
@@ -3,6 +3,6 @@
  */
 
 #define TS_MAGICKEY    0x5a5a5a5a
-#define TS_TSS 478
-#define TS_ESP0 498
-#define TS_FPU 502
+#define TS_TSS 482
+#define TS_ESP0 502
+#define TS_FPU 506
index 9c20abe814481dde9aa4abbf74ac44af445fcfc1..c149d8da9b7e513fa008daf5bbf30dfca2283ead 100644 (file)
@@ -45,6 +45,8 @@ EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(local_bh_count);
 EXPORT_SYMBOL(enable_irq);
index 1eb287ed2e56e89b70a8ac5f767ff46e9d190704..fb9bac4000e4e2c7e7f81ad9864882f6e7005e94 100644 (file)
@@ -40,6 +40,7 @@
  */
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
+static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM;
index 9888d83c13a7b5512c4d1159acdc59bca9dc6ce4..97d547b1da570ca68217d2d95aaacaaf46063e5e 100644 (file)
@@ -375,7 +375,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                case PTRACE_PEEKDATA: {
                        unsigned long tmp;
 
+                       down(&child->mm->mmap_sem);
                        ret = read_long(child, addr, &tmp);
+                       up(&child->mm->mmap_sem);
                        if (ret >= 0)
                                ret = put_user(tmp, (unsigned long *) data);
                        goto out;
@@ -408,7 +410,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
       /* when I and D space are separate, this will have to be fixed. */
                case PTRACE_POKETEXT: /* write the word at location addr. */
                case PTRACE_POKEDATA:
+                       down(&child->mm->mmap_sem);
                        ret = write_long(child,addr,data);
+                       up(&child->mm->mmap_sem);
                        goto out;
 
                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
index 415122f3a96eab902b86ab863e2dbbc88a8484c7..024ebbe4bc6862cf8dc1c95605122ab9890a215a 100644 (file)
@@ -423,7 +423,7 @@ static struct mac_model mac_data_table[]=
         */
 
        {       MAC_MODEL_CLII, "Classic II",           MAC_ADB_IISI,   MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
-       {       MAC_MODEL_CCL,  "Color Classic",        MAC_ADB_IISI,   MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_CCL,  "Color Classic",        MAC_ADB_CUDA,   MAC_VIA_IIci,   MAC_SCSI_OLD,   MAC_IDE_NONE,   MAC_SCC_II,     MAC_ETHER_NONE, MAC_NUBUS},
 
        /*
         *      Some Mac LC machines. Basically the same as the IIci, ADB like IIsi
@@ -475,8 +475,8 @@ static struct mac_model mac_data_table[]=
         *      Centris - just guessing again; maybe like Quadra
         */
 
-       {       MAC_MODEL_C610, "Centris 610",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,  MAC_ETHER_NONE, MAC_NUBUS},
-       {       MAC_MODEL_C650, "Centris 650",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,  MAC_ETHER_NONE, MAC_NUBUS},
+       {       MAC_MODEL_C610, "Centris 610",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,  MAC_ETHER_SONIC, MAC_NUBUS},
+       {       MAC_MODEL_C650, "Centris 650",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,  MAC_ETHER_SONIC, MAC_NUBUS},
        {       MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA,  MAC_ETHER_NONE, MAC_NUBUS},
 
        /*
index fc99409eed487b8404259470f2b13b34ca0a5417..0b40accc1e47c259d93ac4510dc915da5c0dde0b 100644 (file)
@@ -397,14 +397,18 @@ __initfunc(void mac_debug_init(void))
        /* Mac modem port */
        mac_init_scc_port( B9600|CS8, 0 );
        mac_console_driver.write = mac_scca_console_write;
+#ifdef CONFIG_SERIAL_CONSOLE
        mac_console_driver.wait_key = mac_scca_console_wait_key;
+#endif
        scc_port = 0;
     }
     else if (!strcmp( m68k_debug_device, "ser2" )) {
        /* Mac printer port */
        mac_init_scc_port( B9600|CS8, 1 );
        mac_console_driver.write = mac_sccb_console_write;
+#ifdef CONFIG_SERIAL_CONSOLE
        mac_console_driver.wait_key = mac_sccb_console_wait_key;
+#endif
        scc_port = 1;
     }
 #endif
index 95078a384b8084345ab9443269d0323212e53769..1731c929c2ad86ed2abb0b05bf6d847d5d4b950d 100644 (file)
@@ -1,6 +1,12 @@
 /*
  *     Mac bong noise generator. Note - we ought to put a boingy noise
  *     here 8)
+ *      
+ *     ----------------------------------------------------------------------
+ *     16.11.98:
+ *     rewrote some functions, added support for Enhanced ASC (Quadras)
+ *     after the NetBSD asc.c console bell patch by Colin Wood/Frederick Bruck
+ *     Juergen Mellinger (juergen.mellinger@t-online.de)
  */
 
 #include <linux/sched.h>
 #include <asm/macintosh.h>
 #include <asm/mac_asc.h>
 
+static int mac_asc_inited = 0;
+/*
+ * dumb triangular wave table
+ */
+static __u8 mac_asc_wave_tab[ 0x800 ];
+
+/*
+ * Alan's original sine table; needs interpolating to 0x800 
+ * (hint: interpolate or hardwire [0 -> Pi/2[, it's symmetric) 
+ */
 static const signed char sine_data[] = {
        0,  39,  75,  103,  121,  127,  121,  103,  75,  39,
        0, -39, -75, -103, -121, -127, -121, -103, -75, -39
 };
-#define DATA_SIZE      (sizeof(sine_data)/sizeof(sine_data[0]))
 
-static void nosound( unsigned long ignored );
-static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound };
+/*
+ * where the ASC hides ...
+ */
+static volatile __u8* mac_asc_regs = ( void* )0x50F14000;
 
-static volatile unsigned char *asc_base=(void *)0x50F14000;
+/* 
+ * sample rate; is this a good default value? 
+ */
+static unsigned long mac_asc_samplespersec = 11050;  
+static int mac_bell_duration = 0;
+static unsigned long mac_bell_phase; /* 0..2*Pi -> 0..0x800 (wavetable size) */
+static unsigned long mac_bell_phasepersample;
+
+/*
+ * some function protos 
+ */
+static void mac_init_asc( void );
+static void mac_nosound( unsigned long );
+static void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int );
+static void mac_quadra_ring_bell( unsigned long );
+static void mac_av_start_bell( unsigned int, unsigned int, unsigned int );
+static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ) = NULL;
 
+/*
+ * our timer to start/continue/stop the bell
+ */
+static struct timer_list mac_sound_timer = { NULL, NULL, 0, 0, mac_nosound };
 
-void mac_mksound( unsigned int hz, unsigned int ticks )
+/*
+ * Sort of initialize the sound chip (called from mac_mksound on the first
+ * beep).
+ */
+static void mac_init_asc( void )
 {
-       static int inited = 0;
-       unsigned long flags;
-       int samples=512;
+       int i;
 
-       if (macintosh_config->ident == MAC_MODEL_C660
-        || macintosh_config->ident == MAC_MODEL_Q840)
+       /* 
+        * do some machine specific initialization 
+        * BTW:
+        * the NetBSD Quadra patch identifies the Enhanced Apple Sound Chip via
+        *      mac_asc_regs[ 0x800 ] & 0xF0 != 0
+        * this makes no sense here, because we have to set the default sample
+        * rate anyway if we want correct frequencies
+        */
+       switch ( macintosh_config->ident )
        {
-               /*
-                * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O.
-                * It appears to be similar to the "AWACS" custom ASIC in the Power Mac 
-                * [678]100.  Because Singer and AWACS may have a similar hardware 
-                * interface, this would imply that the code in drivers/sound/dmasound.c 
-                * for AWACS could be used as a basis for Singer support.  All we have to
-                * do is figure out how to do DMA on the 660AV/840AV through the PSC and 
-                * figure out where the Singer hardware sits in memory. (I'd look in the
-                * vicinity of the AWACS location in a Power Mac [678]100 first, or the 
-                * current location of the Apple Sound Chip--ASC--in other Macs.)  The 
-                * Power Mac [678]100 info can be found in MkLinux Mach kernel sources.
-                *
-                * Quoted from Apple's Tech Info Library, article number 16405:
-                *   "Among desktop Macintosh computers, only the 660AV, 840AV, and Power
-                *   Macintosh models have 16-bit audio input and output capability 
-                *   because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer
-                *   codec circuitry in the AVs.  The Audio Waveform Amplifier and
-                *   Converter (AWAC) chip in the Power Macintosh performs the same 
-                *   16-bit I/O functionality.  The PowerBook 500 series computers
-                *   support 16-bit stereo output, but only mono input."
-                *
-                *   http://til.info.apple.com/techinfo.nsf/artnum/n16405
-                *
-                * --David Kilzer
-                */
+               case MAC_MODEL_IIFX:
+                       /*
+                        * The IIfx is always special ...
+                        */
+                       mac_asc_regs = ( void* )0x50010000;
+                       break;
+                       /* 
+                        * not sure about how correct this list is 
+                        * machines with the EASC enhanced apple sound chip 
+                        */
+               case MAC_MODEL_Q630:
+               case MAC_MODEL_P475:
+                       mac_special_bell = mac_quadra_start_bell;
+                       mac_asc_samplespersec = 22150;
+                       break;  
+               case MAC_MODEL_Q650:
+               case MAC_MODEL_Q700:
+               case MAC_MODEL_Q800:
+               case MAC_MODEL_Q900:
+               case MAC_MODEL_Q950:
+                       /*
+                        * Currently not implemented!
+                        */
+                       /*
+                        * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O.
+                        * It appears to be similar to the "AWACS" custom ASIC in the Power Mac 
+                        * [678]100.  Because Singer and AWACS may have a similar hardware 
+                        * interface, this would imply that the code in drivers/sound/dmasound.c 
+                        * for AWACS could be used as a basis for Singer support.  All we have to
+                        * do is figure out how to do DMA on the 660AV/840AV through the PSC and 
+                        * figure out where the Singer hardware sits in memory. (I'd look in the
+                        * vicinity of the AWACS location in a Power Mac [678]100 first, or the 
+                        * current location of the Apple Sound Chip--ASC--in other Macs.)  The 
+                        * Power Mac [678]100 info can be found in MkLinux Mach kernel sources.
+                        *
+                        * Quoted from Apple's Tech Info Library, article number 16405:
+                        *   "Among desktop Macintosh computers, only the 660AV, 840AV, and Power
+                        *   Macintosh models have 16-bit audio input and output capability
+                        *   because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer
+                        *   codec circuitry in the AVs.  The Audio Waveform Amplifier and
+                        *   Converter (AWAC) chip in the Power Macintosh performs the same 
+                        *   16-bit I/O functionality.  The PowerBook 500 series computers
+                        *   support 16-bit stereo output, but only mono input."
+                        *
+                        *   http://til.info.apple.com/techinfo.nsf/artnum/n16405
+                        *
+                        * --David Kilzer
+                        */
+                       mac_special_bell = mac_av_start_bell;
+                       break;
+       }
+
+       /* 
+        * init the wave table with a simple triangular wave 
+        * A sine wave would sure be nicer here ...
+        */
+       for ( i = 0; i < 0x400; i++ )
+       {
+               mac_asc_wave_tab[ i ] = i / 4;
+               mac_asc_wave_tab[ i + 0x400 ] = 0xFF - i / 4;
+       }
+       mac_asc_inited = 1;
+}      
 
+/*
+ * Called to make noise; current single entry to the boing driver. 
+ * Does the job for simple ASC, calls other routines else.
+ * XXX Fixme:
+ * Should be split into asc_mksound, easc_mksound, av_mksound and 
+ * function pointer set in mac_init_asc which would be called at 
+ * init time. 
+ * _This_ is rather ugly ...
+ */
+void mac_mksound( unsigned int freq, unsigned int length )
+{
+       __u32 cfreq = ( freq << 5 ) / 468;
+       __u32 flags;
+       int i;
+
+       if ( !mac_asc_inited )
+               mac_init_asc();
+
+       if ( mac_special_bell )
+       {
+               mac_special_bell( freq, length, 128 );
                return;
        }
-       
-       if(!inited)
+
+       if ( freq < 20 || freq > 20000 || length == 0 )
        {
-               int i=0;
-               int j=0;
-               int k=0;
-               int l=0;
-
-               /*
-                *      The IIfx strikes again!
-                */
-                
-               if(macintosh_config->ident==MAC_MODEL_IIFX)
-                       asc_base=(void *)0x50010000;
-
-               for(i=0;i<samples;i++)
-               {
-                       asc_base[i]=sine_data[j];
-                       asc_base[i+512]=sine_data[j];
-                       asc_base[i+1024]=sine_data[j];
-                       asc_base[i+1536]=sine_data[j];
-                       j++;
-                       if(j==DATA_SIZE)
-                               j=0;
-                       if(i&1)
-                               k++;
-                       if(k==DATA_SIZE)
-                               k=0;
-                       if((i&3)==3)
-                               l++;
-                       if(l==DATA_SIZE)
-                               l=0;    
-               }
-               inited=1;
+               mac_nosound( 0 );
+               return;
        }
-       save_flags(flags);
+
+       save_flags( flags );
        cli();
-       del_timer( &sound_timer );
 
-       if (hz > 20 && hz < 32767) {
-               int i;
-               u_long asc_pulses=((hz<<5)*samples)/468;
-               for(i=0;i<4;i++)
+       del_timer( &mac_sound_timer );
+
+       for ( i = 0; i < 0x800; i++ )
+               mac_asc_regs[ i ] = 0;  
+       for ( i = 0; i < 0x800; i++ )
+               mac_asc_regs[ i ] = mac_asc_wave_tab[ i ];
+
+       for ( i = 0; i < 8; i++ )
+               *( __u32* )( ( __u32 )mac_asc_regs + ASC_CONTROL + 0x814 + 8 * i ) = cfreq;
+
+       mac_asc_regs[ 0x807 ] = 0;
+       mac_asc_regs[ ASC_VOLUME ] = 128;
+       mac_asc_regs[ 0x805 ] = 0;
+       mac_asc_regs[ 0x80F ] = 0;
+       mac_asc_regs[ ASC_MODE ] = ASC_MODE_SAMPLE;
+       mac_asc_regs[ ASC_ENABLE ] = ASC_ENABLE_SAMPLE;
+
+       mac_sound_timer.expires = jiffies + length;
+       add_timer( &mac_sound_timer );
+
+       restore_flags( flags ); 
+}
+
+/*
+ * regular ASC: stop whining ..
+ */
+static void mac_nosound( unsigned long ignored )
+{
+       mac_asc_regs[ ASC_ENABLE ] = 0;
+}      
+
+/*
+ * EASC entry; init EASC, don't load wavetable, schedule 'start whining'.
+ */
+static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
+{
+       __u32 flags;
+
+       /* if the bell is already ringing, ring longer */
+       if ( mac_bell_duration > 0 )
+       {
+               mac_bell_duration += length;
+               return;
+       }
+
+       mac_bell_duration = length;
+       mac_bell_phase = 0;
+       mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec;
+       /* this is reasonably big for small frequencies */ 
+
+       save_flags( flags );
+       cli();
+
+       /* set the volume */
+       mac_asc_regs[ 0x806 ] = volume;
+
+       /* set up the ASC registers */
+       if ( mac_asc_regs[ 0x801 ] != 1 )
+       {
+               /* select mono mode */  
+               mac_asc_regs[ 0x807 ] = 0;
+               /* select sampled sound mode */
+               mac_asc_regs[ 0x802 ] = 0;
+               /* ??? */       
+               mac_asc_regs[ 0x801 ] = 1;
+               mac_asc_regs[ 0x803 ] |= 0x80;
+               mac_asc_regs[ 0x803 ] &= 0x7F;
+       }
+
+       mac_sound_timer.function = mac_quadra_ring_bell;
+       mac_sound_timer.expires = jiffies + 1;
+       add_timer( &mac_sound_timer );
+
+       restore_flags( flags );
+}
+
+/*
+ * EASC 'start/continue whining'; I'm not sure why the above function didn't
+ * already load the wave table, or at least call this one... 
+ * This piece keeps reloading the wave table until done.
+ */
+static void mac_quadra_ring_bell( unsigned long ignored )
+{
+       int     i, count = mac_asc_samplespersec / HZ;
+       __u32 flags;
+
+       /*
+        * we neither want a sound buffer overflow nor underflow, so we need to match
+        * the number of samples per timer interrupt as exactly as possible.
+        * using the asc interrupt will give better results in the future
+        * ...and the possibility to use a real sample (a boingy noise, maybe...)
+        */
+
+       save_flags( flags );
+       cli();
+       
+       del_timer( &mac_sound_timer );
+
+       if ( mac_bell_duration-- > 0 )
+       {
+               for ( i = 0; i < count; i++ )
                {
-                       asc_base[ASC_FREQ(i,0)]=0x00;
-                       asc_base[ASC_FREQ(i,1)]=20;
-                       asc_base[ASC_FREQ(i,2)]=0x00;
-                       asc_base[ASC_FREQ(i,3)]=20;
-                       asc_base[ASC_FREQ(i,4)]=(asc_pulses>>24)&0xFF;
-                       asc_base[ASC_FREQ(i,5)]=(asc_pulses>>16)&0xFF;
-                       asc_base[ASC_FREQ(i,6)]=(asc_pulses>>8)&0xFF;
-                       asc_base[ASC_FREQ(i,7)]=(asc_pulses>>0)&0xFF;
+                       mac_bell_phase += mac_bell_phasepersample;
+                       mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ];
                }
-               asc_base[ASC_CHAN]=0x03;
-               asc_base[ASC_VOLUME]=128;
-               asc_base[ASC_MODE]=ASC_MODE_SAMPLE;
-               asc_base[ASC_ENABLE]=ASC_ENABLE_SAMPLE;
-               if (ticks) {
-                       sound_timer.expires = jiffies + ticks;
-                       add_timer( &sound_timer );
-               }
-       } else {
-               nosound( 0 );
+               mac_sound_timer.expires = jiffies + 1;
+               add_timer( &mac_sound_timer );
        }
-       restore_flags(flags);
+       else
+               mac_asc_regs[ 0x801 ] = 0;
+       
+       restore_flags( flags );
 }
 
-
-static void nosound( unsigned long ignored )
+/*
+ * AV code - please fill in.
+ */
+static void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
 {
-       asc_base[ASC_ENABLE]=0;
-}      
+} 
index e6667ab464dd75bb71e90dd0fc7199dac6bff549..87e6692d41ba21481e553e0549dd0ba10521c101 100644 (file)
@@ -162,6 +162,13 @@ static unsigned long nubus_irqs[8];
 
 static unsigned long *mac_irqs[8];
 
+/*
+ * Some special nutcases ...
+ */
+
+static unsigned long mac_ide_irqs = 0;
+static unsigned long nubus_stuck_events = 0;
+
 /*
  * VIA/RBV/OSS/PSC register base pointers
  */
@@ -217,9 +224,13 @@ void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs);
 static void via_do_nubus(int slot, void *via, struct pt_regs *regs);
 
 /* #define DEBUG_MACINTS */
-/* #define DEBUG_NUBUS_INT */
+
+#define DEBUG_SPURIOUS
+#define DEBUG_NUBUS_SPURIOUS
+#define DEBUG_NUBUS_INT
+
 /* #define DEBUG_VIA */
-/* #define DEBUG_VIA_NUBUS */
+#define DEBUG_VIA_NUBUS
 
 void mac_init_IRQ(void)
 {
@@ -350,6 +361,12 @@ void mac_init_IRQ(void)
        mac_irqs[3]      =  &scc_irqs[0];
        mac_irqs[7]      =  &nubus_irqs[0];
 
+       /*
+        * Nubus Macs: turn off the Nubus dispatch interrupt for now
+        */
+
+       mac_turnoff_irq(IRQ_MAC_NUBUS);
+
        /*
         *      AV Macs: shutup the PSC ints
         */
@@ -430,8 +447,10 @@ int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_re
                return 0;
        } 
 
-       /* add similar hack for Nubus pseudo-irq here - hide nubus_request_irq */
-
+       /* 
+        * code below: only for VIA irqs currently 
+        * add similar hack for Nubus pseudo-irq here - hide nubus_request_irq
+        */
        via         = (volatile unsigned char *) via_table[srcidx];
        if (!via) 
                return -EINVAL;
@@ -697,12 +716,18 @@ int  mac_irq_pending( unsigned int irq )
        return (pending);
 }
 
+/*
+ * for /proc/interrupts: log interrupt stats broken down by 
+ * autovector int first, then by actual interrupt source.
+ */
+
 int mac_get_irq_list (char *buf)
 {
        int i, len = 0;
        int srcidx, irqidx;
 
        for (i = VIA1_SOURCE_BASE; i < NUM_MAC_SOURCES+8; ++i) {
+               /* XXX fixme: IRQ_SRC_MASK should cover VIA1 - Nubus */
                srcidx = ((i & IRQ_SRC_MASK)>>3) - 1;
                irqidx = (i & IRQ_IDX_MASK);
 
@@ -767,6 +792,32 @@ int mac_get_irq_list (char *buf)
        }
        if (num_spurious)
                len += sprintf(buf+len, "spurio.: %10u\n", num_spurious);
+
+       /* 
+        * XXX Fixme: Nubus sources are never logged above ...
+        */
+
+       len += sprintf(buf+len, "Nubus interrupts:\n");
+
+       for (i = 0; i < 7; i++) {
+               if (nubus_handler[i].handler == nubus_wtf)
+                       continue;
+               len += sprintf(buf+len, "nubus %01X: %10lu ",
+                              i+9, 
+                              nubus_irqs[i]);
+               len += sprintf(buf+len, "%s\n", 
+                              nubus_param[i].devname);
+
+       }
+       len += sprintf(buf+len, "nubus spurious ints: %10lu\n",
+                      nubus_irqs[7]);
+       len += sprintf(buf+len, "nubus stuck events : %10lu\n",
+                      nubus_stuck_events);
+#ifdef CONFIG_BLK_DEV_IDE
+       len += sprintf(buf+len, "nubus/IDE interrupt: %10lu\n",
+                      mac_ide_irqs);
+#endif 
+
        return len;
 }
 
@@ -787,8 +838,9 @@ void via_scsi_clear(void)
 
 void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-#ifdef DEBUG_VIA
-       printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
+#ifdef DEBUG_SPURIOUS
+       if (console_loglevel > 6)
+               printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
 #endif
 }
 
@@ -863,6 +915,18 @@ void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
        in_nmi--;
 }
 
+/*
+ *     Unexpected via interrupt
+ */
+void via_wtf(int slot, void *via, struct pt_regs *regs)
+{
+#ifdef DEBUG_SPURIOUS
+       if (console_loglevel > 6)
+               printk("Unexpected nubus event %d on via %p\n",slot,via);
+#endif
+}
+
 /*
  * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
  * via6522.c :-), disable/pending masks added.
@@ -1117,17 +1181,6 @@ void rbv_irq(int irq, void *dev_id, struct pt_regs *regs)
 #endif
 }
 
-/*
- *     Unexpected via interrupt
- */
-void via_wtf(int slot, void *via, struct pt_regs *regs)
-{
-#ifdef DEBUG_VIA
-       printk("Unexpected event %d on via %p\n",slot,via);
-#endif
-}
-
 /*
  *     Nubus / SCSI interrupts; OSS style
  *     The OSS is even more different than the RBV. OSS appears to stand for 
@@ -1267,8 +1320,9 @@ void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
  
 void nubus_wtf(int slot, void *via, struct pt_regs *regs)
 {
-#ifdef DEBUG_VIA_NUBUS
-       printk("Unexpected interrupt on nubus slot %d\n",slot);
+#ifdef DEBUG_NUBUS_SPURIOUS
+       if (console_loglevel > 6)
+               printk("Unexpected interrupt on nubus slot %d\n",slot);
 #endif
 }
 
@@ -1282,9 +1336,10 @@ void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
        int i;
                                /* 1+2: compatibility with PSC ! */
        for (i = 1; i < 3; i++) /* currently only these two used */
-               if (scc_handler[i].handler != mac_default_handler)
+               if (scc_handler[i].handler != mac_default_handler) {
                        (scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
-
+                       scc_irqs[i]++;
+               }
 }
 
 /*
@@ -1426,6 +1481,7 @@ int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct
        if (!nubus_active && !via2_is_oss) {
                request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK, 
                            "nubus dispatch", via_do_nubus);
+               mac_turnon_irq(IRQ_MAC_NUBUS);
        }
 
        nubus_active|=1<<slot;
@@ -1475,6 +1531,7 @@ int nubus_free_irq(int slot)
  * IDE interrupt hook
  */
 extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
+extern int (*mac_ide_irq_p_hook)(void);
 #endif
 
 /*
@@ -1482,13 +1539,13 @@ extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
  */
 static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
 {
-       unsigned char map;
+       unsigned char map, allints;
        int i;
        int ct=0;
-
-/*     printk("nubus interrupt\n");*/
+       int ide_pending = 0;
                
        /* lock the nubus interrupt */
+       /* That's just 'clear Nubus IRQ bit in VIA2' BTW. Pretty obsolete ? */
        if (via2_is_rbv) 
                via_write(rbv_regp, rIFR, 0x82);
        else
@@ -1496,37 +1553,69 @@ static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
        
 #ifdef CONFIG_BLK_DEV_MAC_IDE
        /* IDE hack */
-       if (mac_ide_intr_hook)
+       if (mac_ide_intr_hook) {
                /* 'slot' is lacking the machspec bit in 2.0 */
                /* need to pass proper dev_id = hwgroup here */
                mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+               mac_ide_irqs++;
+       }
 #endif
 
        while(1)
        {
                if (via2_is_rbv)
-                       map = ~via_read(rbv_regp, rBufA);
+                       allints = ~via_read(rbv_regp, rBufA);
                else
-                       map = ~via_read(via2_regp, vBufA);
+                       allints = ~via_read(via2_regp, vBufA);
                
-#ifdef DEBUG_NUBUS_INT
-               printk("nubus_irq: map %x mask %x\n", map, nubus_active);
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+               if (mac_ide_irq_p_hook)
+                       ide_pending = mac_ide_irq_p_hook();
 #endif
 
-               if( (map = (map&nubus_active)) ==0 ) {
-#ifdef DEBUG_NUBUS_INT
-                       printk("nubus_irq: nothing pending, map %x mask %x\n", 
-                               map, nubus_active);
+               if ( (map = (allints&nubus_active)) == 0 
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+                     && !ide_pending 
 #endif
-                       nubus_irqs[7]++;
+                                                       ) 
+               {
+                       if (ct == 0) {
+#ifdef DEBUG_VIA_NUBUS
+                               if (console_loglevel > 5)
+                                       printk("nubus_irq: nothing pending, map %x mask %x active %x\n", 
+                                               allints, nubus_active, map);
+#endif
+                               nubus_irqs[7]++;
+                       }
+                       /* clear it */
+                       if (allints)
+                               if (via2_is_rbv)
+                                       via_write(rbv_regp, rIFR, 0x02);
+                               else
+                                       via_write(via2_regp, vIFR, 0x02);
                        break;
                }
 
+#ifdef DEBUG_VIA_NUBUS
+               if (console_loglevel > 6)
+                       printk("nubus_irq: map %x mask %x active %x\n", 
+                               allints, nubus_active, map);
+#endif
+
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+               if (mac_ide_intr_hook && ide_pending) {
+                       mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
+                       mac_ide_irqs++;
+               }
+#endif
+
                if(ct++>2)
                {
-#ifdef DEBUG_NUBUS_INT
-                       printk("nubus stuck events - %d/%d\n", map, nubus_active);
-#endif
+                       if (console_loglevel > 5)
+                               printk("nubus stuck events - %x/%x/%x ide %x\n", 
+                               allints, nubus_active, map, ide_pending);
+                       nubus_stuck_events++;
+
                        return;
                }
 
@@ -1583,12 +1672,14 @@ static void oss_do_nubus(int slot, void *via, struct pt_regs *regs)
                printk("nubus_irq: map %x mask %x\n", map, nubus_active);
 #endif
                if( (map = (map&nubus_active)) ==0 ) {
+                       if (ct == 0) {
 #ifdef CONFIG_BLK_DEV_MAC_IDE
-                       if (!mac_ide_intr_hook)
-                               printk("nubus_irq: nothing pending, map %x mask %x\n", 
-                                       map, nubus_active);
+                               if (!mac_ide_intr_hook)
+                                       printk("nubus_irq: nothing pending, map %x mask %x\n", 
+                                               map, nubus_active);
 #endif
-                       nubus_irqs[7]++;
+                               nubus_irqs[7]++;
+                       }
                        break;
                }
 
index 88ee16b663869298a2298cdeddba3a07e114dec9..b79c9dd87e6dc2c28dbdaf66d5373c2708562d7d 100644 (file)
@@ -35,6 +35,9 @@ SECTIONS
 
   _edata = .;                  /* End of data section */
 
+  . = ALIGN(16);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
   . = ALIGN(4096);             /* Init code and data */
   __init_begin = .;
   .text.init : { *(.text.init) }
index f70d3621d67b1c077e57c8a46f28313d6c346f04..b5276ca1fbbc250db08734d092e1262109a628e7 100644 (file)
@@ -6,6 +6,7 @@
  *
  * Copyright 1994, 1995, 1996, 1997, 1998 by Ralf Baechle
  * Modified for R3000 by Paul M. Antoine, 1995, 1996
+ * Complete output from die() by Ulf Carlsson, 1998
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -80,50 +81,61 @@ int kstack_depth_to_print = 24;
  * This routine abuses get_user()/put_user() to reference pointers
  * with at least a bit of error checking ...
  */
-void show_registers(char * str, struct pt_regs * regs, long err)
+void show_stack(unsigned int *sp)
 {
-       int     i;
-       int     *stack;
-       u32     *sp, *pc, addr, module_start, module_end;
-       extern  char start_kernel, _etext;
+       int i;
+       unsigned int *stack;
 
-       sp = (u32 *)regs->regs[29];
-       pc = (u32 *)regs->cp0_epc;
+       stack = sp;
+       i = 0;
 
-       show_regs(regs);
+       printk("Stack:");
+       while ((unsigned long) stack & (PAGE_SIZE - 1)) {
+               unsigned long stackdata;
 
-       /*
-        * Dump the stack
-        */
-       printk("Process %s (pid: %ld, stackpage=%08lx)\nStack: ",
-               current->comm, current->pid, (unsigned long)current);
-       for(i=0;i<5;i++)
-               printk("%08x ", *sp++);
-       stack = (int *) sp;
+               if (__get_user(stackdata, stack++)) {
+                       printk(" (Bad stack address)");
+                       break;
+               }
 
-       for(i=0; i < kstack_depth_to_print; i++) {
-               unsigned int stackdata;
+               printk(" %08lx", stackdata);
 
-               if (((u32) stack & (PAGE_SIZE -1)) == 0)
-                       break;
-               if (i && ((i % 8) == 0))
-                       printk("\n       ");
-               if (get_user(stackdata, stack++) < 0) {
-                       printk("(Bad stack address)");
+               if (++i > 40) {
+                       printk(" ...");
                        break;
                }
-               printk("%08x ", stackdata);
+
+               if (i % 8 == 0)
+                       printk("\n      ");
        }
-       printk("\nCall Trace: ");
-       stack = (int *)sp;
-       i = 1;
+}
+
+void show_trace(unsigned int *sp)
+{
+       int i;
+       unsigned int *stack;
+       unsigned long kernel_start, kernel_end;
+       unsigned long module_start, module_end;
+       extern char _stext, _etext;
+
+       stack = sp;
+       i = 0;
+
+       kernel_start = (unsigned long) &_stext;
+       kernel_end = (unsigned long) &_etext;
        module_start = VMALLOC_START;
        module_end = module_start + MODULE_RANGE;
-       while (((unsigned long)stack & (PAGE_SIZE -1)) != 0) {
-               if (get_user(addr, stack++) < 0) {
-                       printk("(Bad address)\n");
+
+       printk("\nCall Trace:");
+
+       while ((unsigned long) stack & (PAGE_SIZE -1)) {
+               unsigned long addr;
+
+               if (__get_user(addr, stack++)) {
+                       printk(" (Bad stack address)\n");
                        break;
                }
+
                /*
                 * If the address is either in the text segment of the
                 * kernel, or in the region which contains vmalloc'ed
@@ -132,26 +144,33 @@ void show_registers(char * str, struct pt_regs * regs, long err)
                 * down the cause of the crash will be able to figure
                 * out the call path that was taken.
                 */
-               if (((addr >= (u32) &start_kernel) &&
-                    (addr <= (u32) &_etext)) ||
-                   ((addr >= module_start) && (addr <= module_end))) {
-                       if (i && ((i % 8) == 0))
-                               printk("\n       ");
-                       printk("%08x ", addr);
-                       i++;
+
+               if ((addr >= kernel_start && addr < kernel_end) ||
+                   (addr >= module_start && addr < module_end)) { 
+
+                       printk(" [<%08lx>]", addr);
+                       if (++i > 40) {
+                               printk(" ...");
+                               break;
+                       }
                }
        }
+}
+
+void show_code(unsigned int *pc)
+{
+       long i;
 
-       printk("\nCode : ");
-       if ((KSEGX(pc) == KSEG0 || KSEGX(pc) == KSEG1) &&
-           (((unsigned long) pc & 3) == 0))
-       {
-               for(i=0;i<5;i++)
-                       printk("%08x ", *pc++);
-               printk("\n");
+       printk("\nCode:");
+
+       for(i = -3 ; i < 6 ; i++) {
+               unsigned long insn;
+               if (__get_user(insn, pc + i)) {
+                       printk(" (Bad address in epc)\n");
+                       break;
+               }
+               printk("%c%08lx%c",(i?' ':'<'),insn,(i?' ':'>'));
        }
-       else
-               printk("(Bad address in epc)\n");
 }
 
 void die(const char * str, struct pt_regs * regs, unsigned long err)
@@ -162,6 +181,12 @@ void die(const char * str, struct pt_regs * regs, unsigned long err)
        console_verbose();
        printk("%s: %04lx\n", str, err & 0xffff);
        show_regs(regs);
+       printk("Process %s (pid: %ld, stackpage=%08lx)\n",
+               current->comm, current->pid, (unsigned long) current);
+       show_stack((unsigned int *) regs->regs[29]);
+       show_trace((unsigned int *) regs->regs[29]);
+       show_code((unsigned int *) regs->cp0_epc);
+       printk("\n");
        do_exit(SIGSEGV);
 }
 
index 6cc14e80b76253dfd98be859c6c965b17825ce58..3c0a423452cfc076fc1fb24bb5bc6df8223e6dbd 100644 (file)
@@ -48,7 +48,7 @@ CONFIG_PROC_DEVICETREE=y
 # CONFIG_KGDB is not set
 # CONFIG_XMON is not set
 # CONFIG_TOTALMP is not set
-# CONFIG_BOOTX_TEXT is not set
+CONFIG_BOOTX_TEXT=y
 
 #
 # Plug and Play support
@@ -114,6 +114,10 @@ CONFIG_SKB_LARGE=y
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
 
 #
@@ -133,6 +137,7 @@ CONFIG_BLK_DEV_SR_VENDOR=y
 # SCSI low-level drivers
 #
 # CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
@@ -140,14 +145,16 @@ CONFIG_BLK_DEV_SR_VENDOR=y
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
 # CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 CONFIG_SCSI_NCR53C8XX=y
@@ -171,7 +178,7 @@ CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
-CONFIG_SCSI_MAC53C94=m
+CONFIG_SCSI_MAC53C94=y
 
 #
 # Network device support
@@ -221,6 +228,7 @@ CONFIG_SLIP=m
 # CONFIG_TR is not set
 # CONFIG_SHAPER is not set
 # CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
 
 #
 # Amateur Radio support
@@ -242,25 +250,29 @@ CONFIG_SLIP=m
 #
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FB_OF=y
-# CONFIG_FB_CONTROL is not set
-# CONFIG_FB_PLATINUM is not set
-# CONFIG_FB_VALKYRIE is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+# CONFIG_FB_ATY is not set
 CONFIG_FB_IMSTT=y
-# CONFIG_FB_CT65550 is not set
+CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
 # CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-# CONFIG_FBCON_FONTS is not set
+CONFIG_FBCON_FONTS=y
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+CONFIG_FONT_SUN12x22=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
 
 #
 # Character devices
@@ -272,6 +284,10 @@ CONFIG_SERIAL=m
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_UNIX98_PTYS is not set
 CONFIG_MOUSE=y
+
+#
+# Mice
+#
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_BUSMOUSE is not set
 # CONFIG_MS_BUSMOUSE is not set
@@ -280,9 +296,17 @@ CONFIG_PSMOUSE=y
 # CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
 # CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
+
+#
+# Joystick support
+#
 # CONFIG_JOYSTICK is not set
 
 #
@@ -294,37 +318,46 @@ CONFIG_PSMOUSE=y
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_HFS_FS=y
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFSD=m
 # CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=y
-# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
 # CONFIG_BSD_DISKLABEL is not set
+CONFIG_MAC_PARTITION=y
 # CONFIG_SMD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-CONFIG_MAC_PARTITION=y
+# CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_NLS=y
 
 #
@@ -355,6 +388,7 @@ CONFIG_NLS=y
 # CONFIG_NLS_ISO8859_7 is not set
 # CONFIG_NLS_ISO8859_8 is not set
 # CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 
 #
@@ -383,6 +417,7 @@ CONFIG_SOUND_OSS=y
 # CONFIG_SOUND_OPL3SA2 is not set
 # CONFIG_SOUND_MAUI is not set
 # CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
 # CONFIG_SOUND_OPL3SA1 is not set
 # CONFIG_SOUND_SOFTOSS is not set
 # CONFIG_SOUND_YM3812 is not set
index efa2c69ee81895b045c9f175765defd5c4038041..811d599c0f6cfe88defb99aef3104b1dd4737d31 100644 (file)
@@ -138,6 +138,10 @@ CONFIG_ATALK=m
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
 
 #
@@ -195,7 +199,6 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -311,7 +314,7 @@ CONFIG_FONT_SUN12x22=y
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
index 0b047e60cfa3bc598e72894d509e9eca45913f69..29d70bdfb8026084fe02caae47a0ac44ea5f0481 100644 (file)
@@ -191,6 +191,19 @@ switch_to(struct task_struct *prev, struct task_struct *new)
        _enable_interrupts(s);
 }
 
+void instruction_dump (unsigned long *pc)
+{
+       int i;
+
+       if((((unsigned long) pc) & 3))
+                return;
+
+       printk("Instruction DUMP:");
+       for(i = -3; i < 6; i++)
+               printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
+       printk("\n");
+}
+
 void show_regs(struct pt_regs * regs)
 {
        int i;
index af02252f91adc225d43ef339a268167e4b1dbcf7..fa5184af25e05a7c6b074e9d6ec8f3eabe7647bb 100644 (file)
@@ -79,6 +79,7 @@ _exception(int signr, struct pt_regs *regs)
                debugger(regs);
 #endif
                print_backtrace((unsigned long *)regs->gpr[1]);
+               instruction_dump((unsigned long *)regs->nip);
                panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
        }
        force_sig(signr, current);
@@ -126,6 +127,7 @@ MachineCheckException(struct pt_regs *regs)
                debugger(regs);
 #endif
                print_backtrace((unsigned long *)regs->gpr[1]);
+               instruction_dump((unsigned long *)regs->nip);
                panic("machine check");
        }
        _exception(SIGSEGV, regs);      
@@ -219,6 +221,7 @@ StackOverflow(struct pt_regs *regs)
 #endif
        show_regs(regs);
        print_backtrace((unsigned long *)regs->gpr[1]);
+       instruction_dump((unsigned long *)regs->nip);
        panic("kernel stack overflow");
 }
 
index b45f4e6f4c9766cfe4a3f681c614babc6075e3c7..42e2918b138cf50baddf558329eeac01a83ae539 100644 (file)
@@ -89,6 +89,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
                        printk("page fault in interrupt handler, addr=%lx\n",
                               address);
                        show_regs(regs);
+                       instruction_dump((unsigned long *)regs->nip);
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
                        if (debugger_kernel_faults)
                                debugger(regs);
@@ -174,6 +175,7 @@ bad_page_fault(struct pt_regs *regs, unsigned long address)
        /* kernel has accessed a bad area */
        show_regs(regs);
        print_backtrace( (unsigned long *)regs->gpr[1] );
+       instruction_dump((unsigned long *)regs->nip);
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
        if (debugger_kernel_faults)
                debugger(regs);
index efa2c69ee81895b045c9f175765defd5c4038041..811d599c0f6cfe88defb99aef3104b1dd4737d31 100644 (file)
@@ -138,6 +138,10 @@ CONFIG_ATALK=m
 # CONFIG_NET_FASTROUTE is not set
 # CONFIG_NET_HW_FLOWCONTROL is not set
 # CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
 # CONFIG_NET_SCHED is not set
 
 #
@@ -195,7 +199,6 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -311,7 +314,7 @@ CONFIG_FONT_SUN12x22=y
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
index 5ffbefaf053f7c16b35dc6b819f5bc666fe70bf4..9982493701c12d1b4f13d63173af419b9614de13 100644 (file)
@@ -5,10 +5,10 @@
  */
 
 /*
- *  Original author:   abramov@cecmow.enet.dec.com (Igor Abramov)
+ *  Original authors:  abramov@cecmow.enet.dec.com (Igor Abramov)
+ *                     mlord@pobox.com (Mark Lord)
  *
- *  Maintained by:     mlord@pobox.com (Mark Lord)
- *                     with fanatical support from a legion of hackers!
+ *  See linux/MAINTAINERS for address of current maintainer.
  *
  *  This file provides support for the advanced features and bugs
  *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
index 6eb8cfa163351d7fb4db9cbdb006aeaf1c15d526..653d6c749758d50806185cc955abb03682f9e922 100644 (file)
@@ -570,6 +570,12 @@ check_table:
                                bsd_kdev = MKDEV(hd->major, minor);
                                bsd_maxpart = OPENBSD_MAXPARTITIONS;
                        }
+               } else if (SYS_IND(p) == NETBSD_PARTITION) {
+                       printk("!");
+                       if (!bsd_kdev) {
+                               bsd_kdev = MKDEV(hd->major, minor);
+                               bsd_maxpart = BSD_MAXPARTITIONS;
+                       }
                }
 #endif
 #ifdef CONFIG_UNIXWARE_DISKLABEL
@@ -1336,7 +1342,7 @@ __initfunc(void device_setup(void))
 int get_partition_list(char * page)
 {
        struct gendisk *p;
-       char buf[8];
+       char buf[32];
        int n, len;
 
        len = sprintf(page, "major minor  #blocks  name\n\n");
index 222a008cf45282798d5a836b22ebf8010783d9ca..502e18cba6b5e994b9af68e5b6e54fd0a37131ce 100644 (file)
@@ -5,9 +5,10 @@
  */
 
 /*
- *  Maintained by Mark Lord  <mlord@pobox.com>
- *            and Gadi Oxman <gadio@netvision.net.il>
- *            and Andre Hedrick <hedrick@astro.dyer.vanderbilt.edu>
+ *  Mostly written by Mark Lord <mlord@pobox.com>
+ *                and  Gadi Oxman <gadio@netvision.net.il>
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
  *
  * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
  *
@@ -101,12 +102,17 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
                return 1;       /* lba_capacity is our only option */
        }
        /*
-        * very large drives (8GB+) may lie about the number of cylinders
         * This is a split test for drives less than 8 Gig only.
+        * Drives less than 8GB sometimes declare that they have 15 heads.
+        * This is an accounting trick (0-15) == (1-16), just an initial
+        * zero point difference.
         */
        if ((id->lba_capacity < 16514064) && (lba_sects > chs_sects) &&
-           (id->heads == 16) && (id->sectors == 63)) {
-               id->cyls = lba_sects / (16 * 63); /* correct cyls */
+           ((id->heads == 15) || (id->heads == 16)) && (id->sectors == 63)) {
+               if (id->heads == 15)
+                       id->cyls = lba_sects / (15 * 63); /* correct cyls */
+               if (id->heads == 16)
+                       id->cyls = lba_sects / (16 * 63); /* correct cyls */
                return 1;       /* lba_capacity is our only option */
        }
        /* perform a rough sanity check on lba_sects:  within 10% is "okay" */
index f82f3553ab76499f6402fbd9906b6244d9b22610..8e0c54dc16753b2bb02dfc2185dfb24ccb73647a 100644 (file)
@@ -5,8 +5,10 @@
  */
 
 /*
- *  Maintained by Mark Lord  <mlord@pobox.com>
- *            and Gadi Oxman <gadio@netvision.net.il>
+ *  Mostly written by Mark Lord <mlord@pobox.com>
+ *                and Gadi Oxman <gadio@netvision.net.il>
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
  *
  * This is the IDE probe module, as evolved from hd.c and ide.c.
  *
@@ -587,7 +589,12 @@ static int init_irq (ide_hwif_t *hwif)
                drive->next = hwgroup->drive->next;
                hwgroup->drive->next = drive;
        }
-       hwgroup->hwif = HWIF(hwgroup->drive);
+       if (!hwgroup->hwif) {
+               hwgroup->hwif = HWIF(hwgroup->drive);
+#ifdef DEBUG
+               printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
+#endif
+       }
        restore_flags(flags);   /* all CPUs; safe now that hwif->hwgroup is set up */
 
 #if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
index de1431dac1a719511a588a12973c33401ec9612b..cb33f73383099cdc2daa3bb14c61fe705d09ca83 100644 (file)
  *                        number of tape blocks.
  *                       Add support for INTERRUPT DRQ devices.
  * Ver 1.13  Jan  2 98   Add "speed == 0" work-around for HP COLORADO 5GB
- * Ver 1.14  Dec 30 99   Partial fixes for the Sony/AIWA tape drives.
+ * Ver 1.14  Dec 30 98   Partial fixes for the Sony/AIWA tape drives.
  *                       Replace cli()/sti() with hwgroup spinlocks.
  *
  * Here are some words from the first releases of hd.c, which are quoted
index e10288318123b3a6329b8ff5ca4a6555fbbf3aa9..21d9c59ffc78c3043b1d70283031b577000f6e0f 100644 (file)
@@ -5,8 +5,10 @@
  */
 
 /*
- *  Maintained by Mark Lord  <mlord@pobox.com>
- *            and Gadi Oxman <gadio@netvision.net.il>
+ *  Mostly written by Mark Lord  <mlord@pobox.com>
+ *                and Gadi Oxman <gadio@netvision.net.il>
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
  *
  * This is the multiple IDE interface driver, as evolved from hd.c.
  * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15).
index 41b87fbbe3b50c9a6142c2bee6b4eba1f8646ae6..bc2cf8949d4b3b4fac5d04ae9b50cd266ec081f8 100644 (file)
@@ -1,20 +1,26 @@
 /*
- *  linux/drivers/block/opti621.c       Version 0.3  Nov 29, 1997
+ *  linux/drivers/block/opti621.c       Version 0.6  Jan 02, 1999
  *
- *  Copyright (C) 1996-1998  Linus Torvalds & author (see below)
+ *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
  */
 
 /*
- * OPTi 82C621 chipset EIDE controller driver
- * Author: Jaromir Koutek (E-mail: Jaromir.Koutek@st.mff.cuni.cz)
- *
+ * Authors:
+ * Jaromir Koutek <miri@punknet.cz>,
+ * Jan Harkes <jaharkes@cwi.nl>,
+ * Mark Lord <mlord@pobox.com>
  * Some parts of code are from ali14xx.c and from rz1000.c.
+ *
+ * OPTi is trademark of OPTi, Octek is trademark of Octek.
+ *
  * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
  * and disassembled/traced setupvic.exe (DOS program).
  * It increases kernel code about 2 kB.
+ * I don't have this card no more, but I hope I can get some in case
+ * of needed development.
  * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
  * It has a place for a secondary connector in circuit, but nothing
- * is there. It cost about $25. Also BIOS says no address for
+ * is there. Also BIOS says no address for
  * secondary controller (see bellow in ide_init_opti621).
  * I've only tested this on my system, which only has one disk.
  * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
  * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
  * it slows to about 100kB/s! I don't know why and I have
  * not this drive now, so I can't try it again.
- * If you have two disk, please boot in single mode and carefully
- * (you can boot on read-only fs) try to set PIO mode 0 etc.
+ * I write this driver because I lost the paper ("manual") with
+ * settings of jumpers on the card and I have to boot Linux with
+ * Loadlin except LILO, cause I have to run the setupvic.exe program
+ * already or I get disk errors (my test: rpm -Vf
+ * /usr/X11R6/bin/XF86_SVGA - or any big file).
+ * Some numbers from hdparm -t /dev/hda:
+ * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
+ * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
+ * I have 4 Megs/s before, but I don't know why (maybe changes
+ * in hdparm test).
+ * After release of 0.1, I got some successful reports, so it might work.
+ *
  * The main problem with OPTi is that some timings for master
  * and slave must be the same. For example, if you have master
  * PIO 3 and slave PIO 0, driver have to set some timings of
  * for autoselect mode (you can change it to PIO 0, if you want).
  * If you then set the second drive to another PIO, the old value
  * (automatically selected) will be overrided by yours.
- * I don't know what there is a 25/33MHz switch in configuration
- * register, driver is written for use at any frequency which get
+ * There is a 25/33MHz switch in configuration
+ * register, but driver is written for use at any frequency which get
  * (use idebus=xx to select PCI bus speed).
  * Use ide0=autotune for automatical tune of the PIO modes.
  * If you get strange results, do not use this and set PIO manually
  * by hdparm.
- * I write this driver because I lost the paper ("manual") with
- * settings of jumpers on the card and I have to boot Linux with
- * Loadlin except LILO, cause I have to run the setupvic.exe program
- * already or I get disk errors (my test: rpm -Vf
- * /usr/X11R6/bin/XF86_SVGA - or any big file).
- * Some numbers from hdparm -t /dev/hda:
- * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
- * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
- * I have 4 Megs/s before, but I don't know why (maybe bad hdparm).
- * If you tried this driver, please send me a E-mail of your experiences.
- * My E-mail address is Jaromir.Koutek@st.mff.cuni.cz (I hope
- * till 30. 6. 2000), otherwise you can try miri@atrey.karlin.mff.cuni.cz.
- * I think OPTi is trademark of OPTi, Octek is trademark of Octek and so on.
+ *
+ * Version 0.1, Nov 8, 1996
+ * by Jaromir Koutek, for 2.1.8. 
+ * Initial version of driver.
+ * 
+ * Version 0.2
+ * Number 0.2 skipped.
+ *
+ * Version 0.3, Nov 29, 1997
+ * by Mark Lord (probably), for 2.1.68
+ * Updates for use with new IDE block driver.
+ *
+ * Version 0.4, Dec 14, 1997
+ * by Jan Harkes
+ * Fixed some errors and cleaned the code.
+ *
+ * Version 0.5, Jan 2, 1998
+ * by Jaromir Koutek
+ * Updates for use with (again) new IDE block driver.
+ * Update of documentation.
+ * 
+ * Version 0.6, Jan 2, 1999
+ * by Jaromir Koutek
+ * Reversed to version 0.3 of the driver, because
+ * 0.5 doesn't work.
  */
 
 #undef REALLY_SLOW_IO  /* most systems can safely undef this */
 
 #define READ_REG 0     /* index of Read cycle timing register */
 #define WRITE_REG 1    /* index of Write cycle timing register */
-#define MISC_REG 6     /* index of Miscellaneous register */
 #define CNTRL_REG 3    /* index of Control register */
+#define STRAP_REG 5    /* index of Strap register */
+#define MISC_REG 6     /* index of Miscellaneous register */
+
 int reg_base;
 
 #define PIO_NOT_EXIST 254
@@ -203,9 +233,10 @@ static void compute_clocks(int pio, pio_clocks_t *clks)
                clks->recovery_time = 2;
                /* minimal values */
        }
 }
 
-/* Main tune procedure, hooked by tuneproc. */
+/* Main tune procedure, called from tuneproc. */
 static void opti621_tune_drive (ide_drive_t *drive, byte pio)
 {
        /* primary and secondary drives share some registers,
@@ -218,7 +249,7 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
        byte cycle1, cycle2, misc;
        ide_hwif_t *hwif = HWIF(drive);
 
-       /* set drive->drive_data for both drives */
+       /* sets drive->drive_data for both drives */
        compute_pios(drive, pio);
        pio1 = hwif->drives[0].drive_data;
        pio2 = hwif->drives[1].drive_data;
@@ -250,7 +281,7 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
        outb(0xff, reg_base+5);         /* hmm, setupvic.exe does this ;-) */
        inb(reg_base+CNTRL_REG);        /* if reads 0xff, adapter not exist? */
        read_reg(CNTRL_REG);            /* if reads 0xc0, no interface exist? */
-       read_reg(5);                    /* read version, probably 0 */
+       read_reg(STRAP_REG);            /* read version, probably 0 */
 
        /* program primary drive */
        write_reg(0,      MISC_REG);    /* select Index-0 for Register-A */
index d1ae0a8b63b212266bed0298602ba216ff5dc0b7..fe8c229004db35e83218c4363ca9a1bb3e9890ee 100644 (file)
@@ -5,7 +5,9 @@
  */
 
 /*
- *  Principal Author/Maintainer:  mlord@pobox.com (Mark Lord)
+ *  Principal Author:  mlord@pobox.com (Mark Lord)
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
  *
  *  This file provides support for disabling the buggy read-ahead
  *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
index 7d063f0641615089d3a7f67969dbac16b758c031..8b32ddb7d63f77963a8c3858cd440717f9d30d3d 100644 (file)
@@ -376,8 +376,10 @@ int open_for_data(struct cdrom_device_info * cdi)
                        }
                        cdinfo(CD_OPEN, "the tray is now closed.\n"); 
                }
-               if (ret!=CDS_DISC_OK)
+               if (ret!=CDS_DISC_OK) {
+                       ret = -ENOMEDIUM;
                        goto clean_up_and_return;
+               }
        }
        cdrom_count_tracks(cdi, &tracks);
        if (tracks.error == CDS_NO_DISC) {
index becd60f75926e66705a9177a9cfd1e94c1befb35..17af9e4e59d242c0acf143905eb02dab43cfd8e3 100644 (file)
@@ -584,10 +584,8 @@ static char rcsid[] =
 #include <linux/pci.h>
 #include <linux/version.h>
 
-#ifdef CONFIG_PROC_FS
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
-#endif
 
 #define cy_put_user    put_user
 
@@ -781,9 +779,7 @@ static void cyz_poll(unsigned long);
 static void show_status(int);
 #endif
 
-#ifdef CONFIG_PROC_FS
 static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *);
-#endif
 
 /* The Cyclades-Z polling cycle is defined by this variable */
 static long cyz_polling_cycle = CZ_DEF_POLL;
@@ -4952,7 +4948,6 @@ show_version(void)
        __DATE__, __TIME__);
 } /* show_version */
 
-#ifdef CONFIG_PROC_FS
 static int 
 cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
                       int *eof, void *data)
@@ -5009,7 +5004,6 @@ done:
        len = 0;
     return len;
 }
-#endif
 
 
 /* The serial driver boot-time initialization code!
@@ -5281,15 +5275,8 @@ cy_init(void))
 #endif
     }
 
-#ifdef CONFIG_PROC_FS
         ent = create_proc_entry("cyclades", S_IFREG | S_IRUGO, 0);
         ent->read_proc = cyclades_get_proc_info;
-#endif
-#if 0
-#ifdef CONFIG_PROC_FS
-    proc_register(&proc_root, &cyclades_proc_entry);
-#endif
-#endif
 
     return 0;
     
index 227eff3e338587eabdf1cfbf7556e4a35e34b091..a57a8326630b58b56694c5d68ce1c7654df74b5d 100644 (file)
@@ -138,26 +138,49 @@ static ssize_t write_mem(struct file * file, const char * buf,
        return do_write_mem(file, __va(p), p, buf, count, ppos);
 }
 
+/*
+ * This should probably be per-architecture in <asm/pgtable.h>
+ */
+static inline unsigned long pgprot_noncached(unsigned long prot)
+{
+#if defined(__i386__)
+       if (boot_cpu_data.x86 > 3)
+               prot |= _PAGE_PCD;
+#elif defined(__powerpc__)
+       prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+#elif defined(__mc68000__)
+       if (CPU_IS_020_OR_030)
+               prot |= _PAGE_NOCACHE030;
+       /* Use no-cache mode, serialized */
+       if (CPU_IS_040_OR_060)
+               prot = (prot & _CACHEMASK040) | _PAGE_NOCACHE_S;
+#elif defined(__mips__)
+       prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED;
+#endif
+
+       return prot;
+}
+
 static int mmap_mem(struct file * file, struct vm_area_struct * vma)
 {
        unsigned long offset = vma->vm_offset;
 
        if (offset & ~PAGE_MASK)
                return -ENXIO;
-#if defined(__i386__)
+
        /*
-        * hmm.. This disables high-memory caching, as the XFree86 team
-        * wondered about that at one time.
-        * The surround logic should disable caching for the high device
-        * addresses anyway, but right now this seems still needed.
+        * Accessing memory above the top the kernel knows about or
+        * through a file pointer that was marked O_SYNC will be
+        * done non-cached.
+        *
+        * Set VM_IO, as this is likely a non-cached access to an
+        * I/O area, and we don't want to include that in a core
+        * file.
         */
-       if (boot_cpu_data.x86 > 3 && offset >= __pa(high_memory))
-               pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#endif
-#ifdef __powerpc__
-       if (offset >= __pa(high_memory))
-               pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
-#endif
+       if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) {
+               pgprot_val(vma->vm_page_prot) = pgprot_noncached(pgprot_val(vma->vm_page_prot));
+               vma->vm_flags |= VM_IO;
+       }
        if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
                             vma->vm_page_prot))
                return -EAGAIN;
index af9d7848d251c2a0c62adc9659871d00e1bacfaf..c4a9ea26e70c2ee9deeadbf0ecac66bce0c618a2 100644 (file)
@@ -2356,6 +2356,17 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
                char_time = 1;
        if (timeout)
          char_time = MIN(char_time, timeout);
+       /*
+        * If the transmitter hasn't cleared in twice the approximate
+        * amount of time to send the entire FIFO, it probably won't
+        * ever clear.  This assumes the UART isn't doing flow
+        * control, which is currently the case.  Hence, if it ever
+        * takes longer than info->timeout, this is probably due to a
+        * UART bug of some kind.  So, we clamp the timeout parameter at
+        * 2*info->timeout.
+        */
+       if (!timeout || timeout > 2*info->timeout)
+               timeout = 2*info->timeout;
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
        printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
        printk("jiff=%lu...", jiffies);
index 67e308e43d1bc4a4f3cbe0508d1abefcf2156212..e6b3a9a52c0b615235b3502c590657aef6bf1b54 100644 (file)
 #ifdef CONFIG_HISAX_ELSA
 #define DEFAULT_CARD ISDN_CTYPE_ELSA
 #define DEFAULT_CFG {0,0,0,0}
+#ifdef MODULE
 int elsa_init_pcmcia(void*, int, int*, int);
 EXPORT_SYMBOL(elsa_init_pcmcia);
 #endif
+#endif
 #ifdef CONFIG_HISAX_AVM_A1
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
index befe4232d1c64e10bcee23142c6336fab2c16807..b35d3219334b83d92d26cb8274778532aa9f07a3 100644 (file)
@@ -13,7 +13,7 @@ u32 tigonFwBssAddr = 0x150c0;
 int tigonFwBssLen = 0x2080;
 u32 tigonFwSbssAddr = 0x15090;
 int tigonFwSbssLen = 0x28;
-u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __init = {
+u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, 0x8fbd4f84, 
 0x3a0f021, 0x3c100000, 0x26104000, 0xc00100c, 0x0, 0xd, 
 0x27bdffd8, 0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021, 0x3c170013, 
index 2f118d32813e8971930862ac41b5ade60aec921d..c41da18669e49958766ffbed84a736dc14021416 100644 (file)
@@ -1227,7 +1227,6 @@ __initfunc(int
 plip_init(void))
 {
        struct parport *pb = parport_enumerate();
-       int devices=0;
        int i=0;
 
        if (parport[0] == -2)
@@ -1238,7 +1237,7 @@ plip_init(void))
                timid = 0;
        }
 
-       /* When user feeds parameters, use them */
+       /* If the user feeds parameters, use them */
        while (pb) {
                if ((parport[0] == -1 && (!timid || !pb->devices)) || 
                    plip_searchfor(parport, i)) {
@@ -1266,14 +1265,13 @@ plip_init(void))
                                kfree(dev_plip[i]->name);
                                kfree(dev_plip[i]);
                        } else {
-                               devices++;
+                               i++;
                        }
                }
-               i++;
                pb = pb->next;
        }
 
-       if (devices == 0) {
+       if (i == 0) {
                printk(KERN_INFO "plip: no devices registered\n");
                return -EIO;
        }
index 0a886c6db0d7dd4769b180d7167918af768f2fad..ecf7847581a864c58d28f3c732d45404224c5145 100644 (file)
@@ -1078,6 +1078,8 @@ static int if_send(struct sk_buff *skb, struct device *dev)
                                ++chan->if_send_bfrs_passed_to_adptr;
                                ++chan->ifstats.tx_packets;
                                ++card->wandev.stats.tx_packets;
+                               chan->ifstats.tx_bytes += skb->len;
+                               card->wandev.stats.tx_bytes += skb->len;
                        }
                }
        }
@@ -1501,6 +1503,8 @@ static void fr502_rx_intr(sdla_t * card)
                        netif_rx(skb);
                        ++chan->ifstats.rx_packets;
                        ++card->wandev.stats.rx_packets;
+                       chan->ifstats.rx_bytes += skb->len;
+                       card->wandev.stats.rx_bytes += skb->len;
                }
        }
        sdla_mapmem(&card->hw, FR_MB_VECTOR);
@@ -1621,6 +1625,8 @@ static void fr508_rx_intr(sdla_t * card)
                                                ++chan->rx_intr_bfr_passed_to_stack;
                                                ++chan->ifstats.rx_packets;
                                                ++card->wandev.stats.rx_packets;
+                                               chan->ifstats.rx_bytes += skb->len;
+                                               card->wandev.stats.rx_bytes += skb->len;
                                        }
                                }
                        }
index 69038be9a716e41dd6a1bc0319078e62df47969b..ec9b71b8540b173f87915b3fd7c66f761911b5aa 100644 (file)
@@ -698,6 +698,7 @@ static int if_send(struct sk_buff *skb, struct device *dev)
                } else {
                        ++ppp_priv_area->if_send_bfr_passed_to_adptr;
                        ++card->wandev.stats.tx_packets;
+                       card->wandev.stats.tx_bytes += skb->len;
                }
        }
 tx_done:
@@ -1202,6 +1203,7 @@ static void rx_intr(sdla_t * card)
                                skb->mac.raw = skb->data;
                                netif_rx(skb);
                                ++card->wandev.stats.rx_packets;
+                               card->wandev.stats.rx_bytes += skb->len;
                                ++ppp_priv_area->rx_intr_bfr_passed_to_stack;
                        }
                } else {
index 0c011ffa2e28151ff5f916a2ac36b272abcdedfb..0ef2771d81cd687835dd5b8a2823216adac6ec40 100644 (file)
@@ -1028,6 +1028,7 @@ static void rx_intr (sdla_t* card)
                {
                        netif_rx(skb);
                        ++chan->ifstats.rx_packets;
+                       chan->ifstats.rx_bytes += skb->len;
                }
        }
 }
@@ -2122,6 +2123,7 @@ static int chan_send (struct device* dev, struct sk_buff* skb)
                                return 1;
                        }
                        ++chan->ifstats.tx_packets;
+                       chan->ifstats.tx_bytes += skb->len;
                        break;
 
                case 0x33:      /* Tx busy */
index fb32f3da5d3211fc9db3a3d0e590a2ecc90f05b3..e925dc76c26d694cc572117dcd44014cc53297db 100644 (file)
@@ -75,7 +75,6 @@ static int rx_copybreak = 100;
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 
 #include <asm/processor.h>             /* Processor type for cache alignment. */
 #include <asm/bitops.h>
index bfaef7b7e96b61b7eddad105b0e52cc0e068260f..63dca15e14e53f04dcfdb40a6ac2c5fb6d40afa3 100644 (file)
@@ -539,6 +539,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( ADAPTEC,        ADAPTEC_7884,   "AIC-7884U"),
        DEVICE( ADAPTEC,        ADAPTEC_1030,   "ABA-1030 DVB receiver"),
        DEVICE( ADAPTEC2,       ADAPTEC2_2940U2,"AHA-2940U2"),
+       DEVICE( ADAPTEC2,       ADAPTEC2_78902, "AIC-7890/1"),
        DEVICE( ADAPTEC2,       ADAPTEC2_7890,  "AIC-7890/1"),
        DEVICE( ADAPTEC2,       ADAPTEC2_3940U2,"AHA-3940U2"),
        DEVICE( ADAPTEC2,       ADAPTEC2_3950U2D,"AHA-3950U2D"),
index b350d9d5812f67bfce4f9e9c4b24a3490a58f83d..bbeeeb2f634fa267e72a555bfa026f75e399ccd7 100644 (file)
@@ -37,8 +37,10 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     AHA-3940U
     AHA-3940W
     AHA-3940UW
+    AHA-3940AUW
     AHA-3940U2W
     AHA-3950U2B
+    AHA-3950U2D
     AHA-3985
     AHA-3985U
     AHA-3985W
@@ -52,6 +54,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     AIC-787x
     AIC-788x
     AIC-789x
+    AIC-3860
 
     Bus Types
     ----------------------------
@@ -69,8 +72,30 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     AHA-398x - PCI RAID controllers with three separate SCSI controllers
                on-board.
 
-    NOTE: The AHA-2920 is NOT an AIC-7xxx based controller, and is not
-          handled by this driver.
+  Not Supported Devices
+  ------------------------------
+    Adaptec Cards
+    ----------------------------
+    AHA-2920 (Only the cards that use the Future Domain chipset are not
+              supported, any 2920 cards based on Adaptec AIC chipsets are
+             supported)
+    AAA-13x Raid Adapters
+    AAA-113x Raid Port Card
+
+    Motherboard Chipsets
+    ----------------------------
+    AIC-7810
+
+    Bus Types
+    ----------------------------
+    R - Raid Port busses are not supported.
+
+    The hardware RAID devices sold by Adaptec are *NOT* supported by this
+    driver (and will people please stop emailing me about them, they are
+    a totally separate beast from the bare SCSI controllers and this driver
+    can not be retrofitted in any sane manner to support the hardware RAID
+    features on those cards - Doug Ledford).
+    
 
   People
   ------------------------------
@@ -299,13 +324,12 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
        binary->hex conversion then send an email to the aic7xxx mailing
        list and someone can help you out.
 
-    "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to enable
-        tagged queueing on specific devices.  As of driver version 5.0.6, we
-        now globally enable tagged queueing by default, but we also disable
-        tagged queueing on all individual devices by default.  In order to
-        enable tagged queueing for certian devices at boot time, a user may
+    "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable
+        tagged queueing on specific devices.  As of driver version 5.1.8, we
+        now globally enable tagged queueing by default.  In order to
+        disable tagged queueing for certian devices at boot time, a user may
         use this boot param.  The driver will then parse this message out
-        and enable the specific device entries that are present based upon
+        and disable the specific device entries that are present based upon
         the value given.  The param line is parsed in the following manner:
 
           { - first instance indicates the start of this parameter values
@@ -337,18 +361,13 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
           commas with no value specified will simply increment to the next id
           without changing anything for the missing values.
 
-        tag_info:{{8,8},,{8,8}}
-          First adapter, scsi id 0 to 8, id 1 to 8, remainder stay at their
-          default.  Second adapter stays entirely at default.  Third
-          adapter, id 0 to 8, id 1 to 8, remainder at default (identical to
-          first adapter).
-
-        tag_info:{,,,{,,,64}}
+        tag_info:{,,,{,,,255}}
           First, second, and third adapters at default values.  Fourth
-          adapter, id 3 to 64.  Notice that leading commas simply increment
-          what the first number effects, and there are no need for trailing
-          commas.  When you close out an adapter, or the entire entry,
-          anything not explicitly set stays at the default value.
+          adapter, id 3 is disabled.  Notice that leading commas simply
+         increment what the first number effects, and there are no need
+         for trailing commas.  When you close out an adapter, or the
+         entire entry, anything not explicitly set stays at the default
+         value.
 
         A final note on this option.  The scanner I used for this isn't
         perfect or highly robust.  If you mess the line up, the worst that
@@ -449,10 +468,16 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
       - European Linux mirror of Teleport site
 
+  Web sites
+  ------------------------------
+    http://developer.redhat.com/aic7xxx/
+      - Primary web site maintained by Doug Ledford.  I haven't actually
+        put anything up yet....but I'm planning on it.  This information
+       is put here as an add for the vapor page :)
 
 Dean W. Gehnert
 deang@teleport.com
 
 $Revision: 3.0 $
 
-Modified by Doug Ledford 1998
+Modified by Doug Ledford 1998-9
index 8418ea23b5aea1c341b56ba30724697a21cb410c..f61b13fd1d2bf54ceb1e5d55eed97dda3a05ec83 100644 (file)
  *
  * Further driver modifications made by Doug Ledford <dledford@redhat.com>
  *
- * Copyright (c) 1997-1998 Doug Ledford
+ * Copyright (c) 1997-1999 Doug Ledford
  *
  * These changes are released under the same licensing terms as the FreeBSD
  * driver written by Justin Gibbs.  Please see his Copyright notice above
@@ -354,7 +354,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.7"
+#define AIC7XXX_C_VERSION  "5.1.9"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -449,6 +449,8 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  */
 #ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
 #define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
+#else
+#define AIC7XXX_CMDS_PER_LUN 24
 #endif
 
 /* Set this to the delay in seconds after SCSI bus reset. */
@@ -511,8 +513,8 @@ typedef struct
  * Make a define that will tell the driver not to use tagged queueing
  * by default.
  */
-#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
-                              255, 255, 255, 255, 255, 255, 255, 255}
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
+                              0, 0, 0, 0, 0, 0, 0, 0}
 
 /*
  * Modify this as you see fit for your system.  By setting tag_commands
@@ -884,6 +886,7 @@ typedef enum {
   *  and what flags weren't.  This way, I could clean up the flag usage on
   *  a use by use basis.  Doug Ledford
   */
+        AHC_RESET_DELAY           = 0x00080000,
         AHC_A_SCANNED             = 0x00100000,
         AHC_B_SCANNED             = 0x00200000,
         AHC_MULTI_CHANNEL         = 0x00400000,
@@ -1042,6 +1045,10 @@ struct aic7xxx_host {
   unsigned long            isr_count;        /* Interrupt count */
   unsigned long            spurious_int;
   scb_data_type           *scb_data;
+  volatile unsigned short  needsdtr;
+  volatile unsigned short  sdtr_pending;
+  volatile unsigned short  needwdtr;
+  volatile unsigned short  wdtr_pending;
   struct aic7xxx_cmd_queue {
     Scsi_Cmnd *head;
     Scsi_Cmnd *tail;
@@ -1073,12 +1080,15 @@ struct aic7xxx_host {
   volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
   unsigned char            dev_commands_sent[MAX_TARGETS];
 
+  unsigned int             dev_timer_active; /* Which devs have a timer set */
+  struct timer_list        dev_timer;
+  unsigned long            dev_expires[MAX_TARGETS];
+
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
   spinlock_t               spin_lock;
   volatile unsigned char   cpu_lock_count[NR_CPUS];
 #endif
 
-  unsigned short           dev_timer_active; /* Which devs have a timer set */
 
 #ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
   Scsi_Cmnd               *dev_wdtr_cmnd[MAX_TARGETS];
@@ -1091,12 +1101,6 @@ struct aic7xxx_host {
 
   volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
 
-  unsigned long            dev_expires[MAX_TARGETS];
-  struct timer_list        dev_timer;
-
-  /*
-   * The next 64....
-   */
 
   unsigned char            msg_buf[9];       /* The message for the target */
   unsigned char            msg_type;
@@ -1123,16 +1127,11 @@ struct aic7xxx_host {
   volatile unsigned char   qoutfifo[256];
   volatile unsigned char   qinfifo[256];
   unsigned int             irq;              /* IRQ for this adapter */
-  volatile unsigned short  needsdtr;
-  volatile unsigned short  sdtr_pending;
-  volatile unsigned short  needwdtr;
-  volatile unsigned short  wdtr_pending;
   int                      instance;         /* aic7xxx instance number */
   int                      scsi_id;          /* host adapter SCSI ID */
   int                      scsi_id_b;        /* channel B for twin adapters */
   unsigned int             bios_address;
   int                      board_name_index;
-  unsigned long            reset_start;
   unsigned short           needsdtr_copy;    /* default config */
   unsigned short           needwdtr_copy;    /* default config */
   unsigned short           ultraenb;         /* Ultra mode target list */
@@ -1150,7 +1149,6 @@ struct aic7xxx_host {
   struct Scsi_Host        *host;             /* pointer to scsi host */
   int                      host_no;          /* SCSI host number */
   unsigned long            mbase;            /* I/O memory address */
-  unsigned long            last_reset;
   ahc_chip                 chip;             /* chip type */
 
   /*
@@ -1166,21 +1164,21 @@ struct aic7xxx_host {
    *
    * NOTE: Enabling this feature is likely to cause a noticeable performance
    * decrease as the accesses into the stats structures blows apart multiple
-   * cache lines and is CPU time consuming.  We keep the xfer count always
-   * for use by the aic7xxx_proc.c code, but only do the bins if the
-   * proc stats code is enabled.
+   * cache lines and is CPU time consuming.
+   *
+   * NOTE: Since it doesn't really buy us much, but consumes *tons* of RAM
+   * and blows apart all sorts of cache lines, I modified this so that we
+   * no longer look at the LUN.  All LUNs now go into the same bin on each
+   * device for stats purposes.
    */
   struct aic7xxx_xferstats {
-    long w_total;                            /* total writes */
-    long r_total;                            /* total reads */
+    long w_total;                          /* total writes */
+    long r_total;                          /* total reads */
 #ifdef AIC7XXX_PROC_STATS
-    long xfers;                              /* total xfer count */
-    long w_total512;                         /* 512 byte blocks written */
-    long r_total512;                         /* 512 byte blocks read */
-    long w_bins[10];                         /* binned write */
-    long r_bins[10];                         /* binned reads */
+    long w_bins[8];                       /* binned write */
+    long r_bins[8];                       /* binned reads */
 #endif /* AIC7XXX_PROC_STATS */
-  } stats[MAX_TARGETS][MAX_LUNS];            /* [(channel << 3)|target][lun] */
+  } stats[MAX_TARGETS];                    /* [(channel << 3)|target] */
 
 #if 0
   struct target_cmd       *targetcmds;
@@ -3092,7 +3090,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       int x;
 #endif /* AIC7XXX_PROC_STATS */
 
-      sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7];
+      sp = &p->stats[TARGET_INDEX(cmd)];
 
       /*
        * For block devices, cmd->request.cmd is always == either READ or
@@ -3109,8 +3107,6 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
           aic7xxx_verbose &= 0xffff;
 #endif
 #ifdef AIC7XXX_PROC_STATS
-        sp->xfers++;
-        sp->w_total512 += (actual >> 9);
         ptr = sp->w_bins;
 #endif /* AIC7XXX_PROC_STATS */
       }
@@ -3122,23 +3118,27 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
           aic7xxx_verbose &= 0xffff;
 #endif
 #ifdef AIC7XXX_PROC_STATS
-        sp->xfers++;
-        sp->r_total512 += (actual >> 9);
         ptr = sp->r_bins;
 #endif /* AIC7XXX_PROC_STATS */
       }
 #ifdef AIC7XXX_PROC_STATS
-      for (x = 9; x <= 17; x++)
+      x = -10;
+      while(actual)
       {
-        if (actual < (1 << x))
-        {
-          ptr[x - 9]++;
-          break;
-        }
+        actual >>= 1;
+        x++;
+      }
+      if (x < 0)
+      {
+        ptr[0]++;
+      }
+      else if (x > 7)
+      {
+        ptr[7]++;
       }
-      if (x > 17)
+      else
       {
-        ptr[x - 9]++;
+        ptr[x]++;
       }
 #endif /* AIC7XXX_PROC_STATS */
     }
@@ -3486,13 +3486,13 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
             "delayed_scbs queue!\n", p->host_no, channel, i, lun);
         scbq_init(&p->delayed_scbs[i]);
       }
-      if ( !(p->dev_timer_active & (0x01 << p->scsi_id)) ||
+      if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
             time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
       {
         del_timer(&p->dev_timer);
         p->dev_timer.expires = p->dev_expires[i];
         add_timer(&p->dev_timer);
-        p->dev_timer_active |= (0x01 << p->scsi_id);
+        p->dev_timer_active |= (0x01 << MAX_TARGETS);
       }
     }
   }
@@ -3958,12 +3958,6 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
    */
   aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
 
-  /*
-   * Convince Mid Level SCSI code to leave us be for a little bit...
-   */
-  p->last_reset = jiffies;
-  p->host->last_reset = (jiffies + (HZ * AIC7XXX_RESET_DELAY));
-
   if ( !(p->features & AHC_TWIN) )
   {
     restart_sequencer(p);
@@ -4009,7 +4003,8 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
     }
     if ( (p->dev_active_cmds[tindex] >=
           p->dev_temp_queue_depth[tindex]) ||
-         (p->dev_flags[tindex] & (DEVICE_RESET_DELAY|DEVICE_WAS_BUSY)) )
+         (p->dev_flags[tindex] & (DEVICE_RESET_DELAY|DEVICE_WAS_BUSY)) ||
+         (p->flags & AHC_RESET_DELAY) )
     {
       scbq_insert_tail(&p->delayed_scbs[tindex], scb);
     }
@@ -4128,14 +4123,17 @@ aic7xxx_timer(struct aic7xxx_host *p)
 #else
   spin_lock_irqsave(&io_request_lock, cpu_flags);
 #endif
-  p->dev_timer_active &= ~(0x01 << p->scsi_id);
+  p->dev_timer_active &= ~(0x01 << MAX_TARGETS);
+  if ( (p->dev_timer_active & (0x01 << p->scsi_id)) &&
+       time_after_eq(jiffies, p->dev_expires[p->scsi_id]) )
+  {
+    p->flags &= ~AHC_RESET_DELAY;
+    p->dev_timer_active &= ~(0x01 << p->scsi_id);
+  }
   for(i=0; i<MAX_TARGETS; i++)
   {
-    if ( i == p->scsi_id )
-    {
-      continue;
-    }
-    if ( (p->dev_timer_active & (0x01 << i)) &&
+    if ( (i != p->scsi_id) &&
+         (p->dev_timer_active & (0x01 << i)) &&
          time_after_eq(jiffies, p->dev_expires[i]) )
     {
       p->dev_timer_active &= ~(0x01 << i);
@@ -4161,7 +4159,7 @@ aic7xxx_timer(struct aic7xxx_host *p)
     }
     else if ( p->dev_timer_active & (0x01 << i) )
     {
-      if ( p->dev_timer_active & (0x01 << p->scsi_id) )
+      if ( p->dev_timer_active & (0x01 << MAX_TARGETS) )
       {
         if ( time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
         {
@@ -4171,11 +4169,11 @@ aic7xxx_timer(struct aic7xxx_host *p)
       else
       {
         p->dev_timer.expires = p->dev_expires[i];
-        p->dev_timer_active |= (0x01 << p->scsi_id);
+        p->dev_timer_active |= (0x01 << MAX_TARGETS);
       }
     }
   }
-  if ( p->dev_timer_active & (0x01 << p->scsi_id) )
+  if ( p->dev_timer_active & (0x01 << MAX_TARGETS) )
   {
     add_timer(&p->dev_timer);
   }
@@ -4901,10 +4899,10 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                 {
                   p->dev_expires[tindex] = jiffies + (HZ / 10);
                 }
-                if ( !(p->dev_timer_active & (0x01 << p->scsi_id)) )
+                if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) )
                 {
                   p->dev_timer.expires = p->dev_expires[tindex];
-                  p->dev_timer_active |= (0x01 << p->scsi_id);
+                  p->dev_timer_active |= (0x01 << MAX_TARGETS);
                   add_timer(&p->dev_timer);
                 }
                 else if ( time_after_eq(p->dev_timer.expires,
@@ -6398,11 +6396,7 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
   {
     int tag_enabled = TRUE;
 
-#ifdef AIC7XXX_CMDS_PER_LUN
     default_depth = AIC7XXX_CMDS_PER_LUN;
-#else
-    default_depth = 8;  /* Not many SCBs to work with. */
-#endif
  
     if (!(p->discenable & target_mask))
     {
@@ -7448,7 +7442,6 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
   }
 
   p->host = host;
-  p->last_reset = jiffies;
   p->host_no = host->host_no;
   host->unique_id = p->instance;
   p->isr_count = 0;
@@ -7534,10 +7527,9 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
   }
   aic_outb(p, 0, SEQ_FLAGS);
 
-  /*
-   * Detect SCB parameters and initialize the SCB array.
-   */
   detect_maxscb(p);
+
+
   printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
   if (aic7xxx_verbose & VERBOSE_PROBE2)
   {
@@ -8841,6 +8833,10 @@ aic7xxx_detect(Scsi_Host_Template *template)
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7890_FE,                                      20,
        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_78902, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      20,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7890_FE,                                      21,
@@ -8865,9 +8861,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
 
     unsigned short command;
     unsigned int  devconfig, i, oldverbose;
-#ifdef MMAPIO
-    unsigned long page_offset, base;
-#endif
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
     struct pci_dev *pdev = NULL;
 #else
@@ -9018,21 +9011,68 @@ aic7xxx_detect(Scsi_Host_Template *template)
           temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
           temp_p->unpause = INTEN;
           temp_p->pause = temp_p->unpause | PAUSE;
+          if ( ((temp_p->base == 0) &&
+                (temp_p->mbase == 0)) ||
+               (temp_p->irq == 0) )
+          {
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              PCI_SLOT(temp_p->pdev->devfn),
+              PCI_FUNC(temp_p->pdev->devfn));
+            printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
+            kfree(temp_p);
+            temp_p = NULL;
+            continue;
+          }
 
 #ifdef MMAPIO
-          base = temp_p->mbase & PAGE_MASK;
-          page_offset = temp_p->mbase - base;
+          {
+            unsigned long page_offset, base;
+
+            base = temp_p->mbase & PAGE_MASK;
+            page_offset = temp_p->mbase - base;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-          temp_p->maddr = ioremap_nocache(base, page_offset + 256);
+            temp_p->maddr = ioremap_nocache(base, page_offset + 256);
 #else
-          temp_p->maddr = vremap(base, page_offset + 256);
+            temp_p->maddr = vremap(base, page_offset + 256);
 #endif
-          if(temp_p->maddr)
-          {
-            temp_p->maddr += page_offset;
+            if(temp_p->maddr)
+            {
+              temp_p->maddr += page_offset;
+              /*
+               * We need to check the I/O with the MMAPed address.  Some machines
+               * simply fail to work with MMAPed I/O and certain controllers.
+               */
+              if(aic_inb(temp_p, HCNTRL) == 0xff)
+              {
+                /*
+                 * OK.....we failed our test....go back to programmed I/O
+                 */
+                printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n", 
+                  board_names[aic_pdevs[i].board_name_index],
+                  PCI_SLOT(temp_p->pdev->devfn),
+                  PCI_FUNC(temp_p->pdev->devfn));
+                printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
+                                 "Programmed I/O.\n");
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+                iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
+#else
+                vfree((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
+#endif
+                temp_p->maddr = 0;
+              }
+            }
           }
 #endif
 
+          /*
+           * We HAVE to make sure the first pause_sequencer() and all other
+           * subsequent I/O that isn't PCI config space I/O takes place
+           * after the MMAPed I/O region is configured and tested.  The
+           * problem is the PowerPC architecture that doesn't support
+           * programmed I/O at all, so we have to have the MMAP I/O set up
+           * for this pause to even work on those machines.
+           */
           pause_sequencer(temp_p);
 
           /*
@@ -9067,30 +9107,20 @@ aic7xxx_detect(Scsi_Host_Template *template)
           }
 
           /*
-           * Doing a switch based upon i is really gross, but since Justin
-           * changed around the chip ID stuff, we can't use that any more.
-           * Since we don't scan the devices the same way as FreeBSD, we end
-           * up doing this gross hack in order to avoid totally splitting
-           * away from Justin's init code in ahc_pci.c
+           * We need to set the CHNL? assignments before loading the SEEPROM
+           * The 3940 and 3985 cards (original stuff, not any of the later
+           * stuff) are 7870 and 7880 class chips.  The Ultra2 stuff falls
+           * under 7896 and 7897.  The 7895 is in a class by itself :)
            */
-          switch (i)
+          switch (temp_p->chip & AHC_CHIPID_MASK)
           {
-            case 7:   /* 3940 */
-            case 12:  /* 3940-Ultra */
+            case AHC_AIC7870: /* 3840 / 3985 */
+            case AHC_AIC7880: /* 3840 UW / 3985 UW */
               switch(PCI_SLOT(temp_p->pci_device_fn))
               {
                 case 5:
                   temp_p->flags |= AHC_CHNLB;
                   break;
-                default:
-                  break;
-              }
-              break;
-
-            case 8:   /* 3985 */
-            case 13:  /* 3985-Ultra */
-              switch(PCI_SLOT(temp_p->pci_device_fn))
-              {
                 case 8:
                   temp_p->flags |= AHC_CHNLB;
                   break;
@@ -9102,10 +9132,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
               }
               break;
 
-            case 15:
-            case 18:
-            case 19:
-            case 20:
+            case AHC_AIC7895: /* 7895 */
+            case AHC_AIC7896: /* 7896/7 */
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
               if (PCI_FUNC(temp_p->pdev->devfn) != 0)
               {
@@ -10894,23 +10922,14 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
     }
     action = BUS_RESET;
   }
-  if ( ((jiffies - p->last_reset) < (HZ * 3)) &&
-        (action & (HOST_RESET | BUS_RESET)) )
+  if ( (p->flags & AHC_RESET_DELAY) &&
+       (action & (HOST_RESET | BUS_RESET)) )
   {
     if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
       printk(INFO_LEAD "Reset called too soon after "
         "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
     action = RESET_DELAY;
   }
-  if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & AHC_IN_RESET)
-        && ((jiffies - p->reset_start) > (2 * HZ * 3)) )
-  {
-    printk(KERN_ERR "(scsi%d:%d:%d:%d) Yikes!!  Card must have left to go "
-        "back to Adaptec!!\n", p->host_no, CTL_OF_CMD(cmd));
-    unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
-    return(SCSI_RESET_SNOOZE);
-  }
 /*
  *  By this point, we want to already know what we are going to do and
  *  only have the following code implement our course of action.
@@ -10942,15 +10961,23 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
     case BUS_RESET:
     case HOST_RESET:
     default:
-      p->reset_start = jiffies;
-      p->flags |= AHC_IN_RESET;
+      p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
+      p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
+      p->dev_timer_active |= (0x01 << p->scsi_id);
+      if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
+            time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
+      {
+        del_timer(&p->dev_timer);
+        p->dev_timer.expires = p->dev_expires[p->scsi_id];
+        add_timer(&p->dev_timer);
+        p->dev_timer_active |= (0x01 << MAX_TARGETS);
+      }
       aic7xxx_reset_channel(p, cmd->channel, TRUE);
       if ( (p->features & AHC_TWIN) && (action & HOST_RESET) )
       {
         aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
         restart_sequencer(p);
       }
-      p->last_reset = jiffies;
       if (action != HOST_RESET)
         result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
       else
@@ -10974,7 +11001,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
        */
       if ( flags & SCSI_RESET_SYNCHRONOUS )
       {
-        cmd->result = DID_RESET << 16;
+        cmd->result = DID_BUS_BUSY << 16;
         cmd->done(cmd);
       }
       p->flags &= ~AHC_IN_RESET;
index 3e6e4c678fb775291dfb4e112e6663310444d78f..6e5eca864a8c6dc7ff469b371addf5b9e0350145 100644 (file)
@@ -31,7 +31,7 @@
 
 #define        BLS     (&aic7xxx_buffer[size])
 #define HDRB \
-"        < 512 512-1K   1-2K   2-4K   4-8K  8-16K 16-32K 32-64K 64-128K >128K"
+"             < 2K      2K+     4K+     8K+    16K+    32K+    64K+   128K+"
 
 #ifdef PROC_DEBUG
 extern int vsprintf(char *, const char *, va_list);
@@ -86,7 +86,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   int    size = 0;
   unsigned char i;
   struct aic7xxx_xferstats *sp;
-  unsigned char target, lun;
+  unsigned char target;
 
   HBAptr = NULL;
 
@@ -130,15 +130,12 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   size = 4096;
   for (target = 0; target < MAX_TARGETS; target++)
   {
-    for (lun = 0; lun < MAX_LUNS; lun++)
-    {
-      if (p->stats[target][lun].r_total != 0)
+    if (p->dev_flags[target] & DEVICE_PRESENT)
 #ifdef AIC7XXX_PROC_STATS
-        size += 512;
+      size += 512;
 #else
-        size += 256;
+      size += 256;
 #endif
-    }
   }
   if (aic7xxx_buffer_size != size)
   {
@@ -272,88 +269,83 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
   size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
 
   size += sprintf(BLS, "\n");
-  size += sprintf(BLS, "Statistics:\n");
+  size += sprintf(BLS, "Statistics:\n\n");
   for (target = 0; target < MAX_TARGETS; target++)
   {
-    for (lun = 0; lun < MAX_LUNS; lun++)
+    sp = &p->stats[target];
+    if ((p->dev_flags[target] & DEVICE_PRESENT) == 0)
     {
-      sp = &p->stats[target][lun];
-      if (sp->r_total == 0)
-      {
-        continue;
-      }
-      if (p->features & AHC_TWIN)
+      continue;
+    }
+    if (p->features & AHC_TWIN)
+    {
+      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+          p->host_no, (target >> 3), (target & 0x7), 0);
+    }
+    else
+    {
+      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+          p->host_no, 0, target, 0);
+    }
+    size += sprintf(BLS, "  Device using %s/%s",
+          (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
+          "Wide" : "Narrow",
+          (p->transinfo[target].cur_offset != 0) ?
+          "Sync transfers at " : "Async transfers.\n" );
+    if (p->transinfo[target].cur_offset != 0)
+    {
+      struct aic7xxx_syncrate *sync_rate;
+      int period = p->transinfo[target].cur_period;
+      int rate = (p->transinfo[target].cur_width ==
+                  MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
+
+      sync_rate = aic7xxx_find_syncrate(p, &period, AHC_SYNCRATE_ULTRA2);
+      if (sync_rate != NULL)
       {
-        size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
-            p->host_no, (target >> 3), (target & 0x7), lun);
+        size += sprintf(BLS, "%s MByte/sec, offset %d\n",
+                        sync_rate->rate[rate],
+                        p->transinfo[target].cur_offset );
       }
       else
       {
-        size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
-            p->host_no, 0, target, lun);
+        size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
+                        p->transinfo[target].cur_offset );
       }
-      size += sprintf(BLS, "  Device using %s/%s\n",
-            (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
-            "Wide" : "Narrow",
-            (p->transinfo[target].cur_offset != 0) ?
-            "Sync transfers at" : "Async transfers." );
-      if (p->transinfo[target].cur_offset != 0)
-      {
-        struct aic7xxx_syncrate *sync_rate;
-        int period = p->transinfo[target].cur_period;
-        int rate = (p->transinfo[target].cur_width ==
-                    MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
-
-        sync_rate = aic7xxx_find_syncrate(p, &period, AHC_SYNCRATE_ULTRA2);
-        if (sync_rate != NULL)
-        {
-          size += sprintf(BLS, "  %s MByte/sec, offset %d\n",
-                          sync_rate->rate[rate],
-                          p->transinfo[target].cur_offset );
-        }
-        else
-        {
-          size += sprintf(BLS, "  3.3 MByte/sec, offset %d\n",
-                          p->transinfo[target].cur_offset );
-        }
-      }
-      size += sprintf(BLS, "    Device Negotiation Settings\n");
-      size += sprintf(BLS, "        Period Offset Bus Width\n");
-      size += sprintf(BLS, "User       %03d    %03d        %d\n",
-                      p->transinfo[target].user_period,
-                      p->transinfo[target].user_offset,
-                      p->transinfo[target].user_width);
-      size += sprintf(BLS, "Goal       %03d    %03d        %d\n",
-                      p->transinfo[target].goal_period,
-                      p->transinfo[target].goal_offset,
-                      p->transinfo[target].goal_width);
-      size += sprintf(BLS, "Current    %03d    %03d        %d\n",
-                      p->transinfo[target].cur_period,
-                      p->transinfo[target].cur_offset,
-                      p->transinfo[target].cur_width);
+    }
+    size += sprintf(BLS, "  Transinfo settings: ");
+    size += sprintf(BLS, "current(%d/%d/%d), ",
+                    p->transinfo[target].cur_period,
+                    p->transinfo[target].cur_offset,
+                    p->transinfo[target].cur_width);
+    size += sprintf(BLS, "goal(%d/%d/%d), ",
+                    p->transinfo[target].goal_period,
+                    p->transinfo[target].goal_offset,
+                    p->transinfo[target].goal_width);
+    size += sprintf(BLS, "user(%d/%d/%d)\n",
+                    p->transinfo[target].user_period,
+                    p->transinfo[target].user_offset,
+                    p->transinfo[target].user_width);
 #ifdef AIC7XXX_PROC_STATS
-      size += sprintf(BLS, "    Total transfers %ld (%ld read;%ld written)\n",
-          sp->xfers, sp->r_total, sp->w_total);
-      size += sprintf(BLS, "      blks(512) rd=%ld; blks(512) wr=%ld\n",
-          sp->r_total512, sp->w_total512);
-      size += sprintf(BLS, "%s\n", HDRB);
-      size += sprintf(BLS, " Reads:");
-      for (i = 0; i < NUMBER(sp->r_bins); i++)
-      {
-        size += sprintf(BLS, "%6ld ", sp->r_bins[i]);
-      }
-      size += sprintf(BLS, "\n");
-      size += sprintf(BLS, "Writes:");
-      for (i = 0; i < NUMBER(sp->w_bins); i++)
-      {
-        size += sprintf(BLS, "%6ld ", sp->w_bins[i]);
-      }
+    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
+        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
+    size += sprintf(BLS, "%s\n", HDRB);
+    size += sprintf(BLS, "   Reads:");
+    for (i = 0; i < NUMBER(sp->r_bins); i++)
+    {
+      size += sprintf(BLS, " %7ld", sp->r_bins[i]);
+    }
+    size += sprintf(BLS, "\n");
+    size += sprintf(BLS, "  Writes:");
+    for (i = 0; i < NUMBER(sp->w_bins); i++)
+    {
+      size += sprintf(BLS, " %7ld", sp->w_bins[i]);
+    }
+    size += sprintf(BLS, "\n");
 #else
-      size += sprintf(BLS, "    Total transfers: %ld/%ld read/written)\n",
-          sp->r_total, sp->w_total);
+    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
+        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
 #endif /* AIC7XXX_PROC_STATS */
-      size += sprintf(BLS, "\n\n");
-    }
+    size += sprintf(BLS, "\n\n");
   }
 
   if (size >= aic7xxx_buffer_size)
index 67fde6e8ac0a58625e5502184c9e0a48292e6352..98791e972729bda78976478a67d08291245fc75a 100644 (file)
@@ -279,6 +279,7 @@ static struct dev_info device_list[] =
 {"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"YAMAHA","CDR100","1.00", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
 {"YAMAHA","CDR102","1.00", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
+{"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN},
 /*
  * Must be at end of list...
  */
index 53cf0ba76655e7ed320ffc000d185eb82fb10d09..3f7823eb32e624e38693eff5a334b607a60216fc 100644 (file)
@@ -203,6 +203,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
 
   dep_tristate 'Support for Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
   if [ "$CONFIG_SOUND_OPL3SA2" = "y" ]; then
+      int 'Chipset (-1 for autoprobe, 2, or 3)' CONFIG_OPL3SA2_CHIPSET -1
       hex 'OPL3SA2 audio I/O base (530 - F48 valid)' CONFIG_OPL3SA2_BASE 530
       int 'OPL3SA2 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_IRQ 9
       int 'OPL3SA2 audio DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA 0
index 38e4b8a42a56c214171f244429bfe7fe834534e9..40f8b78c366ca6b1853ddadb3301e17e125f9f06 100644 (file)
@@ -24,8 +24,7 @@ endif
 
 export-objs    :=  ad1848.o audio_syms.o midi_syms.o mpu401.o \
                    msnd.o opl3.o sb_card.o sequencer_syms.o \
-                   sound_core.o sound_firmware.o sound_syms.o \
-                   uart401.o ad1816.o
+                   sound_core.o sound_syms.o uart401.o ad1816.o
 
 
 
@@ -296,7 +295,7 @@ trix.o: trix_boot.h
 
 ifeq ($(CONFIG_TRIX_HAVE_BOOT),y)
     trix_boot.h: $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE)) hex2hex
-       hex2hex -i trix_boot < $(CONFIG_TRIX_BOOT_FILE) > $@
+       ./hex2hex -i trix_boot < $(CONFIG_TRIX_BOOT_FILE) > $@
 else
     trix_boot.h:
        (                                                       \
index 240e0dd68a11b290b68756abd0cb155a6afc2fd3..f24c33fe2ccc83c5392c8f2c5d55a1e4946d631a 100644 (file)
@@ -1944,10 +1944,11 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
                        if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */
                                free_irq(devc->irq, (void *)devc->dev_no);
 
-                       sound_free_dma(audio_devs[dev]->dmap_out->dma);
+                       sound_free_dma(dma_playback);
+
+                       if (dma_playback != dma_capture)
+                               sound_free_dma(dma_capture);
 
-                       if (audio_devs[dev]->dmap_in->dma != audio_devs[dev]->dmap_out->dma)
-                               sound_free_dma(audio_devs[dev]->dmap_in->dma);
                }
                mixer = audio_devs[devc->dev_no]->mixer_dev;
                if(mixer>=0)
index 7e5c4b76c71dfbae9c84d774436d0352b2348a7e..9a6b4c72f59aa57a02573a026bae722f7aa81a4c 100644 (file)
@@ -524,7 +524,7 @@ void sound_unload_audiodev(int dev)
 
 int sound_alloc_audiodev(void)
 { 
-       int i = register_sound_dsp(&oss_sound_fops);
+       int i = register_sound_dsp(&oss_sound_fops, -1);
        if(i==-1)
                return i;
        i>>=4;
@@ -536,7 +536,7 @@ int sound_alloc_audiodev(void)
 int sound_alloc_mididev(void)
 {
 #ifdef CONFIG_MIDI
-       int i = register_sound_midi(&oss_sound_fops);
+       int i = register_sound_midi(&oss_sound_fops, -1);
        if(i==-1)
                return i;
        i>>=4;
@@ -566,7 +566,7 @@ int sound_alloc_synthdev(void)
 
 int sound_alloc_mixerdev(void)
 {
-       int i = register_sound_mixer(&oss_sound_fops);
+       int i = register_sound_mixer(&oss_sound_fops, -1);
        if(i==-1)
                return -1;
        i>>=4;
index 77963cfe01879fac1ccd55106fc867731f9b07ee..43b419817753f8c4dfe1daf2d23533accf040c1f 100644 (file)
@@ -3853,7 +3853,7 @@ static void __init mixer_init(void)
 #ifndef MODULE
        int mixer_unit;
 #endif
-       mixer_unit = register_sound_mixer(&mixer_fops);
+       mixer_unit = register_sound_mixer(&mixer_fops, -1);
        if (mixer_unit < 0)
                return;
 
@@ -4258,7 +4258,7 @@ static void __init sq_init(void)
 #ifndef MODULE
        int sq_unit;
 #endif
-       sq_unit = register_sound_dsp(&sq_fops);
+       sq_unit = register_sound_dsp(&sq_fops, -1);
        if (sq_unit < 0)
                return;
 
index b202c38f04037c26d41c92c95448e315c7d68dfb..f0837aa5546de553fdcae8e6eed9186f4d005dd1 100644 (file)
@@ -2321,13 +2321,13 @@ __initfunc(int init_es1370(void))
                       (s->ctrl & CTRL_XCTL0) ? "out" : "in",
                       (s->ctrl & CTRL_XCTL1) ? "1" : "0");
                /* register devices */
-               if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops)) < 0)
+               if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0)
                        goto err_dev1;
-               if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops)) < 0)
+               if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops, -1)) < 0)
                        goto err_dev2;
-               if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops)) < 0)
+               if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops, -1)) < 0)
                        goto err_dev3;
-               if ((s->dev_midi = register_sound_midi(&es1370_midi_fops)) < 0)
+               if ((s->dev_midi = register_sound_midi(&es1370_midi_fops, -1)) < 0)
                        goto err_dev4;
                /* initialize the chips */
                outl(s->ctrl, s->io+ES1370_REG_CONTROL);
index d95a647272c8a1db88954bfdabe0001a0f33fedb..3154cddd6e9e1937dd8785b7e8724ba10c619c76 100644 (file)
@@ -2745,13 +2745,13 @@ __initfunc(int init_es1371(void))
                printk(KERN_INFO "es1371: found adapter at io %#06x irq %u\n"
                       KERN_INFO "es1371: features: joystick 0x%x\n", s->io, s->irq, joystick[index]);
                /* register devices */
-               if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops)) < 0)
+               if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0)
                        goto err_dev1;
-               if ((s->dev_mixer = register_sound_mixer(&es1371_mixer_fops)) < 0)
+               if ((s->dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0)
                        goto err_dev2;
-               if ((s->dev_dac = register_sound_dsp(&es1371_dac_fops)) < 0)
+               if ((s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1)) < 0)
                        goto err_dev3;
-               if ((s->dev_midi = register_sound_midi(&es1371_midi_fops)) < 0)
+               if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0)
                        goto err_dev4;
                /* initialize codec registers */
                s->ctrl = 0;
index 9109658d456b26b34488ed9ab8e91fa452bac5bc..7bf7364ab9e7f501e25c4e83894ec85698896b64 100644 (file)
@@ -1450,7 +1450,7 @@ __initfunc(static int attach_multisound(void))
                return err;
        }
 
-       if ((dev.dsp_minor = register_sound_dsp(&dev_fileops)) < 0) {
+       if ((dev.dsp_minor = register_sound_dsp(&dev_fileops, -1)) < 0) {
                printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n");
                msnd_unregister(&dev);
                release_region(dev.io, dev.numio);
@@ -1458,7 +1458,7 @@ __initfunc(static int attach_multisound(void))
                return dev.dsp_minor;
        }
 
-       if ((dev.mixer_minor = register_sound_mixer(&dev_fileops)) < 0) {
+       if ((dev.mixer_minor = register_sound_mixer(&dev_fileops, -1)) < 0) {
                printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n");
                unregister_sound_mixer(dev.mixer_minor);
                msnd_unregister(&dev);
index 8be3b91a92d54bdeec537aed8897de45c85b49f5..3414387488423fd4445d1715dd6df9ebc751192d 100644 (file)
@@ -260,6 +260,7 @@ void unload_opl3sa_wss(struct address_info *hw_config)
                      hw_config->dma,
                      dma2,
                      0);
+       sound_unload_audiodev(hw_config->slots[0]);
 }
 
 void unload_opl3sa_mpu(struct address_info *hw_config)
index d2237ffe04e83607f70d96fbab427b6c57eb3a3c..eda25872ebc7d7fc479c0ca9b5d92b2c3e2eeb70 100644 (file)
@@ -26,6 +26,9 @@
  * Scott Murray            Original driver (Jun 14, 1998)
  * Paul J.Y. Lahaie        Changed probing / attach code order
  * Scott Murray            Added mixer support (Dec 03, 1998)
+ * Scott Murray            Changed detection code to be more forgiving,
+ *                         added force option as last resort,
+ *                         fixed ioctl return values. (Dec 30, 1998)
  *
  */
 
 #define DEFAULT_MIC    50
 #define DEFAULT_TIMBRE 0
 
+/*
+ * NOTE: CHIPSET_UNKNOWN should match the default value of
+ *       CONFIG_OPL3SA2_CHIPSET in Config.in to make everything
+ *       work right in all situations.
+ */
 #define CHIPSET_UNKNOWN -1
 #define CHIPSET_OPL3SA2  1
 #define CHIPSET_OPL3SA3  2
 #ifdef CONFIG_OPL3SA2
 
 /* What's my version? */
-static int chipset_version = CHIPSET_UNKNOWN;
+#ifdef CONFIG_OPL3SA2_CHIPSET
+/* Set chipset if compiled into the kernel */
+static int chipset = CONFIG_OPL3SA2_CHIPSET;
+#else
+static int chipset = CHIPSET_UNKNOWN;
+#endif
 
 /* Oh well, let's just cache the name */
 static char chipset_name[16];
@@ -276,43 +289,47 @@ static int opl3sa2_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
                                        return call_ad_mixer(devc, cmd, arg);
                                else
                                {
-                                       if(*(int *)arg != 0)
+                                       if(*(int*)arg != 0)
                                                return -EINVAL;
                                        return 0;
                                }
 
                        case SOUND_MIXER_VOLUME:
-                               arg_to_volume_stereo(*(unsigned int *)arg,
+                               arg_to_volume_stereo(*(unsigned int*)arg,
                                                     &devc->volume_l,
                                                     &devc->volume_r); 
                                opl3sa2_set_volume(devc, devc->volume_l,
                                                   devc->volume_r);
-                               return ret_vol_stereo(devc->volume_l,
-                                                     devc->volume_r);
+                               *(int*)arg = ret_vol_stereo(devc->volume_l,
+                                                            devc->volume_r);
+                               return 0;
                  
                        case SOUND_MIXER_MIC:
-                               arg_to_volume_mono(*(unsigned int *)arg,
+                               arg_to_volume_mono(*(unsigned int*)arg,
                                                   &devc->mic);
                                opl3sa2_set_mic(devc, devc->mic);
-                               return ret_vol_mono(devc->mic);
+                               *(int*)arg = ret_vol_mono(devc->mic);
+                               return 0;
                  
                        case SOUND_MIXER_BASS:
-                               if(chipset_version != CHIPSET_OPL3SA2)
+                               if(chipset != CHIPSET_OPL3SA2)
                                {
-                                       arg_to_volume_mono(*(unsigned int *)arg,
+                                       arg_to_volume_mono(*(unsigned int*)arg,
                                                           &devc->bass);
                                        opl3sa3_set_bass(devc, devc->bass);
-                                       return ret_vol_mono(devc->bass);
+                                       *(int*)arg = ret_vol_mono(devc->bass);
+                                       return 0;
                                }
                                return -EINVAL;
                  
                        case SOUND_MIXER_TREBLE:
-                               if(chipset_version != CHIPSET_OPL3SA2)
+                               if(chipset != CHIPSET_OPL3SA2)
                                {
                                        arg_to_volume_mono(*(unsigned int *)arg,
                                                           &devc->treble);
                                        opl3sa3_set_treble(devc, devc->treble);
-                                       return ret_vol_mono(devc->treble);
+                                       *(int*)arg = ret_vol_mono(devc->treble);
+                                       return 0;
                                }
                                return -EINVAL;
                  
@@ -331,55 +348,83 @@ static int opl3sa2_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
                                if(call_ad_mixer(devc, cmd, arg) == -EINVAL)
                                        *(int*)arg = 0; /* no mixer devices */
 
-                               if(chipset_version != CHIPSET_OPL3SA2)
-                                       return (*(int*)arg |= SOUND_MASK_VOLUME |
-                                                             SOUND_MASK_MIC |
-                                                             SOUND_MASK_BASS |
-                                                             SOUND_MASK_TREBLE);
+                               *(int*)arg |= (SOUND_MASK_VOLUME | SOUND_MASK_MIC);
+
                                /* OPL3-SA2 has no bass and treble mixers */
-                               return (*(int*)arg |= SOUND_MASK_VOLUME |
-                                                     SOUND_MASK_MIC);
+                               if(chipset != CHIPSET_OPL3SA2)
+                                       *(int*)arg |= (SOUND_MASK_BASS |
+                                                      SOUND_MASK_TREBLE);
+                               return 0;
                  
                        case SOUND_MIXER_STEREODEVS:
                                if(call_ad_mixer(devc, cmd, arg) == -EINVAL)
                                        *(int*)arg = 0; /* no stereo devices */
-                               return (*(int*)arg |= SOUND_MASK_VOLUME);
+                               *(int*)arg |= SOUND_MASK_VOLUME;
+                               return 0;
                  
                        case SOUND_MIXER_RECMASK:
                                if(devc->ad_mixer_dev != -1)
+                               {
                                        return call_ad_mixer(devc, cmd, arg);
+                               }
                                else
-                                       return (*(int*)arg = 0); /* no record devices */
+                               {
+                                       /* No recording devices */
+                                       return (*(int*)arg = 0);
+                               }
 
                        case SOUND_MIXER_CAPS:
                                if(devc->ad_mixer_dev != -1)
+                               {
                                        return call_ad_mixer(devc, cmd, arg);
+                               }
                                else
-                                       return (*(int*)arg = SOUND_CAP_EXCL_INPUT);
+                               {
+                                       *(int*)arg = SOUND_CAP_EXCL_INPUT;
+                                       return 0;
+                               }
 
                        case SOUND_MIXER_RECSRC:
                                if(devc->ad_mixer_dev != -1)
+                               {
                                        return call_ad_mixer(devc, cmd, arg);
+                               }
                                else
-                                       return (*(int*)arg = 0); /* no record source */
+                               {
+                                       /* No recording source */
+                                       return (*(int*)arg = 0);
+                               }
 
                        case SOUND_MIXER_VOLUME:
-                               return (*(int*)arg = ret_vol_stereo(devc->volume_l,
-                                                                   devc->volume_r));
+                               *(int*)arg = ret_vol_stereo(devc->volume_l,
+                                                           devc->volume_r);
+                               return 0;
                          
                        case SOUND_MIXER_MIC:
-                               return (*(int*)arg = ret_vol_mono(devc->mic));
+                               *(int*)arg = ret_vol_mono(devc->mic);
+                               return 0;
 
                        case SOUND_MIXER_BASS:
-                               if(chipset_version != CHIPSET_OPL3SA2)
-                                       return (*(int*)arg = ret_vol_mono(devc->bass));
-                               return -EINVAL;
-
+                               if(chipset != CHIPSET_OPL3SA2)
+                               {
+                                       *(int*)arg = ret_vol_mono(devc->bass);
+                                       return 0;
+                               }
+                               else
+                               {
+                                       return -EINVAL;
+                               }
                          
                        case SOUND_MIXER_TREBLE:
-                               if(chipset_version != CHIPSET_OPL3SA2)
-                                       return (*(int*)arg = ret_vol_mono(devc->treble));
-                               return -EINVAL;
+                               if(chipset != CHIPSET_OPL3SA2)
+                               {
+                                       *(int*)arg = ret_vol_mono(devc->treble);
+                                       return 0;
+                               }
+                               else
+                               {
+                                       return -EINVAL;
+                               }
                          
                        default:
                                return -EINVAL;
@@ -481,6 +526,15 @@ static void unload_opl3sa2_mss(struct address_info *hw_config)
 
 int probe_opl3sa2(struct address_info *hw_config)
 {
+       unsigned char chipsets[8] = { CHIPSET_UNKNOWN, /* 0 */
+                                     CHIPSET_OPL3SA2, /* 1 */
+                                     CHIPSET_OPL3SA3, /* 2 */
+                                     CHIPSET_UNKNOWN, /* 3 */
+                                     CHIPSET_OPL3SAX, /* 4 */
+                                     CHIPSET_OPL3SAX, /* 5 */
+                                     CHIPSET_UNKNOWN, /* 6 */
+                                     CHIPSET_OPL3SA3, /* 7 */ };
+       unsigned char version = 0;
        char tag;
 
        /*
@@ -489,20 +543,80 @@ int probe_opl3sa2(struct address_info *hw_config)
        if(check_region(hw_config->io_base, 2))
        {
            printk(KERN_ERR
-                  "opl3sa2.c: Control I/O port 0x%03x not free\n",
+                  "%s: Control I/O port 0x%03x not free\n",
+                  __FILE__,
                   hw_config->io_base);
            return 0;
        }
 
        /*
-        * Look at chipset version in lower 3 bits of index 0x0A, miscellaneous
+        * Determine chipset type (SA2, SA3, or SAx)
+        *
+        * Have to handle two possible override situations:
+        * 1) User compiled driver into the kernel and forced chipset type
+        * 2) User built a module, but wants to override the chipset type
         */
-       chipset_version = 0;
-       opl3sa2_read(hw_config->io_base,
-                    OPL3SA2_MISC,
-                    (unsigned char*) &chipset_version);
-       chipset_version &= 0x0007;
-       switch(chipset_version)
+       if(chipset == CHIPSET_UNKNOWN)
+       {
+               if(hw_config->card_subtype == CHIPSET_UNKNOWN)
+               {
+                       /*
+                        * Look at chipset version in lower 3 bits of index 0x0A, miscellaneous
+                        */
+                       opl3sa2_read(hw_config->io_base,
+                                    OPL3SA2_MISC,
+                                    (unsigned char*) &version);
+                       version &= 0x07;
+
+                       /* Match version number to appropiate chipset */
+                       chipset = chipsets[version];
+               }
+               else
+               {
+                       /* Use user specified chipset */
+                       switch(hw_config->card_subtype)
+                       {
+                               case 2:
+                                       chipset = CHIPSET_OPL3SA2;
+                                       break;
+
+                               case 3:
+                                       chipset = CHIPSET_OPL3SA3;
+                                       break;
+
+                               default:
+                                       printk(KERN_ERR "%s: Unknown chipset %d\n",
+                                              __FILE__,
+                                              hw_config->card_subtype);
+                                       chipset = CHIPSET_UNKNOWN;
+                                       break;
+                       }
+               }
+       }
+       else
+       {
+               /* Use user compiled in chipset */
+               switch(chipset)
+               {
+                       case 2:
+                               chipset = CHIPSET_OPL3SA2;
+                               break;
+                               
+                       case 3:
+                               chipset = CHIPSET_OPL3SA3;
+                               break;
+
+                       default:
+                               printk(KERN_ERR "%s: Unknown chipset %d\n",
+                                      __FILE__,
+                                      chipset);
+                               chipset = CHIPSET_UNKNOWN;
+                               break;
+               }
+       }
+
+       /* Do chipset specific stuff: */
+       switch(chipset)
        {
                case CHIPSET_OPL3SA2:
                        printk(KERN_INFO "Found OPL3-SA2 (YMF711)\n");
@@ -521,15 +635,23 @@ int probe_opl3sa2(struct address_info *hw_config)
 
                default:
                        printk(KERN_ERR "No Yamaha audio controller found\n");
-                       printk(KERN_INFO
-                              "opl3sa2.c: chipset version = %x\n",
-                              chipset_version);
-                       chipset_version = CHIPSET_UNKNOWN;
+
+                       /* If we've actually checked the version, print it out */
+                       if(version)
+                       {
+                               printk(KERN_INFO
+                                      "%s: chipset version = %x\n",
+                                      __FILE__,
+                                      version);
+                       }
+                       
+                       /* Set some sane values */
+                       chipset = CHIPSET_UNKNOWN;
                        tag = '?';
                        break;
        }
 
-       if(chipset_version != CHIPSET_UNKNOWN) {
+       if(chipset != CHIPSET_UNKNOWN) {
                /* Generate a pretty name */
                sprintf(chipset_name, "OPL3-SA%c", tag);
                return 1;
@@ -565,6 +687,7 @@ int mpu_io  = -1;
 int irq     = -1;
 int dma     = -1;
 int dma2    = -1;
+int force   = -1;
 
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "Set i/o base of OPL3-SA2 or SA3 card (usually 0x370)");
@@ -581,9 +704,12 @@ MODULE_PARM_DESC(mss_irq, "Set MSS (audio) IRQ (5, 7, 9, 10, 11, 12)");
 MODULE_PARM(dma, "i");
 MODULE_PARM_DESC(dma, "Set MSS (audio) first DMA channel (0, 1, 3)");
 
-MODULE_PARM(dma2,"i");
+MODULE_PARM(dma2, "i");
 MODULE_PARM_DESC(dma2, "Set MSS (audio) second DMA channel (0, 1, 3)");
 
+MODULE_PARM(force, "i");
+MODULE_PARM_DESC(force, "Force audio controller chipset (2, 3)");
+
 MODULE_DESCRIPTION("Module for OPL3-SA2 and SA3 sound cards (uses AD1848 MSS driver).");
 MODULE_AUTHOR("Scott Murray <scottm@interlog.com>");
 
@@ -605,7 +731,8 @@ int init_module(void)
 
        if(io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1)
        {
-               printk(KERN_ERR "opl3sa2.c: io, mss_io, irq, dma, and dma2 must be set.\n");
+               printk(KERN_ERR "%s: io, mss_io, irq, dma, and dma2 must be set.\n",
+                      __FILE__);
                return -EINVAL;
        }
    
@@ -614,6 +741,12 @@ int init_module(void)
        cfg.irq     = irq;
        cfg.dma     = dma;
        cfg.dma2    = dma2;
+       
+       /* Does the user want to override the chipset type? */
+       if(force != -1)
+               cfg.card_subtype = force;
+       else
+               cfg.card_subtype = CHIPSET_UNKNOWN;
 
         /* The MSS config: */
        mss_cfg.io_base      = mss_io;
index ab87cae403ddf7a61e626f7456a093321fb17791..defd292ebe816cdfe237bca61688f62cfc6ee315 100644 (file)
@@ -73,12 +73,12 @@ extern void     mix_write(unsigned char data, int ioaddr);
 
 unsigned char pas_read(int ioaddr)
 {
-       return inb(ioaddr ^ translate_code);
+       return inb(ioaddr + translate_code);
 }
 
 void pas_write(unsigned char data, int ioaddr)
 {
-       outb((data), ioaddr ^ translate_code);
+       outb((data), ioaddr + translate_code);
 }
 
 /******************* Begin of the Interrupt Handler ********************/
@@ -168,7 +168,7 @@ static int config_pas_hw(struct address_info *hw_config)
        else
        {
                int_ptrs = pas_read(0xF38A);
-               int_ptrs |= irq_bits[pas_irq] & 0xf;
+               int_ptrs = (int_ptrs & 0xf0) | irq_bits[pas_irq];
                pas_write(int_ptrs, 0xF38A);
                if (!irq_bits[pas_irq])
                {
@@ -297,7 +297,7 @@ static int detect_pas_hw(struct address_info *hw_config)
 
        outb((0xBC), 0x9A01);   /* Activate first board */
        outb((hw_config->io_base >> 2), 0x9A01);        /* Set base address */
-       translate_code = 0x388 ^ hw_config->io_base;
+       translate_code = hw_config->io_base - 0x388;
        pas_write(1, 0xBF88);   /* Select one wait states */
 
        board_id = pas_read(0x0B8B);
@@ -347,7 +347,7 @@ void attach_pas_card(struct address_info *hw_config)
                        pas_pcm_init(hw_config);
 #endif
 
-#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB)
+#if !defined(MODULE) && !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB)
 
                        sb_dsp_disable_midi(pas_sb_base);       /* No MIDI capability */
 #endif
@@ -367,8 +367,18 @@ int probe_pas(struct address_info *hw_config)
 
 void unload_pas(struct address_info *hw_config)
 {
+       extern int pas_audiodev;
+       extern int pas2_mididev;
+
        sound_free_dma(hw_config->dma);
        free_irq(hw_config->irq, NULL);
+
+       if(pas_audiodev!=-1)
+               sound_unload_mixerdev(audio_devs[pas_audiodev]->mixer_dev);
+       if(pas2_mididev!=-1)
+               sound_unload_mididev(pas2_mididev);
+       if(pas_audiodev)
+               sound_unload_audiodev(pas_audiodev);
 }
 
 #ifdef MODULE
index 29203071bcbdfd23d51b83283e4caf767a640f0c..d80947012a9c7593d9345eb9c7e26a0b718d8fee 100644 (file)
 static int      midi_busy = 0, input_opened = 0;
 static int      my_dev;
 
+int pas2_mididev;
+
 static unsigned char tmp_queue[256];
 static volatile int qlen;
 static volatile unsigned char qhead, qtail;
 
 static void     (*midi_input_intr) (int dev, unsigned char data);
 
-static int
-pas_midi_open(int dev, int mode,
+static int pas_midi_open(int dev, int mode,
              void            (*input) (int dev, unsigned char data),
              void            (*output) (int dev)
 )
@@ -39,10 +40,8 @@ pas_midi_open(int dev, int mode,
 
 
        if (midi_busy)
-         {
-                 printk("PAS16: Midi busy\n");
-                 return -EBUSY;
-         }
+               return -EBUSY;
+
        /*
         * Reset input and output FIFO pointers
         */
@@ -53,10 +52,10 @@ pas_midi_open(int dev, int mode,
        cli();
 
        if ((err = pas_set_intr(0x10)) < 0)
-         {
-                 restore_flags(flags);
-                 return err;
-         }
+       {
+               restore_flags(flags);
+               return err;
+       }
        /*
         * Enable input available and output FIFO empty interrupts
         */
@@ -66,14 +65,14 @@ pas_midi_open(int dev, int mode,
        midi_input_intr = input;
 
        if (mode == OPEN_READ || mode == OPEN_READWRITE)
-         {
-                 ctrl |= 0x04; /* Enable input */
-                 input_opened = 1;
-         }
+       {
+               ctrl |= 0x04;   /* Enable input */
+               input_opened = 1;
+       }
        if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
-         {
-                 ctrl |= 0x08 | 0x10;  /* Enable output */
-         }
+       {
+               ctrl |= 0x08 | 0x10;    /* Enable output */
+       }
        pas_write(ctrl, 0x178b);
 
        /*
@@ -89,8 +88,7 @@ pas_midi_open(int dev, int mode,
        return 0;
 }
 
-static void
-pas_midi_close(int dev)
+static void pas_midi_close(int dev)
 {
 
        /*
@@ -102,35 +100,32 @@ pas_midi_close(int dev)
        midi_busy = 0;
 }
 
-static int
-dump_to_midi(unsigned char midi_byte)
+static int dump_to_midi(unsigned char midi_byte)
 {
-       int             fifo_space, x;
+       int fifo_space, x;
 
        fifo_space = ((x = pas_read(0x1B89)) >> 4) & 0x0f;
 
-/*
- * The MIDI FIFO space register and it's documentation is nonunderstandable.
- * There seem to be no way to differentiate between buffer full and buffer
- * empty situations. For this reason we don't never write the buffer
- * completely full. In this way we can assume that 0 (or is it 15)
- * means that the buffer is empty.
- */
+       /*
       * The MIDI FIFO space register and it's documentation is nonunderstandable.
       * There seem to be no way to differentiate between buffer full and buffer
       * empty situations. For this reason we don't never write the buffer
       * completely full. In this way we can assume that 0 (or is it 15)
       * means that the buffer is empty.
       */
 
        if (fifo_space < 2 && fifo_space != 0)  /* Full (almost) */
-         {
-                 return 0;     /* Ask upper layers to retry after some time */
-         }
+               return 0;       /* Ask upper layers to retry after some time */
+
        pas_write(midi_byte, 0x178A);
 
        return 1;
 }
 
-static int
-pas_midi_out(int dev, unsigned char midi_byte)
+static int pas_midi_out(int dev, unsigned char midi_byte)
 {
 
-       unsigned long   flags;
+       unsigned long flags;
 
        /*
         * Drain the local queue first
@@ -140,15 +135,15 @@ pas_midi_out(int dev, unsigned char midi_byte)
        cli();
 
        while (qlen && dump_to_midi(tmp_queue[qhead]))
-         {
-                 qlen--;
-                 qhead++;
-         }
+       {
+               qlen--;
+               qhead++;
+       }
 
        restore_flags(flags);
 
        /*
-        * Output the byte if the local queue is empty.
+        *      Output the byte if the local queue is empty.
         */
 
        if (!qlen)
@@ -156,7 +151,7 @@ pas_midi_out(int dev, unsigned char midi_byte)
                        return 1;
 
        /*
-        * Put to the local queue
+        *      Put to the local queue
         */
 
        if (qlen >= 256)
@@ -174,25 +169,21 @@ pas_midi_out(int dev, unsigned char midi_byte)
        return 1;
 }
 
-static int
-pas_midi_start_read(int dev)
+static int pas_midi_start_read(int dev)
 {
        return 0;
 }
 
-static int
-pas_midi_end_read(int dev)
+static int pas_midi_end_read(int dev)
 {
        return 0;
 }
 
-static void
-pas_midi_kick(int dev)
+static void pas_midi_kick(int dev)
 {
 }
 
-static int
-pas_buffer_status(int dev)
+static int pas_buffer_status(int dev)
 {
        return qlen;
 }
@@ -218,23 +209,22 @@ static struct midi_operations pas_midi_operations =
        NULL
 };
 
-void
-pas_midi_init(void)
+void pas_midi_init(void)
 {
-       int             dev = sound_alloc_mididev();
+       int dev = sound_alloc_mididev();
 
        if (dev == -1)
-         {
-                 printk(KERN_WARNING "pas_midi_init: Too many midi devices detected\n");
-                 return;
-         }
+       {
+               printk(KERN_WARNING "pas_midi_init: Too many midi devices detected\n");
+               return;
+       }
        std_midi_synth.midi_dev = my_dev = dev;
        midi_devs[dev] = &pas_midi_operations;
+       pas2_mididev = dev;
        sequencer_init();
 }
 
-void
-pas_midi_interrupt(void)
+void pas_midi_interrupt(void)
 {
        unsigned char   stat;
        int             i, incount;
@@ -243,35 +233,35 @@ pas_midi_interrupt(void)
        stat = pas_read(0x1B88);
 
        if (stat & 0x04)        /* Input data available */
-         {
-                 incount = pas_read(0x1B89) & 0x0f;    /* Input FIFO size */
-                 if (!incount)
-                         incount = 16;
-
-                 for (i = 0; i < incount; i++)
-                         if (input_opened)
-                           {
-                                   midi_input_intr(my_dev, pas_read(0x178A));
-                         } else
-                                 pas_read(0x178A);     /* Flush */
-         }
+       {
+               incount = pas_read(0x1B89) & 0x0f;      /* Input FIFO size */
+               if (!incount)
+                       incount = 16;
+
+               for (i = 0; i < incount; i++)
+                       if (input_opened)
+                       {
+                               midi_input_intr(my_dev, pas_read(0x178A));
+                       } else
+                               pas_read(0x178A);       /* Flush */
+       }
        if (stat & (0x08 | 0x10))
-         {
-                 save_flags(flags);
-                 cli();
-
-                 while (qlen && dump_to_midi(tmp_queue[qhead]))
-                   {
-                           qlen--;
-                           qhead++;
-                   }
-
-                 restore_flags(flags);
-         }
+       {
+               save_flags(flags);
+               cli();
+
+               while (qlen && dump_to_midi(tmp_queue[qhead]))
+               {
+                       qlen--;
+                       qhead++;
+               }
+
+               restore_flags(flags);
+       }
        if (stat & 0x40)
-         {
-                 printk("MIDI output overrun %x,%x\n", pas_read(0x1B89), stat);
-         }
+       {
+               printk(KERN_WARNING "MIDI output overrun %x,%x\n", pas_read(0x1B89), stat);
+       }
        pas_write(stat, 0x1B88);        /* Acknowledge interrupts */
 }
 
index 9f09bd28bbd2bd261544a8db0819676240c23943..ec471f9583735f2351ae5343da3d02b127b7916b 100644 (file)
@@ -49,6 +49,9 @@
 #define MDL_AEDSP      15      /* Audio Excel DSP 16 */
 
 #define SUBMDL_ES188X  0x10    /* Subtype ES188X for specific handling */
+#define SUBMDL_ES1868  0x11    /* Subtype ES1868 for specific handling */
+#define SUBMDL_ES1869  0x12    /* Subtype ES1869 for specific handling */
+#define SUBMDL_ES1878  0x13    /* Subtype ES1878 for specific handling */
 #define SUBMDL_ALS007  42      /* ALS-007 differs from SB16 only in mixer */
                                /* register assignment */
 /*
@@ -144,6 +147,7 @@ void sb_audio_init (sb_devc *devc, char *name);
 void sb_midi_interrupt (sb_devc *devc);
 int ess_write (sb_devc *devc, unsigned char reg, unsigned char data);
 int ess_read (sb_devc *devc, unsigned char reg);
+void ess_mixer_reload (sb_devc * devc, int dev);
 
 extern int acer;
 extern sb_devc *last_sb;
index 889f57b0125286a7b2c5c94d81cd6ab652292466..81ed977c619aad754da814f1afd01b6a90aae09b 100644 (file)
@@ -67,6 +67,7 @@ static int sb_audio_open(int dev, int mode)
        devc->fullduplex = devc->duplex &&
                ((mode & OPEN_READ) && (mode & OPEN_WRITE));
        sb_dsp_reset(devc);
+       ess_mixer_reload (devc, SOUND_MIXER_RECLEV);
 
        /* The ALS007 seems to require that the DSP be removed from the output */
        /* in order for recording to be activated properly.  This is done by   */
@@ -91,8 +92,10 @@ static void sb_audio_close(int dev)
 {
        sb_devc *devc = audio_devs[dev]->devc;
 
-       /* if we did dma juggling put the right dmap in the right place */
-       if(devc->duplex && audio_devs[dev]->dmap_out->dma != devc->dma8)
+       /* fix things if mmap turned off fullduplex */
+       if(devc->duplex
+          && !devc->fullduplex
+          && (devc->opened & OPEN_READ) && (devc->opened & OPEN_WRITE))
        {
                struct dma_buffparms *dmap_temp;
                dmap_temp = audio_devs[dev]->dmap_out;
index 0311f3f1a529347b7aa13a12bb09c6a7083d339b..7902f3ae24fb11bbebb43046ffa5e03c2535f0bc 100644 (file)
@@ -103,6 +103,13 @@ static int sb_dsp_get_byte(sb_devc * devc)
        return 0xffff;
 }
 
+inline void ess_extended (sb_devc * devc)
+{
+       /* Enable extended mode */
+
+       sb_dsp_command(devc, 0xc6);
+}
+
 int ess_write(sb_devc * devc, unsigned char reg, unsigned char data)
 {
        /* Write a byte to an extended mode register of ES1688 */
@@ -225,8 +232,7 @@ int sb_dsp_reset(sb_devc * devc)
                DDB(printk("sb: No response to RESET\n"));
                return 0;       /* Sorry */
        }
-       if (devc->model == MDL_ESS)
-               sb_dsp_command(devc, 0xc6);     /* Enable extended mode */
+       if (devc->model == MDL_ESS) ess_extended (devc);
 
        DEB(printk("sb_dsp_reset() OK\n"));
        return 1;
@@ -491,6 +497,8 @@ static void relocate_ess1688(sb_devc * devc)
  * fiddling with the bits in certain mixer registers. ess_probe is supposed
  * to help.
  */
+static unsigned int ess_identify (sb_devc * devc);
+
 static int ess_probe (sb_devc * devc, int reg, int xorval)
 {
        int  val1, val2, val3;
@@ -554,18 +562,40 @@ static int ess_init(sb_devc * devc, struct address_info *hw_config)
 
        if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
        {
-               char *chip = "ES688";
+               char *chip    = NULL;
+
+               if ((ess_minor & 0x0f) < 8) {
+                       chip = "ES688";
+               };
+               if (chip == NULL) {
+                       int type, dummy;
+
+                       type = ess_identify (devc);
 
-               if ((ess_minor & 0x0f) >= 8) {
+                       switch (type) {
+                       case 0x1868:
+                               chip = "ES1868";
+                               devc->submodel = SUBMDL_ES1868;
+                               break;
+                       case 0x1869:
+                               chip = "ES1869";
+                               devc->submodel = SUBMDL_ES1869;
+                               break;
+                       case 0x1878:
+                               chip = "ES1878";
+                               devc->submodel = SUBMDL_ES1878;
+                               break;
+                       };
+               };
+               if (chip == NULL) {
                        if (  !ess_probe (devc, 0x64, (1 << 3))
                            && ess_probe (devc, 0x70, 0x7f)) {
                                chip = "ES188x";
                                devc->submodel = SUBMDL_ES188X;
-                       } else {
-                               chip = "ES1688";
                        };
-               } else {
-                       chip = "ES688";
+               };
+               if (chip == NULL) {
+                       chip = "ES1688";
                };
 
                sprintf(name,"ESS %s AudioDrive (rev %d)",
@@ -750,7 +780,7 @@ int sb_dsp_detect(struct address_info *hw_config)
                return 0;
        }
        memcpy((char *) detected_devc, (char *) devc, sizeof(sb_devc));
-       MDB(printk("SB %d.%d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base));
+       MDB(printk(KERN_INFO "SB %d.%d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base));
        return 1;
 }
 
@@ -1048,7 +1078,8 @@ void sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value)
 
        save_flags(flags);
        cli();
-       if (devc->model == MDL_ESS && port >= 0xa0 && port <= 0xbf) {
+       if (devc->model == MDL_ESS && port >= 0xa0) {
+               /* ess_extended (devc); */
                ess_write (devc, port, value);
        } else {
                outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
@@ -1077,6 +1108,25 @@ unsigned int sb_getmixer(sb_devc * devc, unsigned int port)
        return val;
 }
 
+static unsigned int ess_identify (sb_devc * devc)
+{
+       unsigned int val;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       outb(((unsigned char) (0x40 & 0xff)), MIXER_ADDR);
+
+       udelay(20);
+       val  = inb(MIXER_DATA) << 8;
+       udelay(20);
+       val |= inb(MIXER_DATA);
+       udelay(20);
+       restore_flags(flags);
+
+       return val;
+}
+
 #ifdef CONFIG_MIDI
 
 /*
index 465f9cbdca7bfc5a73be9b3760168d98b9e516cf..b8415f0656641a13ce3e373d08e890abeae21c1f 100644 (file)
  * for more info.
  *
  *
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
- * Rolf Fokkens    : ES188x recording level support
+ * Thomas Sailer               : ioctl code reworked (vmalloc/vfree removed)
+ * Rolf Fokkens (Dec 20 1998)  : ES188x recording level support on a per
+ *                               input basis
+ *              (Dec 24 1998)  : Recognition of ES188x (?), ES1868, ES1869
+ *                               and ES1878. Could be used for specific
+ *                               handling in the future. All except ES188x
+ *                               and ES688 are handled like ES1688
+ *              (Dec 27 1998)  : RECLEV for all (?) ES1688+ chips, see 
+ *                               ess_mixer_reload for more info. ES188x now
+ *                               has the "Dec 20" support + RECLEV
  */
 
 /*
 #include "sb.h"
 #include "sb_mixer.h"
 
+static mixer_tab sbpro_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME,    0x22, 7, 4, 0x22, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,     0x26, 7, 4, 0x26, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,       0x04, 7, 4, 0x04, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,   0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,      0x2e, 7, 4, 0x2e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,       0x0a, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD,                0x28, 7, 4, 0x28, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,    0x00, 0, 0, 0x00, 0, 0)
+};
+
+static mixer_tab es688_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME,    0x32, 7, 4, 0x32, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,     0x36, 7, 4, 0x36, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,       0x14, 7, 4, 0x14, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,   0x3c, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,      0x3e, 7, 4, 0x3e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,       0x1a, 7, 4, 0x1a, 3, 4),
+MIX_ENT(SOUND_MIXER_CD,                0x38, 7, 4, 0x38, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_IGAIN,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_OGAIN,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE1,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE2,     0x3a, 7, 4, 0x3a, 3, 4),
+MIX_ENT(SOUND_MIXER_LINE3,     0x00, 0, 0, 0x00, 0, 0)
+};
+
+/*
+ * The ES1688 specifics... hopefully correct...
+ * - 6 bit master volume
+ * - RECLEV control
+ * These may apply to ES688 too. I have no idea.
+ */
+static mixer_tab es1688_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME,    0x60, 5, 6, 0x62, 5, 6),
+MIX_ENT(SOUND_MIXER_BASS,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,     0x36, 7, 4, 0x36, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,       0x14, 7, 4, 0x14, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,   0x3c, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,      0x3e, 7, 4, 0x3e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,       0x1a, 7, 4, 0x1a, 3, 4),
+MIX_ENT(SOUND_MIXER_CD,                0x38, 7, 4, 0x38, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,    0xb4, 7, 4, 0xb4, 3, 4),
+MIX_ENT(SOUND_MIXER_IGAIN,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_OGAIN,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE1,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE2,     0x3a, 7, 4, 0x3a, 3, 4),
+MIX_ENT(SOUND_MIXER_LINE3,     0x00, 0, 0, 0x00, 0, 0)
+};
+
+/*
+ * The ES188x specifics.
+ * Note that de master volume unlike ES688 is now controlled by two 6 bit
+ * registers. These seem to work OK on 1868 too, but I have no idea if it's
+ * compatible to 688 or 1688....
+ * Also Note that the recording levels (ES188X_MIXER_REC...) have own 
+ * entries as if they were playback devices. They are used internally in the
+ * driver only!
+ */
+static mixer_tab es188x_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME,    0x60, 5, 6, 0x62, 5, 6),
+MIX_ENT(SOUND_MIXER_BASS,       0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,      0x36, 7, 4, 0x36, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,        0x14, 7, 4, 0x14, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,    0x3c, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,       0x3e, 7, 4, 0x3e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,        0x1a, 7, 4, 0x1a, 3, 4),
+MIX_ENT(SOUND_MIXER_CD,         0x38, 7, 4, 0x38, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,       0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,    0xb4, 7, 4, 0xb4, 3, 4),
+MIX_ENT(SOUND_MIXER_IGAIN,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_OGAIN,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE1,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE2,      0x3a, 7, 4, 0x3a, 3, 4),
+MIX_ENT(SOUND_MIXER_LINE3,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4),
+MIX_ENT(ES188X_MIXER_RECPCM,   0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECSPEAKER,0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECLINE,  0x6e, 7, 4, 0x6e, 3, 4),
+MIX_ENT(ES188X_MIXER_RECMIC,   0x68, 7, 4, 0x68, 3, 4),
+MIX_ENT(ES188X_MIXER_RECCD,    0x6a, 7, 4, 0x6a, 3, 4),
+MIX_ENT(ES188X_MIXER_RECIMIX,  0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECALTPCM,        0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECRECLEV,        0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4),
+MIX_ENT(ES188X_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0)
+};
+
+#ifdef __SGNXPRO__
+#if 0
+static mixer_tab sgnxpro_mix = {       /* not used anywhere */
+MIX_ENT(SOUND_MIXER_VOLUME,    0x22, 7, 4, 0x22, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS,      0x46, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,    0x44, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,     0x26, 7, 4, 0x26, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,       0x04, 7, 4, 0x04, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,   0x42, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,      0x2e, 7, 4, 0x2e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,       0x0a, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD,                0x28, 7, 4, 0x28, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_IGAIN,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_OGAIN,     0x00, 0, 0, 0x00, 0, 0)
+};
+#endif
+#endif
+
+static mixer_tab sb16_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME,    0x30, 7, 5, 0x31, 7, 5),
+MIX_ENT(SOUND_MIXER_BASS,      0x46, 7, 4, 0x47, 7, 4),
+MIX_ENT(SOUND_MIXER_TREBLE,    0x44, 7, 4, 0x45, 7, 4),
+MIX_ENT(SOUND_MIXER_SYNTH,     0x34, 7, 5, 0x35, 7, 5),
+MIX_ENT(SOUND_MIXER_PCM,       0x32, 7, 5, 0x33, 7, 5),
+MIX_ENT(SOUND_MIXER_SPEAKER,   0x3b, 7, 2, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,      0x38, 7, 5, 0x39, 7, 5),
+MIX_ENT(SOUND_MIXER_MIC,       0x3a, 7, 5, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD,                0x36, 7, 5, 0x37, 7, 5),
+MIX_ENT(SOUND_MIXER_IMIX,      0x3c, 0, 1, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,    0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */
+MIX_ENT(SOUND_MIXER_IGAIN,     0x3f, 7, 2, 0x40, 7, 2),
+MIX_ENT(SOUND_MIXER_OGAIN,     0x41, 7, 2, 0x42, 7, 2)
+};
+
+static mixer_tab als007_mix = 
+{
+MIX_ENT(SOUND_MIXER_VOLUME,    0x62, 7, 4, 0x62, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,     0x66, 7, 4, 0x66, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,       0x64, 7, 4, 0x64, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,   0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,      0x6e, 7, 4, 0x6e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,       0x6a, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD,                0x68, 7, 4, 0x68, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,    0x00, 0, 0, 0x00, 0, 0), /* Obsolete. Use IGAIN */
+MIX_ENT(SOUND_MIXER_IGAIN,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_OGAIN,     0x00, 0, 0, 0x00, 0, 0)
+};
+
+
+/* SM_GAMES          Master volume is lower and PCM & FM volumes
+                            higher than with SB Pro. This improves the
+                            sound quality */
+
+static int smg_default_levels[32] =
+{
+  0x2020,                      /* Master Volume */
+  0x4b4b,                      /* Bass */
+  0x4b4b,                      /* Treble */
+  0x6464,                      /* FM */
+  0x6464,                      /* PCM */
+  0x4b4b,                      /* PC Speaker */
+  0x4b4b,                      /* Ext Line */
+  0x0000,                      /* Mic */
+  0x4b4b,                      /* CD */
+  0x4b4b,                      /* Recording monitor */
+  0x4b4b,                      /* SB PCM */
+  0x4b4b,                      /* Recording level */
+  0x4b4b,                      /* Input gain */
+  0x4b4b,                      /* Output gain */
+  0x4040,                      /* Line1 */
+  0x4040,                      /* Line2 */
+  0x1515                       /* Line3 */
+};
+
+static int sb_default_levels[32] =
+{
+  0x5a5a,                      /* Master Volume */
+  0x4b4b,                      /* Bass */
+  0x4b4b,                      /* Treble */
+  0x4b4b,                      /* FM */
+  0x4b4b,                      /* PCM */
+  0x4b4b,                      /* PC Speaker */
+  0x4b4b,                      /* Ext Line */
+  0x1010,                      /* Mic */
+  0x4b4b,                      /* CD */
+  0x0000,                      /* Recording monitor */
+  0x4b4b,                      /* SB PCM */
+  0x4b4b,                      /* Recording level */
+  0x4b4b,                      /* Input gain */
+  0x4b4b,                      /* Output gain */
+  0x4040,                      /* Line1 */
+  0x4040,                      /* Line2 */
+  0x1515                       /* Line3 */
+};
+
+static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
+{
+       0x00,   /* SOUND_MIXER_VOLUME   */
+       0x00,   /* SOUND_MIXER_BASS     */
+       0x00,   /* SOUND_MIXER_TREBLE   */
+       0x40,   /* SOUND_MIXER_SYNTH    */
+       0x00,   /* SOUND_MIXER_PCM      */
+       0x00,   /* SOUND_MIXER_SPEAKER  */
+       0x10,   /* SOUND_MIXER_LINE     */
+       0x01,   /* SOUND_MIXER_MIC      */
+       0x04,   /* SOUND_MIXER_CD       */
+       0x00,   /* SOUND_MIXER_IMIX     */
+       0x00,   /* SOUND_MIXER_ALTPCM   */
+       0x00,   /* SOUND_MIXER_RECLEV   */
+       0x00,   /* SOUND_MIXER_IGAIN    */
+       0x00    /* SOUND_MIXER_OGAIN    */
+};
+
+static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
+{
+       0x00,   /* SOUND_MIXER_VOLUME   */
+       0x00,   /* SOUND_MIXER_BASS     */
+       0x00,   /* SOUND_MIXER_TREBLE   */
+       0x20,   /* SOUND_MIXER_SYNTH    */
+       0x00,   /* SOUND_MIXER_PCM      */
+       0x00,   /* SOUND_MIXER_SPEAKER  */
+       0x08,   /* SOUND_MIXER_LINE     */
+       0x01,   /* SOUND_MIXER_MIC      */
+       0x02,   /* SOUND_MIXER_CD       */
+       0x00,   /* SOUND_MIXER_IMIX     */
+       0x00,   /* SOUND_MIXER_ALTPCM   */
+       0x00,   /* SOUND_MIXER_RECLEV   */
+       0x00,   /* SOUND_MIXER_IGAIN    */
+       0x00    /* SOUND_MIXER_OGAIN    */
+};
+
+static char     smw_mix_regs[] =       /* Left mixer registers */
+{
+  0x0b,                                /* SOUND_MIXER_VOLUME */
+  0x0d,                                /* SOUND_MIXER_BASS */
+  0x0d,                                /* SOUND_MIXER_TREBLE */
+  0x05,                                /* SOUND_MIXER_SYNTH */
+  0x09,                                /* SOUND_MIXER_PCM */
+  0x00,                                /* SOUND_MIXER_SPEAKER */
+  0x03,                                /* SOUND_MIXER_LINE */
+  0x01,                                /* SOUND_MIXER_MIC */
+  0x07,                                /* SOUND_MIXER_CD */
+  0x00,                                /* SOUND_MIXER_IMIX */
+  0x00,                                /* SOUND_MIXER_ALTPCM */
+  0x00,                                /* SOUND_MIXER_RECLEV */
+  0x00,                                /* SOUND_MIXER_IGAIN */
+  0x00,                                /* SOUND_MIXER_OGAIN */
+  0x00,                                /* SOUND_MIXER_LINE1 */
+  0x00,                                /* SOUND_MIXER_LINE2 */
+  0x00                         /* SOUND_MIXER_LINE3 */
+};
+
+#define SBPRO_RECORDING_DEVICES        (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
+
+/* Same as SB Pro, unless I find otherwise */
+#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
+
+#define SBPRO_MIXER_DEVICES            (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+                                        SOUND_MASK_CD | SOUND_MASK_VOLUME)
+
+/* SG NX Pro has treble and bass settings on the mixer. The 'speaker'
+ * channel is the COVOX/DisneySoundSource emulation volume control
+ * on the mixer. It does NOT control speaker volume. Should have own
+ * mask eventually?
+ */
+#define SGNXPRO_MIXER_DEVICES  (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \
+                                SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER )
+
+#define SB16_RECORDING_DEVICES         (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+                                        SOUND_MASK_CD)
+
+#define SB16_OUTFILTER_DEVICES         (SOUND_MASK_LINE | SOUND_MASK_MIC | \
+                                        SOUND_MASK_CD)
+
+#define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
+#define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER)
+
+#define ES1688_RECORDING_DEVICES ES688_RECORDING_DEVICES
+#define ES1688_MIXER_DEVICES (ES688_MIXER_DEVICES|SOUND_MASK_RECLEV)
+
+#define ES188X_RECORDING_DEVICES       (ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 \
+                                        |SOUND_MASK_SYNTH)
+#define ES188X_MIXER_DEVICES (ES1688_MIXER_DEVICES)
+
+#define SB16_MIXER_DEVICES             (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+                                        SOUND_MASK_CD | \
+                                        SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
+                                        SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \
+                                       SOUND_MASK_IMIX)
+
+/* These are the only devices that are working at the moment.  Others could
+ * be added once they are identified and a method is found to control them.
+ */
+#define ALS007_MIXER_DEVICES   (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \
+                                SOUND_MASK_PCM | SOUND_MASK_MIC | \
+                                SOUND_MASK_CD | \
+                                SOUND_MASK_VOLUME)
+
+/*
+ * Mixer registers of ES188x
+ *
+ * These registers specifically take care of recording levels. To make the
+ * mapping from playback devices to recording devices every recording
+ * devices = playback device + ES188X_MIXER_RECDIFF
+ */
+#define ES188X_MIXER_RECBASE   (SOUND_MIXER_LINE3 + 1)
+#define ES188X_MIXER_RECDIFF   (ES188X_MIXER_RECBASE - SOUND_MIXER_SYNTH)
+
+#define ES188X_MIXER_RECSYNTH  (SOUND_MIXER_SYNTH      + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECPCM    (SOUND_MIXER_PCM        + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECSPEAKER        (SOUND_MIXER_SPEAKER    + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE   (SOUND_MIXER_LINE       + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECMIC    (SOUND_MIXER_MIC        + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECCD     (SOUND_MIXER_CD         + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECIMIX   (SOUND_MIXER_IMIX       + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECALTPCM (SOUND_MIXER_ALTPCM     + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECRECLEV (SOUND_MIXER_RECLEV     + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECIGAIN  (SOUND_MIXER_IGAIN      + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECOGAIN  (SOUND_MIXER_OGAIN      + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE1  (SOUND_MIXER_LINE1      + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE2  (SOUND_MIXER_LINE2      + ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE3  (SOUND_MIXER_LINE3      + ES188X_MIXER_RECDIFF)
+
+
 static int      sbmixnum = 1;
 
 static void     sb_mixer_reset(sb_devc * devc);
 
+inline void sb_mixer_bits
+       (sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val)
+{
+       int value;
+
+       value = sb_getmixer(devc, reg);
+       value = (value & ~mask) | (val & mask);
+       sb_setmixer(devc, reg, value);
+}
+
+
 void sb_mixer_set_stereo(sb_devc * devc, int mode)
 {
-       sb_setmixer(devc, OUT_FILTER, ((sb_getmixer(devc, OUT_FILTER) & ~STEREO_DAC)
-                                      | (mode ? STEREO_DAC : MONO_DAC)));
+       sb_mixer_bits(devc, OUT_FILTER, STEREO_DAC, (mode ? STEREO_DAC : MONO_DAC));
 }
 
 static int detect_mixer(sb_devc * devc)
@@ -109,8 +463,6 @@ static int common_mixer_set(sb_devc * devc, int dev, int left, int right)
        val = sb_getmixer(devc, regoffs);
        change_bits(devc, &val, dev, LEFT_CHN, left);
 
-       devc->levels[dev] = left | (left << 8);
-
        if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs)    /*
                                                                 * Change register
                                                                 */
@@ -133,10 +485,25 @@ static int common_mixer_set(sb_devc * devc, int dev, int left, int right)
 
        sb_setmixer(devc, regoffs, val);
 
-       devc->levels[dev] = left | (right << 8);
        return left | (right << 8);
 }
 
+/*
+ * After a sb_dsp_reset extended register 0xb4 (RECLEV) is reset too. After
+ * sb_dsp_reset RECLEV has to be restored. This is where ess_mixer_reload
+ * helps.
+ */
+void ess_mixer_reload (sb_devc * devc, int dev)
+{
+       int left, right, value;
+
+       value = devc->levels[dev];
+       left  = value & 0x000000ff;
+       right = (value & 0x0000ff00) >> 8;
+
+       common_mixer_set(devc, dev, left, right);
+}
+
 /*
  * Changing playback levels at ES188x means having to take care of recording
  * levels of recorded inputs (devc->recmask) too!
@@ -191,6 +558,7 @@ static int sb_mixer_set(sb_devc * devc, int dev, int value)
 {
        int left = value & 0x000000ff;
        int right = (value & 0x0000ff00) >> 8;
+       int retval;
 
        if (left > 100)
                left = 100;
@@ -205,19 +573,24 @@ static int sb_mixer_set(sb_devc * devc, int dev, int value)
                                                         */
                return -EINVAL;
 
-       /* Differentiate dependong on the chipsets */
+       /* Differentiate depending on the chipsets */
        switch (devc->model) {
        case MDL_SMW:
-               return smw_mixer_set(devc, dev, left, right);
+               retval = smw_mixer_set(devc, dev, left, right);
                break;
        case MDL_ESS:
                if (devc->submodel == SUBMDL_ES188X) {
-                       return es188x_mixer_set(devc, dev, left, right);
+                       retval = es188x_mixer_set(devc, dev, left, right);
+               } else {
+                       retval = common_mixer_set(devc, dev, left, right);
                }
                break;
+       default:
+               retval = common_mixer_set(devc, dev, left, right);
        }
+       if (retval >= 0) devc->levels[dev] = retval;
 
-       return common_mixer_set(devc, dev, left, right);
+       return retval;
 }
 
 /*
@@ -496,7 +869,7 @@ static struct mixer_operations als007_mixer_operations =
 static void sb_mixer_reset(sb_devc * devc)
 {
        char name[32];
-       int i, regval;
+       int i;
        extern int sm_games;
 
        sprintf(name, "SB_%d", devc->sbmixnum);
@@ -516,12 +889,8 @@ static void sb_mixer_reset(sb_devc * devc)
         * Then call set_recmask twice to do extra ES188x initializations
         */
        if (devc->model == MDL_ESS && devc->submodel == SUBMDL_ES188X) {
-               regval = sb_getmixer(devc, 0x7a);
-               regval = (regval & 0xe7) | 0x08;
-               sb_setmixer(devc, 0x7a, regval);
-               regval = sb_getmixer(devc, 0x1c);
-               regval = (regval & 0xf8) | 0x07;
-               sb_setmixer(devc, 0x1c, regval);
+               sb_mixer_bits(devc, 0x7a, 0x18, 0x08);
+               sb_mixer_bits(devc, 0x1c, 0x07, 0x07);
 
                set_recmask(devc, ES188X_RECORDING_DEVICES);
                set_recmask(devc, 0);
@@ -568,11 +937,19 @@ int sb_mixer_init(sb_devc * devc)
                                devc->iomap = &es188x_mix;
                                break;
                        default:
-                               devc->supported_devices
-                                       = ES688_MIXER_DEVICES;
-                               devc->supported_rec_devices
-                                       = ES688_RECORDING_DEVICES;
-                               devc->iomap = &es688_mix;
+                               if (devc->submodel < 8) {
+                                       devc->supported_devices
+                                               = ES688_MIXER_DEVICES;
+                                       devc->supported_rec_devices
+                                               = ES688_RECORDING_DEVICES;
+                                       devc->iomap = &es688_mix;
+                               } else {
+                                       devc->supported_devices
+                                               = ES1688_MIXER_DEVICES;
+                                       devc->supported_rec_devices
+                                               = ES1688_RECORDING_DEVICES;
+                                       devc->iomap = &es1688_mix;
+                               }
                        }
 
                        break;
index 00dd031a6eea7f55baa55188601c8c156771d444..70685f53549498d7107acaf8983875acba3c0f10 100644 (file)
  *     Added defines for the Sound Galaxy NX Pro mixer.
  *
  *     Rolf Fokkens    Dec 20 1998
- *     Added (BETA?) support for ES188x chips.
- *     Which means: you can adjust the recording levels.
+ *     Added defines for some ES188x chips.
+ *
+ *     Rolf Fokkens    Dec 27 1998
+ *     Moved static stuff to sb_mixer.c
  *
  */
 #include <linux/config.h>
 #define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
 #define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER)
 
-#define ES188X_RECORDING_DEVICES       (ES688_RECORDING_DEVICES | SOUND_MASK_LINE2 \
+#define ES1688_RECORDING_DEVICES ES688_RECORDING_DEVICES
+#define ES1688_MIXER_DEVICES (ES688_MIXER_DEVICES|SOUND_MASK_RECLEV)
+
+#define ES188X_RECORDING_DEVICES       (ES1688_RECORDING_DEVICES | SOUND_MASK_LINE2 \
                                         |SOUND_MASK_SYNTH)
-#define ES188X_MIXER_DEVICES (ES688_MIXER_DEVICES)
+#define ES188X_MIXER_DEVICES (ES1688_MIXER_DEVICES)
 
 #define SB16_MIXER_DEVICES             (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
                                         SOUND_MASK_CD | \
 /*
  * Mixer registers of ES188x
  *
- * These register specifically take care of recording levels. To make the
+ * These registers specifically take care of recording levels. To make the
  * mapping from playback devices to recording devices every recording
  * devices = playback device + ES188X_MIXER_RECDIFF
  */
 #define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r)        \
        {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}}
 
-#ifdef __SB_MIXER_C__
-static mixer_tab sbpro_mix = {
-MIX_ENT(SOUND_MIXER_VOLUME,    0x22, 7, 4, 0x22, 3, 4),
-MIX_ENT(SOUND_MIXER_BASS,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_TREBLE,    0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_SYNTH,     0x26, 7, 4, 0x26, 3, 4),
-MIX_ENT(SOUND_MIXER_PCM,       0x04, 7, 4, 0x04, 3, 4),
-MIX_ENT(SOUND_MIXER_SPEAKER,   0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE,      0x2e, 7, 4, 0x2e, 3, 4),
-MIX_ENT(SOUND_MIXER_MIC,       0x0a, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_CD,                0x28, 7, 4, 0x28, 3, 4),
-MIX_ENT(SOUND_MIXER_IMIX,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV,    0x00, 0, 0, 0x00, 0, 0)
-};
-static mixer_tab es688_mix = {
-MIX_ENT(SOUND_MIXER_VOLUME,    0x32, 7, 4, 0x32, 3, 4),
-MIX_ENT(SOUND_MIXER_BASS,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_TREBLE,    0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_SYNTH,     0x36, 7, 4, 0x36, 3, 4),
-MIX_ENT(SOUND_MIXER_PCM,       0x14, 7, 4, 0x14, 3, 4),
-MIX_ENT(SOUND_MIXER_SPEAKER,   0x3c, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE,      0x3e, 7, 4, 0x3e, 3, 4),
-MIX_ENT(SOUND_MIXER_MIC,       0x1a, 7, 4, 0x1a, 3, 4),
-MIX_ENT(SOUND_MIXER_CD,                0x38, 7, 4, 0x38, 3, 4),
-MIX_ENT(SOUND_MIXER_IMIX,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV,    0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_IGAIN,     0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_OGAIN,     0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE1,     0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE2,     0x3a, 7, 4, 0x3a, 3, 4),
-MIX_ENT(SOUND_MIXER_LINE3,     0x00, 0, 0, 0x00, 0, 0)
-};
-
-/*
- * The ES188x specifics.
- * Note that de master volume unlike ES688 is now controlled by two 6 bit
- * registers. These seem to work OK on 1868 too, but I have no idea if it's
- * compatible to 688 or 1688....
- * Also Note that the recording levels (ES188X_MIXER_REC...) have own 
- * entries as if they were playback devices. They are used internally in the
- * driver only!
- */
-static mixer_tab es188x_mix = {
-MIX_ENT(SOUND_MIXER_VOLUME,    0x60, 5, 6, 0x62, 5, 6),
-MIX_ENT(SOUND_MIXER_BASS,       0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_TREBLE,     0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_SYNTH,      0x36, 7, 4, 0x36, 3, 4),
-MIX_ENT(SOUND_MIXER_PCM,        0x14, 7, 4, 0x14, 3, 4),
-MIX_ENT(SOUND_MIXER_SPEAKER,    0x3c, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE,       0x3e, 7, 4, 0x3e, 3, 4),
-MIX_ENT(SOUND_MIXER_MIC,        0x1a, 7, 4, 0x1a, 3, 4),
-MIX_ENT(SOUND_MIXER_CD,         0x38, 7, 4, 0x38, 3, 4),
-MIX_ENT(SOUND_MIXER_IMIX,       0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_ALTPCM,     0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV,     0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_IGAIN,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_OGAIN,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE1,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE2,      0x3a, 7, 4, 0x3a, 3, 4),
-MIX_ENT(SOUND_MIXER_LINE3,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES188X_MIXER_RECSYNTH, 0x6b, 7, 4, 0x6b, 3, 4),
-MIX_ENT(ES188X_MIXER_RECPCM,   0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES188X_MIXER_RECSPEAKER,0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES188X_MIXER_RECLINE,  0x6e, 7, 4, 0x6e, 3, 4),
-MIX_ENT(ES188X_MIXER_RECMIC,   0x68, 7, 4, 0x68, 3, 4),
-MIX_ENT(ES188X_MIXER_RECCD,    0x6a, 7, 4, 0x6a, 3, 4),
-
-MIX_ENT(ES188X_MIXER_RECIMIX,  0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES188X_MIXER_RECALTPCM,        0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES188X_MIXER_RECRECLEV,        0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES188X_MIXER_RECIGAIN, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES188X_MIXER_RECOGAIN, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES188X_MIXER_RECLINE1, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(ES188X_MIXER_RECLINE2, 0x6c, 7, 4, 0x6c, 3, 4),
-MIX_ENT(ES188X_MIXER_RECLINE3, 0x00, 0, 0, 0x00, 0, 0)
-};
-
-#ifdef __SGNXPRO__
-#if 0
-static mixer_tab sgnxpro_mix = {       /* not used anywhere */
-MIX_ENT(SOUND_MIXER_VOLUME,    0x22, 7, 4, 0x22, 3, 4),
-MIX_ENT(SOUND_MIXER_BASS,      0x46, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_TREBLE,    0x44, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_SYNTH,     0x26, 7, 4, 0x26, 3, 4),
-MIX_ENT(SOUND_MIXER_PCM,       0x04, 7, 4, 0x04, 3, 4),
-MIX_ENT(SOUND_MIXER_SPEAKER,   0x42, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE,      0x2e, 7, 4, 0x2e, 3, 4),
-MIX_ENT(SOUND_MIXER_MIC,       0x0a, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_CD,                0x28, 7, 4, 0x28, 3, 4),
-MIX_ENT(SOUND_MIXER_IMIX,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV,    0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_IGAIN,     0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_OGAIN,     0x00, 0, 0, 0x00, 0, 0)
-};
-#endif
-#endif
-
-static mixer_tab sb16_mix = {
-MIX_ENT(SOUND_MIXER_VOLUME,    0x30, 7, 5, 0x31, 7, 5),
-MIX_ENT(SOUND_MIXER_BASS,      0x46, 7, 4, 0x47, 7, 4),
-MIX_ENT(SOUND_MIXER_TREBLE,    0x44, 7, 4, 0x45, 7, 4),
-MIX_ENT(SOUND_MIXER_SYNTH,     0x34, 7, 5, 0x35, 7, 5),
-MIX_ENT(SOUND_MIXER_PCM,       0x32, 7, 5, 0x33, 7, 5),
-MIX_ENT(SOUND_MIXER_SPEAKER,   0x3b, 7, 2, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE,      0x38, 7, 5, 0x39, 7, 5),
-MIX_ENT(SOUND_MIXER_MIC,       0x3a, 7, 5, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_CD,                0x36, 7, 5, 0x37, 7, 5),
-MIX_ENT(SOUND_MIXER_IMIX,      0x3c, 0, 1, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV,    0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */
-MIX_ENT(SOUND_MIXER_IGAIN,     0x3f, 7, 2, 0x40, 7, 2),
-MIX_ENT(SOUND_MIXER_OGAIN,     0x41, 7, 2, 0x42, 7, 2)
-};
-
-static mixer_tab als007_mix = 
-{
-MIX_ENT(SOUND_MIXER_VOLUME,    0x62, 7, 4, 0x62, 3, 4),
-MIX_ENT(SOUND_MIXER_BASS,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_TREBLE,    0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_SYNTH,     0x66, 7, 4, 0x66, 3, 4),
-MIX_ENT(SOUND_MIXER_PCM,       0x64, 7, 4, 0x64, 3, 4),
-MIX_ENT(SOUND_MIXER_SPEAKER,   0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE,      0x6e, 7, 4, 0x6e, 3, 4),
-MIX_ENT(SOUND_MIXER_MIC,       0x6a, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_CD,                0x68, 7, 4, 0x68, 3, 4),
-MIX_ENT(SOUND_MIXER_IMIX,      0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV,    0x00, 0, 0, 0x00, 0, 0), /* Obsolete. Use IGAIN */
-MIX_ENT(SOUND_MIXER_IGAIN,     0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_OGAIN,     0x00, 0, 0, 0x00, 0, 0)
-};
-
-
-/* SM_GAMES          Master volume is lower and PCM & FM volumes
-                            higher than with SB Pro. This improves the
-                            sound quality */
-
-static int smg_default_levels[32] =
-{
-  0x2020,                      /* Master Volume */
-  0x4b4b,                      /* Bass */
-  0x4b4b,                      /* Treble */
-  0x6464,                      /* FM */
-  0x6464,                      /* PCM */
-  0x4b4b,                      /* PC Speaker */
-  0x4b4b,                      /* Ext Line */
-  0x0000,                      /* Mic */
-  0x4b4b,                      /* CD */
-  0x4b4b,                      /* Recording monitor */
-  0x4b4b,                      /* SB PCM */
-  0x4b4b,                      /* Recording level */
-  0x4b4b,                      /* Input gain */
-  0x4b4b,                      /* Output gain */
-  0x4040,                      /* Line1 */
-  0x4040,                      /* Line2 */
-  0x1515                       /* Line3 */
-};
-
-static int sb_default_levels[32] =
-{
-  0x5a5a,                      /* Master Volume */
-  0x4b4b,                      /* Bass */
-  0x4b4b,                      /* Treble */
-  0x4b4b,                      /* FM */
-  0x4b4b,                      /* PCM */
-  0x4b4b,                      /* PC Speaker */
-  0x4b4b,                      /* Ext Line */
-  0x1010,                      /* Mic */
-  0x4b4b,                      /* CD */
-  0x0000,                      /* Recording monitor */
-  0x4b4b,                      /* SB PCM */
-  0x4b4b,                      /* Recording level */
-  0x4b4b,                      /* Input gain */
-  0x4b4b,                      /* Output gain */
-  0x4040,                      /* Line1 */
-  0x4040,                      /* Line2 */
-  0x1515                       /* Line3 */
-};
-
-static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
-{
-       0x00,   /* SOUND_MIXER_VOLUME   */
-       0x00,   /* SOUND_MIXER_BASS     */
-       0x00,   /* SOUND_MIXER_TREBLE   */
-       0x40,   /* SOUND_MIXER_SYNTH    */
-       0x00,   /* SOUND_MIXER_PCM      */
-       0x00,   /* SOUND_MIXER_SPEAKER  */
-       0x10,   /* SOUND_MIXER_LINE     */
-       0x01,   /* SOUND_MIXER_MIC      */
-       0x04,   /* SOUND_MIXER_CD       */
-       0x00,   /* SOUND_MIXER_IMIX     */
-       0x00,   /* SOUND_MIXER_ALTPCM   */
-       0x00,   /* SOUND_MIXER_RECLEV   */
-       0x00,   /* SOUND_MIXER_IGAIN    */
-       0x00    /* SOUND_MIXER_OGAIN    */
-};
-
-static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
-{
-       0x00,   /* SOUND_MIXER_VOLUME   */
-       0x00,   /* SOUND_MIXER_BASS     */
-       0x00,   /* SOUND_MIXER_TREBLE   */
-       0x20,   /* SOUND_MIXER_SYNTH    */
-       0x00,   /* SOUND_MIXER_PCM      */
-       0x00,   /* SOUND_MIXER_SPEAKER  */
-       0x08,   /* SOUND_MIXER_LINE     */
-       0x01,   /* SOUND_MIXER_MIC      */
-       0x02,   /* SOUND_MIXER_CD       */
-       0x00,   /* SOUND_MIXER_IMIX     */
-       0x00,   /* SOUND_MIXER_ALTPCM   */
-       0x00,   /* SOUND_MIXER_RECLEV   */
-       0x00,   /* SOUND_MIXER_IGAIN    */
-       0x00    /* SOUND_MIXER_OGAIN    */
-};
-
-static char     smw_mix_regs[] =       /* Left mixer registers */
-{
-  0x0b,                                /* SOUND_MIXER_VOLUME */
-  0x0d,                                /* SOUND_MIXER_BASS */
-  0x0d,                                /* SOUND_MIXER_TREBLE */
-  0x05,                                /* SOUND_MIXER_SYNTH */
-  0x09,                                /* SOUND_MIXER_PCM */
-  0x00,                                /* SOUND_MIXER_SPEAKER */
-  0x03,                                /* SOUND_MIXER_LINE */
-  0x01,                                /* SOUND_MIXER_MIC */
-  0x07,                                /* SOUND_MIXER_CD */
-  0x00,                                /* SOUND_MIXER_IMIX */
-  0x00,                                /* SOUND_MIXER_ALTPCM */
-  0x00,                                /* SOUND_MIXER_RECLEV */
-  0x00,                                /* SOUND_MIXER_IGAIN */
-  0x00,                                /* SOUND_MIXER_OGAIN */
-  0x00,                                /* SOUND_MIXER_LINE1 */
-  0x00,                                /* SOUND_MIXER_LINE2 */
-  0x00                         /* SOUND_MIXER_LINE3 */
-};
-
 /*
  *     Recording sources (SB Pro)
  */
@@ -409,4 +175,3 @@ static char     smw_mix_regs[] =    /* Left mixer registers */
 #define ALS007_SYNTH   7
 
 #endif
-#endif
index 84b0bf978a67e45b656d19d9424627d8ee33b9db..75d93a4626b41011f8dcff0c1625e900ccf9f240 100644 (file)
@@ -2389,11 +2389,11 @@ __initfunc(int init_sonicvibes(void))
                printk(KERN_INFO "sv: found adapter at io %#06x irq %u dmaa %#06x dmac %#06x revision %u\n",
                       s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION));
                /* register devices */
-               if ((s->dev_audio = register_sound_dsp(&sv_audio_fops)) < 0)
+               if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0)
                        goto err_dev1;
-               if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops)) < 0)
+               if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops, -1)) < 0)
                        goto err_dev2;
-               if ((s->dev_midi = register_sound_midi(&sv_midi_fops)) < 0)
+               if ((s->dev_midi = register_sound_midi(&sv_midi_fops, -1)) < 0)
                        goto err_dev3;
                if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0)
                        goto err_dev4;
index d05369d7c0ddc0c128b9c232e650f7115a85fb9e..e162d8edced39469c5a1f9aa33c249fb946d62ca 100644 (file)
@@ -300,5 +300,5 @@ void unload_wavefront (struct address_info *hw_config);
 void attach_wf_mpu(struct address_info * hw_config);
 int probe_wf_mpu(struct address_info *hw_config);
 void unload_wf_mpu(struct address_info *hw_config);
-int virtual_midi_enable (int mididev, struct address_info *);
-void virtual_midi_disable (int mididev);
+int virtual_midi_enable (void);
+int virtual_midi_disable (void);
index 3600284212bbdf37397c5f29f0ea783f10cdd2c9..c4531e275ed07cfdc7ead2f181ea48cd9a0917f7 100644 (file)
@@ -57,24 +57,32 @@ struct sound_unit
  *     join into it. Called with the lock asserted
  */
 
-static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, struct file_operations *fops, int low, int top)
+static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, struct file_operations *fops, int index, int low, int top)
 {
        int n=low;
 
-       while(n<top)
-       {
-               /* Found a hole ? */
-               if(*list==NULL || (*list)->unit_minor>n)
-                       break;
-               list=&((*list)->next);
-               n+=16;
-       }
-       
-       if(n==top)
-       {
-               return -1;
-       }
-       
+       if (index < 0) {        /* first free */
+               while(n<top)
+               {
+                       /* Found a hole ? */
+                       if(*list==NULL || (*list)->unit_minor>n)
+                               break;
+                       list=&((*list)->next);
+                       n+=16;
+               }
+
+               if(n>=top)
+                       return -ENOMEM;
+       } else {
+               n = low+(index*16);
+               while (*list) {
+                       if ((*list)->unit_minor==n)
+                               return -EBUSY;
+                       if ((*list)->unit_minor>n)
+                               break;
+                       list=&((*list)->next);
+               }
+       }       
                
        /*
         *      Fill it in
@@ -127,7 +135,7 @@ static spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED;
  *     list. Acquires locks as needed
  */
  
-static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int low, int top)
+static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top)
 {
        int r;
        struct sound_unit *s=(struct sound_unit *)kmalloc(sizeof(struct sound_unit), GFP_KERNEL);
@@ -135,7 +143,7 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f
                return -1;
                
        spin_lock(&sound_loader_lock);
-       r=__sound_insert_unit(s,list,fops,low,top);
+       r=__sound_insert_unit(s,list,fops,index,low,top);
        spin_unlock(&sound_loader_lock);
        
        if(r==-1)
@@ -181,21 +189,21 @@ static struct sound_unit *chains[16];
 
 int register_sound_special(struct file_operations *fops, int unit)
 {
-       return sound_insert_unit(&chains[unit&15], fops, unit, unit+1);
+       return sound_insert_unit(&chains[unit&15], fops, -1, unit, unit+1);
 }
  
 EXPORT_SYMBOL(register_sound_special);
 
-int register_sound_mixer(struct file_operations *fops)
+int register_sound_mixer(struct file_operations *fops, int dev)
 {
-       return sound_insert_unit(&chains[0], fops, 0, 128);
+       return sound_insert_unit(&chains[0], fops, dev, 0, 128);
 }
 
 EXPORT_SYMBOL(register_sound_mixer);
 
-int register_sound_midi(struct file_operations *fops)
+int register_sound_midi(struct file_operations *fops, int dev)
 {
-       return sound_insert_unit(&chains[2], fops, 2, 130);
+       return sound_insert_unit(&chains[2], fops, dev, 2, 130);
 }
 
 EXPORT_SYMBOL(register_sound_midi);
@@ -205,16 +213,16 @@ EXPORT_SYMBOL(register_sound_midi);
  *     in open - see below.
  */
  
-int register_sound_dsp(struct file_operations *fops)
+int register_sound_dsp(struct file_operations *fops, int dev)
 {
-       return sound_insert_unit(&chains[3], fops, 3, 131);
+       return sound_insert_unit(&chains[3], fops, dev, 3, 131);
 }
 
 EXPORT_SYMBOL(register_sound_dsp);
 
-int register_sound_synth(struct file_operations *fops)
+int register_sound_synth(struct file_operations *fops, int dev)
 {
-       return sound_insert_unit(&chains[9], fops, 9, 137);
+       return sound_insert_unit(&chains[9], fops, dev, 9, 137);
 }
 
 EXPORT_SYMBOL(register_sound_synth);
@@ -279,6 +287,20 @@ static struct file_operations soundcore_fops=
        NULL
 };
 
+static struct sound_unit *__look_for_unit(int chain, int unit)
+{
+       struct sound_unit *s;
+       
+       s=chains[chain];
+       while(s && s->unit_minor <= unit)
+       {
+               if(s->unit_minor==unit)
+                       return s;
+               s=s->next;
+       }
+       return NULL;
+}
+
 int soundcore_open(struct inode *inode, struct file *file)
 {
        int chain;
@@ -294,28 +316,48 @@ int soundcore_open(struct inode *inode, struct file *file)
        }
        
        spin_lock(&sound_loader_lock);
+       s = __look_for_unit(chain, unit);
+#ifdef CONFIG_KMOD
+       if (s == NULL) {
+               char mod[32];
        
-       s=chains[chain];
-       
-       while(s && s->unit_minor <= unit)
-       {
-               if(s->unit_minor==unit)
-               {
-                       file->f_op=s->unit_fops;
-                       spin_unlock(&sound_loader_lock);
-                       if(file->f_op->open)
-                               return file->f_op->open(inode,file);
-                       else
-                               return 0;
-                       break;
-               }
-               s=s->next;
+               spin_unlock(&sound_loader_lock);
+               /*
+                *  Please, don't change this order or code.
+                *  For ALSA slot means soundcard and OSS emulation code
+                *  comes as add-on modules which aren't depend on
+                *  ALSA toplevel modules for soundcards, thus we need
+                *  load them at first.   [Jaroslav Kysela <perex@jcu.cz>]
+                */
+               sprintf(mod, "sound-slot-%i", unit>>4);
+               request_module(mod);
+               sprintf(mod, "sound-service-%i-%i", unit>>4, chain);
+               request_module(mod);
+               spin_lock(&sound_loader_lock);
+               s = __look_for_unit(chain, unit);
+       }
+#endif
+       if (s) {
+               file->f_op=s->unit_fops;
+               spin_unlock(&sound_loader_lock);
+               if(file->f_op->open)
+                       return file->f_op->open(inode,file);
+               else
+                       return 0;
        }
        spin_unlock(&sound_loader_lock);
        return -ENODEV;
 }
 
 #ifdef MODULE
+
+MODULE_DESCRIPTION("Core sound module");
+MODULE_AUTHOR("Alan Cox");
+
+extern int mod_firmware_load(const char *, char **);
+EXPORT_SYMBOL(mod_firmware_load);
+
+
 void cleanup_module(void)
 {
        /* We have nothing to really do here - we know the lists must be
index f4777addfdabfe264767de6fe7203c0cac932d29..c446e98e01c4fe4a64b0eb107e74fa0ac4be1adb 100644 (file)
@@ -58,4 +58,3 @@ int mod_firmware_load(const char *fn, char **fp)
        return r;
 }
 
-EXPORT_SYMBOL(mod_firmware_load);
index 08f092e9081a3a8b0541c28c99fc7dd652c875fa..b0568d82ab523cb624ccc26fbd6b67a4bdfd07a4 100644 (file)
@@ -43,6 +43,7 @@ EXPORT_SYMBOL(sound_unload_synthdev);
 
 EXPORT_SYMBOL(load_mixer_volumes);
 
+
 EXPORT_SYMBOL(conf_printf);
 EXPORT_SYMBOL(conf_printf2);
 
@@ -54,5 +55,5 @@ EXPORT_SYMBOL(softoss_dev);
 EXPORT_SYMBOL(sound_locker);
 EXPORT_SYMBOL(sound_notifier_chain_register);
 
-MODULE_DESCRIPTION("Sound subsystem");
+MODULE_DESCRIPTION("OSS Sound subsystem");
 MODULE_AUTHOR("Hannu Savolainen, et al.");
index b2e33ab1a2000762cf0117b949778ddcbc1548bf..d0558c753b18ff3dfa69943071f6681ff16c5c14 100644 (file)
  * now, you just get the YSS225 in the same state as Turtle Beach's
  * "SETUPSND.EXE" utility leaves it.
  *
- * The boards' CODEC (a Crystal CS4232) is supported by cs4232.[co],
+ * The boards' DAC/ADC (a Crystal CS4232) is supported by cs4232.[co],
  * This chip also controls the configuration of the card: the wavefront
  * synth is logical unit 4.
  *
+ *
+ * Supported devices:
+ *
+ *   /dev/dsp                      - using cs4232+ad1848 modules, OSS compatible
+ *   /dev/midiNN and /dev/midiNN+1 - using wf_midi code, OSS compatible
+ *   /dev/synth00                  - raw synth interface
+ * 
  **********************************************************************
  *
  * Copyright (C) by Paul Barton-Davis 1998
@@ -36,9 +43,9 @@
  * Although the relevant code here is all new, the handling of
  * sample/alias/multi- samples is entirely based on a driver by Matt
  * Martin and Rutger Nijlunsing which demonstrated how to get things
- * to most aspects of this to work correctly. The GUS patch loading
- * code has been almost unaltered by me, except to fit formatting and
- * function names in the rest of the file. Many thanks to them.
+ * to work correctly. The GUS patch loading code has been almost
+ * unaltered by me, except to fit formatting and function names in the
+ * rest of the file. Many thanks to them.
  *
  * Appreciation and thanks to Hannu Savolainen for his early work on the Maui
  * driver, and answering a few questions while this one was developed.
  * aspects of configuring a WaveFront soundcard, particularly the
  * effects processor.
  *
- * $Id: wavfront.c,v 0.5 1998/07/22 16:16:41 pbd Exp $
+ * $Id: wavfront.c,v 0.7 1998/09/09 15:47:36 pbd Exp $
  *
  * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
+ * for more info.  */
 
-#include <linux/config.h>
 #include <linux/module.h>
-#include <asm/init.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fcntl.h>
+#include <linux/ioport.h>    
+
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/init.h>
 
 #include "sound_config.h"
 #include "soundmodule.h"
 #define MIDI_SYNTH_CAPS        SYNTH_CAP_INPUT
 #include "midi_synth.h"
 
-/* This thing is meant to work as a module */
+/* Compile-time control of the extent to which OSS is supported.
+
+   I consider /dev/sequencer to be an anachronism, but given its
+   widespread usage by various Linux MIDI software, it seems worth
+   offering support to it if its not too painful. Instead of using
+   /dev/sequencer, I recommend:
+
+     for synth programming and patch loading: /dev/synthNN
+     for kernel-synchronized MIDI sequencing: the ALSA sequencer
+     for direct MIDI control: /dev/midiNN
+
+   I have never tried static compilation into the kernel. The #if's
+   for this are really just notes to myself about what the code is
+   for.
+*/
+
+#define OSS_SUPPORT_SEQ            0x1  /* use of /dev/sequencer */
+#define OSS_SUPPORT_STATIC_INSTALL 0x2  /* static compilation into kernel */
+
+#define OSS_SUPPORT_LEVEL          0x1  /* just /dev/sequencer for now */
+
+#if    OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+static int (*midi_load_patch) (int devno, int format, const char *addr,
+                              int offs, int count, int pmgr_flag) = NULL;
+#endif OSS_SUPPORT_SEQ
+
+/* This is meant to work as a module */
 
 #if defined(CONFIG_SOUND_WAVEFRONT_MODULE) && defined(MODULE)
 
 
 #define WF_DEBUG 1
 
+#ifdef WF_DEBUG
+
+/* Thank goodness for gcc's preprocessor ... */
+
+#define DPRINT(cond, format, args...) \
+       if ((dev.debug & (cond)) == (cond)) { \
+            printk (KERN_DEBUG LOGNAME format, ## args); \
+       }
+#else
+#define DPRINT(cond, format, args...)
+#endif
+
+#define LOGNAME "WaveFront: "
+
 /* bitmasks for WaveFront status port value */
 
-#define STAT_INTR_WRITE                0x40
-#define STAT_CAN_WRITE         0x20
-#define STAT_WINTR_ENABLED     0x10
-#define STAT_INTR_READ         0x04
-#define STAT_CAN_READ          0x02
 #define STAT_RINTR_ENABLED     0x01
+#define STAT_CAN_READ          0x02
+#define STAT_INTR_READ         0x04
+#define STAT_WINTR_ENABLED     0x10
+#define STAT_CAN_WRITE         0x20
+#define STAT_INTR_WRITE                0x40
 
 /*** Module-accessible parameters ***************************************/
 
@@ -117,9 +171,6 @@ char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed
                                             version of the WaveFront OS
                                          */
 
-int sleep_interval = 100;     /* HZ/sleep_interval seconds per sleep */
-int sleep_tries = 50;       /* number of times we'll try to sleep */
-
 int wait_usecs = 150; /* This magic number seems to give pretty optimal
                         throughput based on my limited experimentation.
                         If you want to play around with it and find a better
@@ -133,24 +184,40 @@ int wait_usecs = 150; /* This magic number seems to give pretty optimal
                         status waits, only about 250 result in a sleep.
                      */
 
+int sleep_interval = 100;     /* HZ/sleep_interval seconds per sleep */
+int sleep_tries = 50;       /* number of times we'll try to sleep */
+
+int reset_time = 2;        /* hundreths of a second we wait after a HW reset for
+                             the expected interrupt.
+                          */
+
+int ramcheck_time = 20;    /* time in seconds to wait while ROM code
+                             checks on-board RAM.
+                          */
+
+int osrun_time = 10;       /* time in seconds we wait for the OS to
+                             start running.
+                          */
+
 MODULE_PARM(wf_raw,"i");
 MODULE_PARM(fx_raw,"i");
 MODULE_PARM(debug_default,"i");
+MODULE_PARM(wait_usecs,"i");
 MODULE_PARM(sleep_interval,"i");
 MODULE_PARM(sleep_tries,"i");
-MODULE_PARM(wait_usecs,"i");
 MODULE_PARM(ospath,"s");
+MODULE_PARM(reset_time,"i");
+MODULE_PARM(ramcheck_time,"i");
+MODULE_PARM(osrun_time,"i");
 
 /***************************************************************************/
 
-static struct synth_info wavefront_info =
-{"Turtle Beach WaveFront", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_WAVEFRONT,
- 0, 32, 0, 0, SYNTH_CAP_INPUT};
-
-static int (*midi_load_patch) (int dev, int format, const char *addr,
-                              int offs, int count, int pmgr_flag) = NULL;
+/* Note: because this module doesn't export any symbols, this really isn't
+   a global variable, even if it looks like one. I was quite confused by
+   this when I started writing this as a (newer) module -- pbd.
+*/
 
-typedef struct wf_config {
+struct wf_config {
        int devno;            /* device number from kernel */
        int irq;              /* "you were one, one of the few ..." */
        int base;             /* low i/o port address */
@@ -181,15 +248,23 @@ typedef struct wf_config {
 #define fx_mod_data     base + 0xf 
 
        volatile int irq_ok;               /* set by interrupt handler */
-       int opened;                        /* flag, holds open(1) mode */
+        volatile int irq_cnt;              /* ditto */
+       int opened;                        /* flag, holds open(2) mode */
        char debug;                        /* debugging flags */
        int freemem;                       /* installed RAM, in bytes */ 
-       int synthdev;                      /* OSS minor devnum for synth */
-       int mididev;                       /* OSS minor devno for internal MIDI */
-       int ext_mididev;                   /* OSS minor devno for external MIDI */ 
+
+       int synth_dev;                     /* devno for "raw" synth */
+       int mididev;                       /* devno for internal MIDI */
+       int ext_mididev;                   /* devno for external MIDI */ 
+        int fx_mididev;                    /* devno for FX MIDI interface */
+#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+       int oss_dev;                      /* devno for OSS sequencer synth */
+#endif OSS_SUPPORT_SEQ
+
        char fw_version[2];                /* major = [0], minor = [1] */
        char hw_version[2];                /* major = [0], minor = [1] */
        char israw;                        /* needs Motorola microcode */
+       char has_fx;                       /* has FX processor (Tropez+) */
        char prog_status[WF_MAX_PROGRAM];  /* WF_SLOT_* */
        char patch_status[WF_MAX_PATCH];   /* WF_SLOT_* */
        char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */
@@ -197,27 +272,22 @@ typedef struct wf_config {
        char interrupts_on;                /* h/w MPU interrupts enabled ? */
        char rom_samples_rdonly;           /* can we write on ROM samples */
        struct wait_queue *interrupt_sleeper; 
-#ifdef  WF_STATS
-       unsigned long status_found_during_loop;
-       unsigned long status_found_during_sleep[4];
-#endif  WF_STATS
-
-} wf_config;
-
-/* Note: because this module doesn't export any symbols, this really isn't
-   a global variable, even if it looks like one. I was quite confused by
-   this when I started writing this as a (newer) module -- pbd.
-*/
+} dev;
 
-static wf_config wavefront_configuration;
+static int  detect_wffx(void);
+static int  wffx_ioctl (wavefront_fx_info *);
+static int  wffx_init (void);
 
-#define wavefront_status(hw) (inb (hw->status_port))
+static int wavefront_delete_sample (int sampnum);
+static int wavefront_find_free_sample (void);
 
-/* forward references */
+/* From wf_midi.c */
 
-static int wffx_ioctl (struct wf_config *, wavefront_fx_info *);
-static int wffx_init (struct wf_config *hw);
-static int wavefront_delete_sample (struct wf_config *hw, int sampnum);
+extern int  virtual_midi_enable  (void);
+extern int  virtual_midi_disable (void);
+extern int  detect_wf_mpu (int, int);
+extern int  install_wf_mpu (void);
+extern int  uninstall_wf_mpu (void);
 
 typedef struct {
        int cmd;
@@ -339,92 +409,92 @@ wavefront_get_command (int cmd)
        return (wavefront_command *) 0;
 }
 
+static inline int
+wavefront_status (void) 
+
+{
+       return inb (dev.status_port);
+}
+
 static int
-wavefront_sleep (wf_config *hw, int limit)
+wavefront_sleep (int limit)
 
 {
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(limit);
+
        return signal_pending(current);
 }
-    
+
 static int
-wavefront_wait (wf_config *hw, int mask)
+wavefront_wait (int mask)
 
 {
        int             i;
        static int      short_loop_cnt = 0;
 
+       /* Compute the loop count that lets us sleep for about the
+          right amount of time, cache issues, bus speeds and all
+          other issues being unequal but largely irrelevant.
+       */
+
        if (short_loop_cnt == 0) {
-           short_loop_cnt = (int) (((double) wait_usecs / 1000000.0) *
-               (double) current_cpu_data.loops_per_sec);
+               short_loop_cnt = wait_usecs *
+                       (current_cpu_data.loops_per_sec / 1000000);
        }
 
+       /* Spin for a short period of time, because >99% of all
+          requests to the WaveFront can be serviced inline like this.
+       */
+
        for (i = 0; i < short_loop_cnt; i++) {
-               if (wavefront_status(hw) & mask) {
-#ifdef WF_STATS
-                       hw->status_found_during_loop++;
-#endif WF_STATS
+               if (wavefront_status() & mask) {
                        return 1;
                }
        }
 
        for (i = 0; i < sleep_tries; i++) {
 
-               if (wavefront_status(hw) & mask) {
-#ifdef WF_STATS
-                       if (i < 4) {
-                               hw->status_found_during_sleep[i]++;
-                       }
-#endif WF_STATS
+               if (wavefront_status() & mask) {
                        return 1;
                }
 
-               if (wavefront_sleep (hw, HZ/sleep_interval)) {
+               if (wavefront_sleep (HZ/sleep_interval)) {
                        return (0);
                }
        }
 
-       return 0;
+       return (0);
 }
 
 static int
-wavefront_read (wf_config *hw)
+wavefront_read (void)
+
 {
-       if (wavefront_wait (hw, STAT_CAN_READ))
-               return inb (hw->data_port);
+       if (wavefront_wait (STAT_CAN_READ))
+               return inb (dev.data_port);
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_DATA) {
-               printk (KERN_DEBUG "WaveFront: read timeout.\n");
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_DATA, "read timeout.\n");
 
        return -1;
 }
 
 static int
-wavefront_write (wf_config *hw, unsigned char data)
+wavefront_write (unsigned char data)
 
 {
-       if (wavefront_wait (hw, STAT_CAN_WRITE)) {
-               outb (data, hw->data_port);
-               return 1;
+       if (wavefront_wait (STAT_CAN_WRITE)) {
+               outb (data, dev.data_port);
+               return 0;
        }
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_DATA) {
-               printk (KERN_DEBUG "WaveFront: write timeout.\n");
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_DATA, "write timeout.\n");
 
-       return 0;
+       return -1;
 }
 
 static int
-wavefront_cmd (wf_config *hw, int cmd,
-              unsigned char *rbuf,
-              unsigned char *wbuf)
+wavefront_cmd (int cmd, unsigned char *rbuf, unsigned char *wbuf)
 
 {
        int ack;
@@ -433,7 +503,7 @@ wavefront_cmd (wf_config *hw, int cmd,
        wavefront_command *wfcmd;
 
        if ((wfcmd = wavefront_get_command (cmd)) == (wavefront_command *) 0) {
-               printk (KERN_WARNING "WaveFront: command 0x%x not supported.\n",
+               printk (KERN_WARNING LOGNAME "command 0x%x not supported.\n",
                        cmd);
                return 1;
        }
@@ -448,89 +518,59 @@ wavefront_cmd (wf_config *hw, int cmd,
                rbuf = 0;
        }
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_CMD) {
-               printk (KERN_DEBUG "Wavefront: 0x%x [%s] (%d,%d,%d)\n",
-                       cmd, wfcmd->action, wfcmd->read_cnt, wfcmd->write_cnt,
-                       wfcmd->need_ack);
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n",
+                              cmd, wfcmd->action, wfcmd->read_cnt,
+                              wfcmd->write_cnt, wfcmd->need_ack);
     
-       if (!wavefront_write (hw, cmd)) { 
-#ifdef WF_DEBUG
-               if (hw->debug & (WF_DEBUG_IO|WF_DEBUG_CMD)) {
-                       printk (KERN_DEBUG "WaveFront: cannot request "
-                               "0x%x [%s].\n",
-                               cmd, wfcmd->action);
-               }
-#endif WF_DEBUG
+       if (wavefront_write (cmd)) { 
+               DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request "
+                                                    "0x%x [%s].\n",
+                                                    cmd, wfcmd->action);
                return 1;
        } 
 
        if (wfcmd->write_cnt > 0) {
-#ifdef WF_DEBUG
-               if (hw->debug & WF_DEBUG_DATA) {
-                       printk (KERN_DEBUG "WaveFront: writing %d bytes "
-                               "for 0x%x\n",
-                               wfcmd->write_cnt, cmd);
-               }
-#endif WF_DEBUG
+               DPRINT (WF_DEBUG_DATA, "writing %d bytes "
+                                       "for 0x%x\n",
+                                       wfcmd->write_cnt, cmd);
 
                for (i = 0; i < wfcmd->write_cnt; i++) {
-                       if (!wavefront_write (hw, wbuf[i])) {
-#ifdef WF_DEBUG
-                               if (hw->debug & WF_DEBUG_IO) {
-                                       printk (KERN_DEBUG
-                           "WaveFront: bad write for byte %d of 0x%x [%s].\n",
-                                               i, cmd, wfcmd->action);
-                               }
-#endif WF_DEBUG
+                       if (wavefront_write (wbuf[i])) {
+                               DPRINT (WF_DEBUG_IO, "bad write for byte "
+                                                     "%d of 0x%x [%s].\n",
+                                                     i, cmd, wfcmd->action);
                                return 1;
                        }
-#ifdef WF_DEBUG
-                       if (hw->debug & WF_DEBUG_DATA) {
-                               printk (KERN_DEBUG
-                                        "WaveFront: write[%d] = 0x%x\n",
-                                       i, wbuf[i]);
-#endif WF_DEBUG
-                       }
+
+                       DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n",
+                                               i, wbuf[i]);
                }
        }
 
        if (wfcmd->read_cnt > 0) {
-#ifdef WF_DEBUG
-               if (hw->debug & WF_DEBUG_DATA) {
-                       printk (KERN_DEBUG "WaveFront: reading %d ints "
-                               "for 0x%x\n",
-                               wfcmd->read_cnt, cmd);
-               }
-#endif WF_DEBUG
+               DPRINT (WF_DEBUG_DATA, "reading %d ints "
+                                       "for 0x%x\n",
+                                       wfcmd->read_cnt, cmd);
 
                for (i = 0; i < wfcmd->read_cnt; i++) {
 
-                       if ((c = wavefront_read(hw)) == -1) {
-#ifdef WF_DEBUG
-                               if (hw->debug & WF_DEBUG_IO) {
-                                       printk (KERN_DEBUG
-                               "WaveFront: bad read for byte %d of 0x%x [%s].\n",
-                                               i, cmd, wfcmd->action);
-                               }
-#endif WF_DEBUG
+                       if ((c = wavefront_read()) == -1) {
+                               DPRINT (WF_DEBUG_IO, "bad read for byte "
+                                                     "%d of 0x%x [%s].\n",
+                                                     i, cmd, wfcmd->action);
                                return 1;
                        }
 
                        /* Now handle errors. Lots of special cases here */
            
                        if (c == 0xff) { 
-                               if ((c = wavefront_read (hw)) == -1) {
-#ifdef WF_DEBUG
-                                       if (hw->debug & WF_DEBUG_IO) {
-                                               printk (KERN_DEBUG
-                                 "WaveFront: bad read for error byte at "
-                                  "read byte %d of 0x%x [%s].\n",
-                                                       i, cmd, wfcmd->action);
-                                       }
-#endif WF_DEBUG
+                               if ((c = wavefront_read ()) == -1) {
+                                       DPRINT (WF_DEBUG_IO, "bad read for "
+                                                             "error byte at "
+                                                             "read byte %d "
+                                                             "of 0x%x [%s].\n",
+                                                             i, cmd,
+                                                             wfcmd->action);
                                        return 1;
                                }
 
@@ -553,60 +593,44 @@ wavefront_cmd (wf_config *hw, int cmd,
 
                                } else {
 
-#ifdef WF_DEBUG
-                                       if (hw->debug & WF_DEBUG_IO) {
-                                               printk (KERN_DEBUG
-                                            "WaveFront: error %d (%s) during "
-                                                "read for byte "
-                                                 "%d of 0x%x [%s].\n",
-                                                       c,
-                                                       wavefront_errorstr (c),
-                                                       i, cmd, wfcmd->action);
-                                       }
-#endif WF_DEBUG
+                                       DPRINT (WF_DEBUG_IO, "error %d (%s) "
+                                                             "during "
+                                                             "read for byte "
+                                                             "%d of 0x%x "
+                                                             "[%s].\n",
+                                                             c,
+                                                             wavefront_errorstr (c),
+                                                             i, cmd,
+                                                             wfcmd->action);
                                        return 1;
 
                                }
-                       } else {
+               
+               } else {
                                rbuf[i] = c;
                        }
-
-#ifdef WF_DEBUG
-                       if (hw->debug & WF_DEBUG_DATA) {
-                               printk (KERN_DEBUG
-                                       "WaveFront: read[%d] = 0x%x\n",
-                                       i, rbuf[i]);
-                       }
-#endif WF_DEBUG
+                       
+                       DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]);
                }
        }
-
+       
        if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) {
 
-#ifdef WF_DEBUG
-               if (hw->debug & WF_DEBUG_CMD) {
-                       printk (KERN_DEBUG "WaveFront: reading ACK for 0x%x\n",
-                               cmd);
-               }
-#endif WF_DEBUG
+               DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd);
 
                /* Some commands need an ACK, but return zero instead
                   of the standard value.
                */
            
-               if ((ack = wavefront_read(hw)) == 0) {
+               if ((ack = wavefront_read()) == 0) {
                        ack = WF_ACK;
                }
        
                if (ack != WF_ACK) {
                        if (ack == -1) {
-#ifdef WF_DEBUG
-                               if (hw->debug & WF_DEBUG_IO) {
-                                       printk (KERN_DEBUG
-                               "WaveFront: cannot read ack for 0x%x [%s].\n",
-                                               cmd, wfcmd->action);
-                               }
-#endif WF_DEBUG
+                               DPRINT (WF_DEBUG_IO, "cannot read ack for "
+                                                     "0x%x [%s].\n",
+                                                     cmd, wfcmd->action);
                                return 1;
                
                        } else {
@@ -614,47 +638,32 @@ wavefront_cmd (wf_config *hw, int cmd,
 
                                if (ack == 0xff) { /* explicit error */
                    
-                                       if ((err = wavefront_read (hw)) == -1) {
-#ifdef WF_DEBUG
-                                               if (hw->debug & WF_DEBUG_DATA) {
-                                                       printk (KERN_DEBUG
-                               "WaveFront: cannot read err for 0x%x [%s].\n",
-                                                            cmd, wfcmd->action);
-                                               }
-#endif WF_DEBUG
+                                       if ((err = wavefront_read ()) == -1) {
+                                               DPRINT (WF_DEBUG_DATA,
+                                                       "cannot read err "
+                                                       "for 0x%x [%s].\n",
+                                                       cmd, wfcmd->action);
                                        }
                                }
-
-#ifdef WF_DEBUG
-                               if (hw->debug & WF_DEBUG_IO) {
-                                       printk (KERN_DEBUG
-                                               "WaveFront: 0x%x [%s] "
-                                               "failed (0x%x, 0x%x, %s)\n",
-                                               cmd, wfcmd->action, ack, err,
-                                               wavefront_errorstr (err));
-                               }
-#endif WF_DEBUG
+                               
+                               DPRINT (WF_DEBUG_IO, "0x%x [%s] "
+                                       "failed (0x%x, 0x%x, %s)\n",
+                                       cmd, wfcmd->action, ack, err,
+                                       wavefront_errorstr (err));
+                               
                                return -err;
-                       } 
-               }
-
-#ifdef WF_DEBUG
-               if (hw->debug & WF_DEBUG_DATA) {
-                       printk (KERN_DEBUG "WaveFront: ack received "
-                               "for 0x%x [%s]\n",
-                               cmd, wfcmd->action);
+                       }
                }
-#endif WF_DEBUG
+               
+               DPRINT (WF_DEBUG_DATA, "ack received "
+                                       "for 0x%x [%s]\n",
+                                       cmd, wfcmd->action);
        } else {
-#ifdef WF_DEBUG
-               if (hw->debug & WF_DEBUG_CMD) {
-                       printk (KERN_DEBUG 
-                               "Wavefront: 0x%x [%s] does not need "
-                               "ACK (%d,%d,%d)\n",
-                               cmd, wfcmd->action, wfcmd->read_cnt,
-                               wfcmd->write_cnt, wfcmd->need_ack);
-#endif WF_DEBUG
-               }
+
+               DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need "
+                                      "ACK (%d,%d,%d)\n",
+                                      cmd, wfcmd->action, wfcmd->read_cnt,
+                                      wfcmd->write_cnt, wfcmd->need_ack);
        }
 
        return 0;
@@ -749,7 +758,7 @@ WaveFront: sample, patch and program management.
 ***********************************************************************/
 
 static int
-wavefront_delete_sample (wf_config *hw, int sample_num)
+wavefront_delete_sample (int sample_num)
 
 {
        unsigned char wbuf[2];
@@ -758,15 +767,15 @@ wavefront_delete_sample (wf_config *hw, int sample_num)
        wbuf[0] = sample_num & 0x7f;
        wbuf[1] = sample_num >> 7;
 
-       if ((x = wavefront_cmd (hw, WFC_DELETE_SAMPLE, 0, wbuf)) == 0) {
-               hw->sample_status[sample_num] = WF_ST_EMPTY;
+       if ((x = wavefront_cmd (WFC_DELETE_SAMPLE, 0, wbuf)) == 0) {
+               dev.sample_status[sample_num] = WF_ST_EMPTY;
        }
 
        return x;
 }
 
 static int
-wavefront_get_sample_status (struct wf_config *hw, int assume_rom)
+wavefront_get_sample_status (int assume_rom)
 
 {
        int i;
@@ -775,29 +784,30 @@ wavefront_get_sample_status (struct wf_config *hw, int assume_rom)
 
        /* check sample status */
     
-       if (wavefront_cmd (hw, WFC_GET_NSAMPLES, rbuf, wbuf)) {
-               printk ("WaveFront: cannot request sample count.\n");
+       if (wavefront_cmd (WFC_GET_NSAMPLES, rbuf, wbuf)) {
+               printk (KERN_WARNING LOGNAME "cannot request sample count.\n");
+               return -1;
        } 
     
-       sc_real = sc_alias = sc_multi = hw->samples_used = 0;
+       sc_real = sc_alias = sc_multi = dev.samples_used = 0;
     
        for (i = 0; i < WF_MAX_SAMPLE; i++) {
        
                wbuf[0] = i & 0x7f;
                wbuf[1] = i >> 7;
 
-               if (wavefront_cmd (hw, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
-                       printk (KERN_WARNING
-                               "WaveFront: cannot identify sample "
+               if (wavefront_cmd (WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
+                       printk (KERN_WARNING LOGNAME
+                               "cannot identify sample "
                                "type of slot %d\n", i);
-                       hw->sample_status[i] = WF_ST_EMPTY;
+                       dev.sample_status[i] = WF_ST_EMPTY;
                        continue;
                }
 
-               hw->sample_status[i] = (WF_SLOT_FILLED|rbuf[0]);
+               dev.sample_status[i] = (WF_SLOT_FILLED|rbuf[0]);
 
                if (assume_rom) {
-                       hw->sample_status[i] |= WF_SLOT_ROM;
+                       dev.sample_status[i] |= WF_SLOT_ROM;
                }
 
                switch (rbuf[0] & WF_ST_MASK) {
@@ -814,21 +824,20 @@ wavefront_get_sample_status (struct wf_config *hw, int assume_rom)
                        break;
 
                default:
-                       printk (KERN_WARNING
-                               "WaveFront: unknown sample type for "
+                       printk (KERN_WARNING LOGNAME "unknown sample type for "
                                "slot %d (0x%x)\n", 
                                i, rbuf[0]);
                }
 
                if (rbuf[0] != WF_ST_EMPTY) {
-                       hw->samples_used++;
+                       dev.samples_used++;
                } 
        }
 
-       printk (KERN_INFO
-               "WaveFront: %d samples used (%d real, %d aliases, %d multi), "
-               "%d empty\n", hw->samples_used, sc_real, sc_alias, sc_multi,
-               WF_MAX_SAMPLE - hw->samples_used);
+       printk (KERN_INFO LOGNAME
+               "%d samples used (%d real, %d aliases, %d multi), "
+               "%d empty\n", dev.samples_used, sc_real, sc_alias, sc_multi,
+               WF_MAX_SAMPLE - dev.samples_used);
 
 
        return (0);
@@ -836,7 +845,8 @@ wavefront_get_sample_status (struct wf_config *hw, int assume_rom)
 }
 
 static int
-wavefront_get_patch_status (struct wf_config *hw)
+wavefront_get_patch_status (void)
+
 {
        unsigned char patchbuf[WF_PATCH_BYTES];
        unsigned char patchnum[2];
@@ -847,21 +857,21 @@ wavefront_get_patch_status (struct wf_config *hw)
                patchnum[0] = i & 0x7f;
                patchnum[1] = i >> 7;
 
-               if ((x = wavefront_cmd (hw, WFC_UPLOAD_PATCH, patchbuf,
+               if ((x = wavefront_cmd (WFC_UPLOAD_PATCH, patchbuf,
                                        patchnum)) == 0) {
 
-                       hw->patch_status[i] |= WF_SLOT_FILLED;
+                       dev.patch_status[i] |= WF_SLOT_FILLED;
                        p = (wavefront_patch *) patchbuf;
-                       hw->sample_status
+                       dev.sample_status
                                [p->sample_number|(p->sample_msb<<7)] |=
                                WF_SLOT_USED;
            
                } else if (x == 3) { /* Bad patch number */
-                       hw->patch_status[i] = 0;
+                       dev.patch_status[i] = 0;
                } else {
-                       printk (KERN_ERR "WaveFront: upload patch "
+                       printk (KERN_ERR LOGNAME "upload patch "
                                "error 0x%x\n", x);
-                       hw->patch_status[i] = 0;
+                       dev.patch_status[i] = 0;
                        return 1;
                }
        }
@@ -869,22 +879,23 @@ wavefront_get_patch_status (struct wf_config *hw)
        /* program status has already filled in slot_used bits */
 
        for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) {
-               if (hw->patch_status[i] & WF_SLOT_FILLED) {
+               if (dev.patch_status[i] & WF_SLOT_FILLED) {
                        cnt++;
                }
-               if (hw->patch_status[i] & WF_SLOT_USED) {
+               if (dev.patch_status[i] & WF_SLOT_USED) {
                        cnt2++;
                }
        
        }
-       printk (KERN_INFO
-               "WaveFront: %d patch slots filled, %d in use\n", cnt, cnt2);
+       printk (KERN_INFO LOGNAME
+               "%d patch slots filled, %d in use\n", cnt, cnt2);
 
        return (0);
 }
 
 static int
-wavefront_get_program_status (struct wf_config *hw)
+wavefront_get_program_status (void)
+
 {
        unsigned char progbuf[WF_PROGRAM_BYTES];
        wavefront_program prog;
@@ -894,64 +905,59 @@ wavefront_get_program_status (struct wf_config *hw)
        for (i = 0; i < WF_MAX_PROGRAM; i++) {
                prognum = i;
 
-               if ((x = wavefront_cmd (hw, WFC_UPLOAD_PROGRAM, progbuf,
+               if ((x = wavefront_cmd (WFC_UPLOAD_PROGRAM, progbuf,
                                        &prognum)) == 0) {
 
-                       hw->prog_status[i] |= WF_SLOT_USED;
+                       dev.prog_status[i] |= WF_SLOT_USED;
 
                        demunge_buf (progbuf, (unsigned char *) &prog,
                                     WF_PROGRAM_BYTES);
 
                        for (l = 0; l < WF_NUM_LAYERS; l++) {
                                if (prog.layer[l].mute) {
-                                       hw->patch_status
+                                       dev.patch_status
                                                [prog.layer[l].patch_number] |=
                                                WF_SLOT_USED;
                                }
                        }
                } else if (x == 1) { /* Bad program number */
-                       hw->prog_status[i] = 0;
+                       dev.prog_status[i] = 0;
                } else {
-                       printk (KERN_ERR "WaveFront: upload program "
+                       printk (KERN_ERR LOGNAME "upload program "
                                "error 0x%x\n", x);
-                       hw->prog_status[i] = 0;
+                       dev.prog_status[i] = 0;
                }
        }
 
        for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) {
-               if (hw->prog_status[i]) {
+               if (dev.prog_status[i]) {
                        cnt++;
                }
        }
 
-       printk (KERN_INFO "WaveFront: %d programs slots in use\n", cnt);
+       printk (KERN_INFO LOGNAME "%d programs slots in use\n", cnt);
 
        return (0);
 }
 
 static int
-wavefront_send_patch (wf_config *hw, 
-                     wavefront_patch_info *header)
+wavefront_send_patch (wavefront_patch_info *header)
 
 {
        unsigned char buf[WF_PATCH_BYTES+2];
        unsigned char *bptr;
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_LOAD_PATCH) {
-               printk (KERN_DEBUG "WaveFront: downloading patch %d\n",
-                       header->number);
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n",
+                                     header->number);
 
-       hw->patch_status[header->number] |= WF_SLOT_FILLED;
+       dev.patch_status[header->number] |= WF_SLOT_FILLED;
 
        bptr = buf;
        bptr = munge_int32 (header->number, buf, 2);
        munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES);
     
-       if (wavefront_cmd (hw, WFC_DOWNLOAD_PATCH, 0, buf)) {
-               printk (KERN_ERR "WaveFront: download patch failed\n");
+       if (wavefront_cmd (WFC_DOWNLOAD_PATCH, 0, buf)) {
+               printk (KERN_ERR LOGNAME "download patch failed\n");
                return -(EIO);
        }
 
@@ -959,21 +965,16 @@ wavefront_send_patch (wf_config *hw,
 }
 
 static int
-wavefront_send_program (wf_config *hw, 
-                       wavefront_patch_info *header)
+wavefront_send_program (wavefront_patch_info *header)
 
 {
        unsigned char buf[WF_PROGRAM_BYTES+1];
        int i;
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_LOAD_PATCH) {
-               printk (KERN_DEBUG
-                       "WaveFront: downloading program %d\n", header->number);
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n",
+               header->number);
 
-       hw->prog_status[header->number] = WF_SLOT_USED;
+       dev.prog_status[header->number] = WF_SLOT_USED;
 
        /* XXX need to zero existing SLOT_USED bit for program_status[i]
           where `i' is the program that's being (potentially) overwritten.
@@ -981,7 +982,7 @@ wavefront_send_program (wf_config *hw,
     
        for (i = 0; i < WF_NUM_LAYERS; i++) {
                if (header->hdr.pr.layer[i].mute) {
-                       hw->patch_status[header->hdr.pr.layer[i].patch_number] |=
+                       dev.patch_status[header->hdr.pr.layer[i].patch_number] |=
                                WF_SLOT_USED;
 
                        /* XXX need to mark SLOT_USED for sample used by
@@ -993,8 +994,8 @@ wavefront_send_program (wf_config *hw,
        buf[0] = header->number;
        munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES);
     
-       if (wavefront_cmd (hw, WFC_DOWNLOAD_PROGRAM, 0, buf)) {
-               printk (KERN_WARNING "WaveFront: download patch failed\n");     
+       if (wavefront_cmd (WFC_DOWNLOAD_PROGRAM, 0, buf)) {
+               printk (KERN_WARNING LOGNAME "download patch failed\n");        
                return -(EIO);
        }
 
@@ -1002,13 +1003,13 @@ wavefront_send_program (wf_config *hw,
 }
 
 static int
-wavefront_freemem (wf_config *hw)
+wavefront_freemem (void)
 
 {
        char rbuf[8];
 
-       if (wavefront_cmd (hw, WFC_REPORT_FREE_MEMORY, rbuf, 0)) {
-               printk (KERN_WARNING "WaveFront: can't get memory stats.\n");
+       if (wavefront_cmd (WFC_REPORT_FREE_MEMORY, rbuf, 0)) {
+               printk (KERN_WARNING LOGNAME "can't get memory stats.\n");
                return -1;
        } else {
                return demunge_int32 (rbuf, 4);
@@ -1016,8 +1017,7 @@ wavefront_freemem (wf_config *hw)
 }
 
 static int
-wavefront_send_sample (wf_config      *hw,
-                      wavefront_patch_info *header,
+wavefront_send_sample (wavefront_patch_info *header,
                       UINT16 *dataptr,
                       int data_is_unsigned)
 
@@ -1045,15 +1045,22 @@ wavefront_send_sample (wf_config      *hw,
        int skip = 0;
        int initial_skip = 0;
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_LOAD_PATCH) {
-               printk (KERN_DEBUG "WaveFront: sample %sdownload for slot %d, "
-                       "type %d, %d bytes from 0x%x\n",
-                       header->size ? "" : "header ", 
-                       header->number, header->subkey, header->size,
-                       (int) header->dataptr);
+       DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, "
+                                     "type %d, %d bytes from 0x%x\n",
+                                     header->size ? "" : "header ", 
+                                     header->number, header->subkey,
+                                     header->size,
+                                     (int) header->dataptr);
+
+       if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) {
+               int x;
+
+               if ((x = wavefront_find_free_sample ()) < 0) {
+                       return -ENOMEM;
+               }
+               printk (KERN_DEBUG LOGNAME "unspecified sample => %d\n", x);
+               header->number = x;
        }
-#endif WF_DEBUG
 
        if (header->size) {
 
@@ -1080,24 +1087,24 @@ wavefront_send_sample (wf_config      *hw,
                   a copy of the patch/program/sample header data.
                */
 
-               if (hw->rom_samples_rdonly) {
-                       if (hw->sample_status[header->number] & WF_SLOT_ROM) {
-                               printk (KERN_ERR "WaveFront: sample slot %d "
+               if (dev.rom_samples_rdonly) {
+                       if (dev.sample_status[header->number] & WF_SLOT_ROM) {
+                               printk (KERN_ERR LOGNAME "sample slot %d "
                                        "write protected\n",
                                        header->number);
                                return -EACCES;
                        }
                }
 
-               wavefront_delete_sample (hw, header->number);
+               wavefront_delete_sample (header->number);
        }
 
        if (header->size) {
-               hw->freemem = wavefront_freemem (hw);
+               dev.freemem = wavefront_freemem ();
 
-               if (hw->freemem < header->size) {
-                       printk (KERN_ERR
-                               "WaveFront: insufficient memory to "
+               if (dev.freemem < header->size) {
+                       printk (KERN_ERR LOGNAME
+                               "insufficient memory to "
                                "load %d byte sample.\n",
                                header->size);
                        return -ENOMEM;
@@ -1107,16 +1114,10 @@ wavefront_send_sample (wf_config      *hw,
 
        skip = WF_GET_CHANNEL(&header->hdr.s);
 
-       if (skip > 0) {
-               switch (header->hdr.s.SampleResolution) {
-               case LINEAR_16BIT:
-                       break;
-               default:
-                       printk (KERN_ERR
-                               "WaveFront: channel selection only possible "
-                               "on 16-bit samples");
-                       return -(EINVAL);
-               }
+       if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) {
+               printk (KERN_ERR LOGNAME "channel selection only "
+                       "possible on 16-bit samples");
+               return -(EINVAL);
        }
 
        switch (skip) {
@@ -1150,13 +1151,10 @@ wavefront_send_sample (wf_config      *hw,
                break;
        }
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_LOAD_PATCH) {
-               printk (KERN_DEBUG "WaveFront: channel selection: %d => "
-                       "initial skip = %d, skip = %d\n",
-                       WF_GET_CHANNEL (&header->hdr.s), initial_skip, skip);
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => "
+                                     "initial skip = %d, skip = %d\n",
+                                     WF_GET_CHANNEL (&header->hdr.s),
+                                     initial_skip, skip);
     
        /* Be safe, and zero the "Unused" bits ... */
 
@@ -1210,10 +1208,10 @@ wavefront_send_sample (wf_config      *hw,
        shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1),
                             shptr, 2);
 
-       if (wavefront_cmd (hw, header->size ?
+       if (wavefront_cmd (header->size ?
                           WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER,
                           0, sample_hdr)) {
-               printk (KERN_WARNING "WaveFront: sample %sdownload refused.\n",
+               printk (KERN_WARNING LOGNAME "sample %sdownload refused.\n",
                        header->size ? "" : "header ");
                return -(EIO);
        }
@@ -1238,8 +1236,8 @@ wavefront_send_sample (wf_config      *hw,
                        blocksize = ((length-written+7)&~0x7);
                }
 
-               if (wavefront_cmd (hw, WFC_DOWNLOAD_BLOCK, 0, 0)) {
-                       printk (KERN_WARNING "WaveFront: download block "
+               if (wavefront_cmd (WFC_DOWNLOAD_BLOCK, 0, 0)) {
+                       printk (KERN_WARNING LOGNAME "download block "
                                "request refused.\n");
                        return -(EIO);
                }
@@ -1248,7 +1246,7 @@ wavefront_send_sample (wf_config      *hw,
 
                        if (dataptr < data_end) {
                
-                               get_user (sample_short, dataptr);
+                               __get_user (sample_short, dataptr);
                                dataptr += skip;
                
                                if (data_is_unsigned) { /* GUS ? */
@@ -1287,21 +1285,23 @@ wavefront_send_sample (wf_config      *hw,
                        }
            
                        if (i < blocksize - 1) {
-                               outw (sample_short, hw->block_port);
+                               outw (sample_short, dev.block_port);
                        } else {
-                               outw (sample_short, hw->last_block_port);
+                               outw (sample_short, dev.last_block_port);
                        }
                }
 
-               /* Get "DMA page acknowledge" */
+               /* Get "DMA page acknowledge", even though its really
+                  nothing to do with DMA at all.
+               */
        
-               if ((dma_ack = wavefront_read (hw)) != WF_DMA_ACK) {
+               if ((dma_ack = wavefront_read ()) != WF_DMA_ACK) {
                        if (dma_ack == -1) {
-                               printk (KERN_ERR "WaveFront: upload sample "
+                               printk (KERN_ERR LOGNAME "upload sample "
                                        "DMA ack timeout\n");
                                return -(EIO);
                        } else {
-                               printk (KERN_ERR "WaveFront: upload sample "
+                               printk (KERN_ERR LOGNAME "upload sample "
                                        "DMA ack error 0x%x\n",
                                        dma_ack);
                                return -(EIO);
@@ -1309,7 +1309,7 @@ wavefront_send_sample (wf_config      *hw,
                }
        }
 
-       hw->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE);
+       dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE);
 
        /* Note, label is here because sending the sample header shouldn't
           alter the sample_status info at all.
@@ -1320,20 +1320,15 @@ wavefront_send_sample (wf_config      *hw,
 }
 
 static int
-wavefront_send_alias (struct wf_config *hw, 
-                     wavefront_patch_info *header)
+wavefront_send_alias (wavefront_patch_info *header)
 
 {
        unsigned char alias_hdr[WF_ALIAS_BYTES];
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_LOAD_PATCH) {
-               printk (KERN_DEBUG "WaveFront: download alias, %d is "
-                       "alias for %d\n",
-                       header->number,
-                       header->hdr.a.OriginalSample);
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is "
+                                     "alias for %d\n",
+                                     header->number,
+                                     header->hdr.a.OriginalSample);
     
        munge_int32 (header->number, &alias_hdr[0], 2);
        munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2);
@@ -1348,19 +1343,18 @@ wavefront_send_alias (struct wf_config *hw,
        munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3);
        munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2);
 
-       if (wavefront_cmd (hw, WFC_DOWNLOAD_SAMPLE_ALIAS, 0, alias_hdr)) {
-               printk (KERN_ERR "WaveFront: download alias failed.\n");
+       if (wavefront_cmd (WFC_DOWNLOAD_SAMPLE_ALIAS, 0, alias_hdr)) {
+               printk (KERN_ERR LOGNAME "download alias failed.\n");
                return -(EIO);
        }
 
-       hw->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS);
+       dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS);
 
        return (0);
 }
 
 static int
-wavefront_send_multisample (struct wf_config *hw,
-                           wavefront_patch_info *header)
+wavefront_send_multisample (wavefront_patch_info *header)
 {
        int i;
        int num_samples;
@@ -1376,23 +1370,16 @@ wavefront_send_multisample (struct wf_config *hw,
        num_samples = (1<<(header->hdr.ms.NumberOfSamples&7));
        msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples;
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_LOAD_PATCH) {
-               printk (KERN_DEBUG "WaveFront: multi %d with %d=%d samples\n",
-                       header->number, header->hdr.ms.NumberOfSamples, num_samples);
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n",
+                                     header->number,
+                                     header->hdr.ms.NumberOfSamples,
+                                     num_samples);
 
        for (i = 0; i < num_samples; i++) {
-#ifdef WF_DEBUG
-               if ((hw->debug & (WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA)) ==
-                   (WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA)) {
-                       printk (KERN_DEBUG "WaveFront: sample[%d] = %d\n",
-                               i, header->hdr.ms.SampleNumber[i]);
-               }
-#endif WF_DEBUG
+               DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n",
+                      i, header->hdr.ms.SampleNumber[i]);
                munge_int32 (header->hdr.ms.SampleNumber[i],
-                            &msample_hdr[3+(i*2)], 2);
+                    &msample_hdr[3+(i*2)], 2);
        }
     
        /* Need a hack here to pass in the number of bytes
@@ -1400,21 +1387,20 @@ wavefront_send_multisample (struct wf_config *hw,
           one day, I'll fix it.
        */
 
-       if (wavefront_cmd (hw, WFC_DOWNLOAD_MULTISAMPLE, 
+       if (wavefront_cmd (WFC_DOWNLOAD_MULTISAMPLE, 
                           (unsigned char *) ((num_samples*2)+3),
                           msample_hdr)) {
-               printk (KERN_ERR "WaveFront: download of multisample failed.\n");
+               printk (KERN_ERR LOGNAME "download of multisample failed.\n");
                return -(EIO);
        }
 
-       hw->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE);
+       dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE);
 
        return (0);
 }
 
 static int
-wavefront_fetch_multisample (struct wf_config *hw,
-                            wavefront_patch_info *header)
+wavefront_fetch_multisample (wavefront_patch_info *header)
 {
        int i;
        unsigned char log_ns[1];
@@ -1423,17 +1409,13 @@ wavefront_fetch_multisample (struct wf_config *hw,
 
        munge_int32 (header->number, number, 2);
     
-       if (wavefront_cmd (hw, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) {
-               printk (KERN_ERR "WaveFront: upload multisample failed.\n");
+       if (wavefront_cmd (WFC_UPLOAD_MULTISAMPLE, log_ns, number)) {
+               printk (KERN_ERR LOGNAME "upload multisample failed.\n");
                return -(EIO);
        }
     
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_DATA) {
-               printk (KERN_DEBUG "WaveFront: msample %d has %d samples\n",
-                       header->number, log_ns[0]);
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n",
+                               header->number, log_ns[0]);
 
        header->hdr.ms.NumberOfSamples = log_ns[0];
 
@@ -1444,14 +1426,14 @@ wavefront_fetch_multisample (struct wf_config *hw,
        for (i = 0; i < num_samples; i++) {
                char d[2];
        
-               if ((d[0] = wavefront_read (hw)) == -1) {
-                       printk (KERN_ERR "WaveFront: upload multisample failed "
+               if ((d[0] = wavefront_read ()) == -1) {
+                       printk (KERN_ERR LOGNAME "upload multisample failed "
                                "during sample loop.\n");
                        return -(EIO);
                }
 
-               if ((d[1] = wavefront_read (hw)) == -1) {
-                       printk (KERN_ERR "WaveFront: upload multisample failed "
+               if ((d[1] = wavefront_read ()) == -1) {
+                       printk (KERN_ERR LOGNAME "upload multisample failed "
                                "during sample loop.\n");
                        return -(EIO);
                }
@@ -1459,13 +1441,8 @@ wavefront_fetch_multisample (struct wf_config *hw,
                header->hdr.ms.SampleNumber[i] =
                        demunge_int32 ((unsigned char *) d, 2);
        
-#ifdef WF_DEBUG
-               if (hw->debug & WF_DEBUG_DATA) {
-                       printk (KERN_DEBUG "WaveFront: msample "
-                               "sample[%d] = %d\n",
-                               i, header->hdr.ms.SampleNumber[i]);
-               }
-#endif WF_DEBUG
+               DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n",
+                                       i, header->hdr.ms.SampleNumber[i]);
        }
 
        return (0);
@@ -1473,21 +1450,16 @@ wavefront_fetch_multisample (struct wf_config *hw,
 
 
 static int
-wavefront_send_drum (struct wf_config *hw, wavefront_patch_info *header)
+wavefront_send_drum (wavefront_patch_info *header)
 
 {
        unsigned char drumbuf[WF_DRUM_BYTES];
        wavefront_drum *drum = &header->hdr.d;
        int i;
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_LOAD_PATCH) {
-               printk (KERN_DEBUG
-                       "WaveFront: downloading edrum for MIDI "
-                       "note %d, patch = %d\n", 
-                       header->number, drum->PatchNumber);
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI "
+               "note %d, patch = %d\n", 
+               header->number, drum->PatchNumber);
 
        drumbuf[0] = header->number & 0x7f;
 
@@ -1495,8 +1467,8 @@ wavefront_send_drum (struct wf_config *hw, wavefront_patch_info *header)
                munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2);
        }
 
-       if (wavefront_cmd (hw, WFC_DOWNLOAD_EDRUM_PROGRAM, 0, drumbuf)) {
-               printk (KERN_ERR "WaveFront: download drum failed.\n");
+       if (wavefront_cmd (WFC_DOWNLOAD_EDRUM_PROGRAM, 0, drumbuf)) {
+               printk (KERN_ERR LOGNAME "download drum failed.\n");
                return -(EIO);
        }
 
@@ -1504,32 +1476,32 @@ wavefront_send_drum (struct wf_config *hw, wavefront_patch_info *header)
 }
 
 static int 
-wavefront_find_free_sample (struct wf_config *hw)
+wavefront_find_free_sample (void)
 
 {
        int i;
 
        for (i = 0; i < WF_MAX_SAMPLE; i++) {
-               if (!(hw->sample_status[i] & WF_SLOT_FILLED)) {
+               if (!(dev.sample_status[i] & WF_SLOT_FILLED)) {
                        return i;
                }
        }
-       printk (KERN_WARNING "WaveFront: no free sample slots!\n");
+       printk (KERN_WARNING LOGNAME "no free sample slots!\n");
        return -1;
 }
 
 static int 
-wavefront_find_free_patch (struct wf_config *hw)
+wavefront_find_free_patch (void)
 
 {
        int i;
 
        for (i = 0; i < WF_MAX_PATCH; i++) {
-               if (!(hw->patch_status[i] & WF_SLOT_FILLED)) {
+               if (!(dev.patch_status[i] & WF_SLOT_FILLED)) {
                        return i;
                }
        }
-       printk (KERN_WARNING "WaveFront: no free patch slots!\n");
+       printk (KERN_WARNING LOGNAME "no free patch slots!\n");
        return -1;
 }
 
@@ -1562,8 +1534,7 @@ log2_2048(int n)
 }
 
 static int
-wavefront_load_gus_patch (struct wf_config *hw,
-                         int dev, int format, const char *addr,
+wavefront_load_gus_patch (int devno, int format, const char *addr,
                          int offs, int count, int pmgr_flag)
 {
        struct patch_info guspatch;
@@ -1581,14 +1552,14 @@ wavefront_load_gus_patch (struct wf_config *hw,
        copy_from_user (&((char *) &guspatch)[offs],
                        &(addr)[offs], sizeof_patch - offs);
 
-       if ((i = wavefront_find_free_patch (hw)) == -1) {
+       if ((i = wavefront_find_free_patch ()) == -1) {
                return -EBUSY;
        }
        pat.number = i;
        pat.subkey = WF_ST_PATCH;
        patp = &pat.hdr.p;
 
-       if ((i = wavefront_find_free_sample (hw)) == -1) {
+       if ((i = wavefront_find_free_sample ()) == -1) {
                return -EBUSY;
        }
        samp.number = i;
@@ -1644,7 +1615,7 @@ wavefront_load_gus_patch (struct wf_config *hw,
        progp->layer[0].mix_level=127  /* guspatch.volume */;
        progp->layer[0].split_type=0;
        progp->layer[0].split_point=0;
-       progp->layer[0].updown=0;
+       progp->layer[0].play_below=0;
 
        for (i = 1; i < 4; i++) {
                progp->layer[i].mute=0;
@@ -1685,11 +1656,11 @@ wavefront_load_gus_patch (struct wf_config *hw,
 
        /* Now ship it down */
 
-       wavefront_send_sample (hw, &samp, 
+       wavefront_send_sample (&samp, 
                               (unsigned short *) &(addr)[sizeof_patch],
                               (guspatch.mode & WAVE_UNSIGNED) ? 1:0);
-       wavefront_send_patch (hw, &pat);
-       wavefront_send_program (hw, &prog);
+       wavefront_send_patch (&pat);
+       wavefront_send_program (&prog);
 
        /* Now pan as best we can ... use the slave/internal MIDI device
           number if it exists (since it talks to the WaveFront), or the
@@ -1697,8 +1668,8 @@ wavefront_load_gus_patch (struct wf_config *hw,
        */
 
 #ifdef CONFIG_MIDI
-       if (hw->mididev > 0) {
-               midi_synth_controller (hw->mididev, guspatch.instr_no, 10,
+       if (dev.mididev > 0) {
+               midi_synth_controller (dev.mididev, guspatch.instr_no, 10,
                                       ((guspatch.panning << 4) > 127) ?
                                       127 : (guspatch.panning << 4));
        }
@@ -1707,60 +1678,26 @@ wavefront_load_gus_patch (struct wf_config *hw,
        return(0);
 }
 
-int
-wavefront_load_patch (int dev, int format, const char *addr,
-                     int offs, int count, int pmgr_flag)
-{
-
-       struct wf_config *hw = &wavefront_configuration;
-       wavefront_patch_info header;
-
-       if (format == SYSEX_PATCH) {    /* Handled by midi_synth.c */
-               if (midi_load_patch == NULL) {
-                       printk (KERN_ERR
-                               "WaveFront: SYSEX not loadable: "
-                               "no midi patch loader!\n");
-                       return -(EINVAL);
-               }
-               return midi_load_patch (dev, format, addr,
-                                       offs, count, pmgr_flag);
-
-       } else if (format == GUS_PATCH) {
-               return wavefront_load_gus_patch (hw, dev, format,
-                                                addr, offs, count, pmgr_flag);
+static int
+wavefront_load_patch (const char *addr)
 
-       } else if (format != WAVEFRONT_PATCH) {
-               printk (KERN_ERR "WaveFront: unknown patch format %d\n", format);
-               return -(EINVAL);
-       }
 
-       if (count < sizeof (wavefront_patch_info)) {
-               printk (KERN_ERR "WaveFront: sample header too short\n");
+{
+       wavefront_patch_info header;
+       
+       if (copy_from_user (&header, addr, sizeof(wavefront_patch_info) -
+                           sizeof(wavefront_any))) {
+               printk (KERN_WARNING LOGNAME "bad address for load patch.\n");
                return -(EINVAL);
        }
 
-       /* copied in so far: `offs' bytes from `addr'. We shouldn't copy
-          them in again, and they correspond to header->key and header->devno.
-          So now, copy the rest of the wavefront_patch_info struct, except
-          for the 'hdr' field, since this is handled via indirection
-          through the 'hdrptr' field.
-       */
-
-       copy_from_user (&((char *) &header)[offs], &(addr)[offs],
-                       sizeof(wavefront_patch_info) -
-                       sizeof(wavefront_any) - offs);
-
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_LOAD_PATCH) {
-               printk (KERN_DEBUG "WaveFront: download "
-                       "Sample type: %d "
-                       "Sample number: %d "
-                       "Sample size: %d\n",
-                       header.subkey,
-                       header.number,
-                       header.size);
-       }
-#endif WF_DEBUG
+       DPRINT (WF_DEBUG_LOAD_PATCH, "download "
+                                     "Sample type: %d "
+                                     "Sample number: %d "
+                                     "Sample size: %d\n",
+                                     header.subkey,
+                                     header.number,
+                                     header.size);
 
        switch (header.subkey) {
        case WF_ST_SAMPLE:  /* sample or sample_header, based on patch->size */
@@ -1769,7 +1706,7 @@ wavefront_load_patch (int dev, int format, const char *addr,
                                (unsigned char *) header.hdrptr,
                                sizeof (wavefront_sample));
 
-               return wavefront_send_sample (hw, &header, header.dataptr, 0);
+               return wavefront_send_sample (&header, header.dataptr, 0);
 
        case WF_ST_MULTISAMPLE:
 
@@ -1777,7 +1714,7 @@ wavefront_load_patch (int dev, int format, const char *addr,
                                (unsigned char *) header.hdrptr,
                                sizeof (wavefront_multisample));
 
-               return wavefront_send_multisample (hw, &header);
+               return wavefront_send_multisample (&header);
 
 
        case WF_ST_ALIAS:
@@ -1786,31 +1723,31 @@ wavefront_load_patch (int dev, int format, const char *addr,
                                (unsigned char *) header.hdrptr,
                                sizeof (wavefront_alias));
 
-               return wavefront_send_alias (hw, &header);
+               return wavefront_send_alias (&header);
 
        case WF_ST_DRUM:
                copy_from_user ((unsigned char *) &header.hdr.d, 
                                (unsigned char *) header.hdrptr,
                                sizeof (wavefront_drum));
 
-               return wavefront_send_drum (hw, &header);
+               return wavefront_send_drum (&header);
 
        case WF_ST_PATCH:
                copy_from_user ((unsigned char *) &header.hdr.p, 
                                (unsigned char *) header.hdrptr,
                                sizeof (wavefront_patch));
 
-               return wavefront_send_patch (hw, &header);
+               return wavefront_send_patch (&header);
 
        case WF_ST_PROGRAM:
                copy_from_user ((unsigned char *) &header.hdr.pr, 
                                (unsigned char *) header.hdrptr,
                                sizeof (wavefront_program));
 
-               return wavefront_send_program (hw, &header);
+               return wavefront_send_program (&header);
 
        default:
-               printk (KERN_ERR "WaveFront: unknown patch type %d.\n",
+               printk (KERN_ERR LOGNAME "unknown patch type %d.\n",
                        header.subkey);
                return -(EINVAL);
        }
@@ -1855,155 +1792,248 @@ process_sample_hdr (UCHAR8 *buf)
 }
 
 static int
-wavefront_synth_control (int dev, int cmd, caddr_t arg)
+wavefront_synth_control (int cmd, wavefront_control *wc)
 
 {
-       struct wf_config *hw = &wavefront_configuration;
-       wavefront_control wc;
        unsigned char patchnumbuf[2];
        int i;
 
-       copy_from_user (&wc, arg, sizeof (wc));
+       DPRINT (WF_DEBUG_CMD, "synth control with "
+               "cmd 0x%x\n", wc->cmd);
 
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_CMD) {
-               printk (KERN_DEBUG "WaveFront: synth control with "
-                       "cmd 0x%x\n", wc.cmd);
-       }
-#endif WF_DEBUG
-
-       /* special case handling of or for various commands */
+       /* Pre-handling of or for various commands */
 
-       switch (wc.cmd) {
+       switch (wc->cmd) {
        case WFC_DISABLE_INTERRUPTS:
-               printk (KERN_INFO "WaveFront: interrupts disabled.\n");
-               outb (0x80|0x20, hw->control_port);
-               hw->interrupts_on = 0;
+               printk (KERN_INFO LOGNAME "interrupts disabled.\n");
+               outb (0x80|0x20, dev.control_port);
+               dev.interrupts_on = 0;
                return 0;
 
        case WFC_ENABLE_INTERRUPTS:
-               printk (KERN_INFO "WaveFront: interrupts enabled.\n");
-               outb (0x80|0x20|0x40, hw->control_port);
-               hw->interrupts_on = 1;
+               printk (KERN_INFO LOGNAME "interrupts enabled.\n");
+               outb (0x80|0x40|0x20, dev.control_port);
+               dev.interrupts_on = 1;
                return 0;
 
        case WFC_INTERRUPT_STATUS:
-               wc.rbuf[0] = hw->interrupts_on;
+               wc->rbuf[0] = dev.interrupts_on;
                return 0;
 
        case WFC_ROMSAMPLES_RDONLY:
-               hw->rom_samples_rdonly = wc.wbuf[0];
-               wc.status = 0;
+               dev.rom_samples_rdonly = wc->wbuf[0];
+               wc->status = 0;
                return 0;
 
        case WFC_IDENTIFY_SLOT_TYPE:
-               i = wc.wbuf[0] | (wc.wbuf[1] << 7);
+               i = wc->wbuf[0] | (wc->wbuf[1] << 7);
                if (i <0 || i >= WF_MAX_SAMPLE) {
-                       printk (KERN_WARNING "WaveFront: invalid slot ID %d\n",
+                       printk (KERN_WARNING LOGNAME "invalid slot ID %d\n",
                                i);
-                       wc.status = EINVAL;
+                       wc->status = EINVAL;
                        return 0;
                }
-               wc.rbuf[0] = hw->sample_status[i];
-               wc.status = 0;
+               wc->rbuf[0] = dev.sample_status[i];
+               wc->status = 0;
                return 0;
 
        case WFC_DEBUG_DRIVER:
-               hw->debug = wc.wbuf[0];
-               printk (KERN_INFO "WaveFront: debug = 0x%x\n", hw->debug);
+               dev.debug = wc->wbuf[0];
+               printk (KERN_INFO LOGNAME "debug = 0x%x\n", dev.debug);
                return 0;
 
        case WFC_FX_IOCTL:
-               wffx_ioctl (hw, (wavefront_fx_info *) &wc.wbuf[0]);
+               wffx_ioctl ((wavefront_fx_info *) &wc->wbuf[0]);
                return 0;
 
        case WFC_UPLOAD_PATCH:
-               munge_int32 (*((UINT32 *) wc.wbuf), patchnumbuf, 2);
-               memcpy (wc.wbuf, patchnumbuf, 2);
+               munge_int32 (*((UINT32 *) wc->wbuf), patchnumbuf, 2);
+               memcpy (wc->wbuf, patchnumbuf, 2);
                break;
 
        case WFC_UPLOAD_MULTISAMPLE:
+               /* multisamples have to be handled differently, and
+                  cannot be dealt with properly by wavefront_cmd() alone.
+               */
+               wc->status = wavefront_fetch_multisample
+                       ((wavefront_patch_info *) wc->rbuf);
+               return 0;
+
        case WFC_UPLOAD_SAMPLE_ALIAS:
-               printk (KERN_INFO "WaveFront: support for various uploads "
+               printk (KERN_INFO LOGNAME "support for sample alias upload "
                        "being considered.\n");
-               wc.status = EINVAL;
+               wc->status = EINVAL;
                return -EINVAL;
        }
 
-       wc.status = wavefront_cmd (hw, wc.cmd, wc.rbuf, wc.wbuf);
+       wc->status = wavefront_cmd (wc->cmd, wc->rbuf, wc->wbuf);
 
-       /* Special case handling of certain commands.
+       /* Post-handling of certain commands.
 
           In particular, if the command was an upload, demunge the data
           so that the user-level doesn't have to think about it.
        */
 
-       if (wc.status == 0) {
-               switch (wc.cmd) {
+       if (wc->status == 0) {
+               switch (wc->cmd) {
                        /* intercept any freemem requests so that we know
                           we are always current with the user-level view
                           of things.
                        */
 
                case WFC_REPORT_FREE_MEMORY:
-                       hw->freemem = demunge_int32 (wc.rbuf, 4);
+                       dev.freemem = demunge_int32 (wc->rbuf, 4);
                        break;
 
                case WFC_UPLOAD_PATCH:
-                       demunge_buf (wc.rbuf, wc.rbuf, WF_PATCH_BYTES);
+                       demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES);
                        break;
 
                case WFC_UPLOAD_PROGRAM:
-                       demunge_buf (wc.rbuf, wc.rbuf, WF_PROGRAM_BYTES);
+                       demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES);
                        break;
 
                case WFC_UPLOAD_EDRUM_PROGRAM:
-                       demunge_buf (wc.rbuf, wc.rbuf, WF_DRUM_BYTES - 1);
+                       demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1);
                        break;
 
                case WFC_UPLOAD_SAMPLE_HEADER:
-                       process_sample_hdr (wc.rbuf);
+                       process_sample_hdr (wc->rbuf);
                        break;
 
-               case WFC_UPLOAD_MULTISAMPLE:
                case WFC_UPLOAD_SAMPLE_ALIAS:
-                       printk (KERN_INFO "WaveFront: support for "
-                               "various uploads "
+                       printk (KERN_INFO LOGNAME "support for "
+                               "sample aliases still "
                                "being considered.\n");
                        break;
 
                case WFC_VMIDI_OFF:
-                       virtual_midi_disable (hw->mididev);
+                       if (virtual_midi_disable () < 0) {
+                               return -(EIO);
+                       }
                        break;
 
                case WFC_VMIDI_ON:
-                       virtual_midi_enable (hw->mididev, 0);
-                       break;
-
+                       if (virtual_midi_enable () < 0) {
+                               return -(EIO);
+                       }
                        break;
                }
        }
 
-       /* XXX It would be nice to avoid a complete copy of the whole
-          struct sometimes. But I think its fast enough that this
-          is a low priority fix.
-       */
+       return 0;
+}
 
-       copy_to_user (arg, &wc, sizeof (wc));
+\f
+/***********************************************************************/
+/* WaveFront: Linux file system interface (for access via raw synth)    */
+/***********************************************************************/
+
+static loff_t
+wavefront_llseek(struct file *file, loff_t offset, int origin)
+{
+       return -ESPIPE;
+}
+
+static int 
+wavefront_open (struct inode *inode, struct file *file)
+{
+       /* XXX fix me */
+       dev.opened = file->f_flags;
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
+static int
+wavefront_release(struct inode *inode, struct file *file)
+{
+       dev.opened = 0;
+       dev.debug = 0;
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static int
+wavefront_ioctl(struct inode *inode, struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       wavefront_control wc;
+       int err;
+
+       switch (cmd) {
+
+       case WFCTL_WFCMD:
+               copy_from_user (&wc, (void *) arg, sizeof (wc));
+               
+               if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
+                       copy_to_user ((void *) arg, &wc, sizeof (wc));
+               }
+
+               return err;
+               
+       case WFCTL_LOAD_SPP:
+               return wavefront_load_patch ((const char *) arg);
+               
+       default:
+               printk (KERN_WARNING LOGNAME "invalid ioctl %#x\n", cmd);
+               return -(EINVAL);
+
+       }
+       return 0;
+}
+
+static /*const*/ struct file_operations wavefront_fops = {
+       &wavefront_llseek,
+       NULL,  /* read */
+       NULL,  /* write */
+       NULL,  /* readdir */
+       NULL,  /* poll */
+       &wavefront_ioctl,
+       NULL,  /* mmap */
+       &wavefront_open,
+       NULL,  /* flush */
+       &wavefront_release,
+       NULL,  /* fsync */
+       NULL,  /* fasync */
+       NULL,  /* check_media_change */
+       NULL,  /* revalidate */
+       NULL,  /* lock */
+};
+
 \f
-/***********************************************************************
-WaveFront: MIDI synth interface
-***********************************************************************/
+/***********************************************************************/
+/* WaveFront: OSS installation and support interface                   */
+/***********************************************************************/
 
+#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+
+static struct synth_info wavefront_info =
+{"Turtle Beach WaveFront", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_WAVEFRONT,
+ 0, 32, 0, 0, SYNTH_CAP_INPUT};
 
 static int
-wavefront_ioctl (int dev, unsigned int cmd, caddr_t arg)
+wavefront_oss_open (int devno, int mode)
+
+{
+       dev.opened = mode;
+       return 0;
+}
+
+static void
+wavefront_oss_close (int devno)
+
 {
-       wf_config *hw = &wavefront_configuration;
-       unsigned char rbuf[4];
+       dev.opened = 0;
+       dev.debug = 0;
+       return;
+}
+
+static int
+wavefront_oss_ioctl (int devno, unsigned int cmd, caddr_t arg)
+
+{
+       wavefront_control wc;
+       int err;
 
        switch (cmd) {
        case SNDCTL_SYNTH_INFO:
@@ -2013,183 +2043,156 @@ wavefront_ioctl (int dev, unsigned int cmd, caddr_t arg)
                break;
 
        case SNDCTL_SEQ_RESETSAMPLES:
-               printk (KERN_WARNING
-                       "WaveFront: cannot reset sample status in kernel.\n");
+               printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
                return 0; /* don't force an error */
                break;
 
        case SNDCTL_SEQ_PERCMODE:
-               /* XXX does this correspond to anything obvious ?*/
                return 0; /* don't force an error */
                break;
 
        case SNDCTL_SYNTH_MEMAVL:
-               if (wavefront_cmd (hw, WFC_REPORT_FREE_MEMORY, rbuf, 0) != 0) {
-                       printk (KERN_ERR
-                               "WaveFront: cannot get free memory size\n");
-                       return 0;
+               if ((dev.freemem = wavefront_freemem ()) < 0) {
+                       printk (KERN_ERR LOGNAME "cannot get memory size\n");
+                       return -EIO;
                } else {
-                       hw->freemem = demunge_int32 (rbuf, 4);
-                       return hw->freemem;
+                       return dev.freemem;
                }
+               break;
 
        case SNDCTL_SYNTH_CONTROL:
-               return wavefront_synth_control (dev, cmd, arg);
+               copy_from_user (&wc, arg, sizeof (wc));
+
+               if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
+                       copy_to_user (arg, &wc, sizeof (wc));
+               }
+
+               return err;
 
        default:
                return -(EINVAL);
        }
 }
 
-static int
-wavefront_open (int dev, int mode)
-
+int
+wavefront_oss_load_patch (int devno, int format, const char *addr,
+                         int offs, int count, int pmgr_flag)
 {
-       struct wf_config *hw = &wavefront_configuration;
 
-       if (hw->opened) {
-               printk (KERN_WARNING "WaveFront: warning: device in use\n");
-       }
+       if (format == SYSEX_PATCH) {    /* Handled by midi_synth.c */
+               if (midi_load_patch == NULL) {
+                       printk (KERN_ERR LOGNAME
+                               "SYSEX not loadable: "
+                               "no midi patch loader!\n");
+                       return -(EINVAL);
+               }
 
-       hw->opened = mode;
-       return (0);
-}
+               return midi_load_patch (devno, format, addr,
+                                       offs, count, pmgr_flag);
 
-static void wavefront_close (int dev)
-{
-       struct wf_config *hw = &wavefront_configuration;
+       } else if (format == GUS_PATCH) {
+               return wavefront_load_gus_patch (devno, format,
+                                                addr, offs, count, pmgr_flag);
 
-#ifdef WF_STATS
-       int i;
-       printk ("Status during loop: %ld\n", hw->status_found_during_loop);
-       for (i = 0; i < 4; i++) {
-               printk ("Status during sleep[%d]: %ld\n",
-                       i, hw->status_found_during_sleep[i]);
+       } else if (format != WAVEFRONT_PATCH) {
+               printk (KERN_ERR LOGNAME "unknown patch format %d\n", format);
+               return -(EINVAL);
        }
-#endif WF_STATS
-       hw->opened = 0;
-       hw->debug = 0;
-
-       return;
-}
 
-static void wavefront_aftertouch (int dev, int channel, int pressure)
-{
-       midi_synth_aftertouch (wavefront_configuration.mididev,channel,pressure);
-};
+       if (count < sizeof (wavefront_patch_info)) {
+               printk (KERN_ERR LOGNAME "sample header too short\n");
+               return -(EINVAL);
+       }
 
-static void wavefront_bender (int dev, int chn, int value)
-{
-       midi_synth_bender (wavefront_configuration.mididev, chn, value);
-};
+       /* "addr" points to a user-space wavefront_patch_info */
 
-static void wavefront_controller (int dev, int channel, int ctrl_num, int value)
-{
-       if(ctrl_num==CTRL_PITCH_BENDER) wavefront_bender(0,channel,value);
-       midi_synth_controller (wavefront_configuration.mididev,
-                              channel,ctrl_num,value);
-};
+       return wavefront_load_patch (addr);
+}      
 
-static void wavefront_panning(int dev, int channel, int pressure)
+static struct synth_operations wavefront_operations =
 {
-       midi_synth_controller (wavefront_configuration.mididev,
-                              channel,CTL_PAN,pressure);
+       "WaveFront",
+       &wavefront_info,
+       0,
+       SYNTH_TYPE_SAMPLE,
+       SAMPLE_TYPE_WAVEFRONT,
+       wavefront_oss_open,
+       wavefront_oss_close,
+       wavefront_oss_ioctl,
+
+       midi_synth_kill_note,
+       midi_synth_start_note,
+       midi_synth_set_instr,
+       midi_synth_reset,
+       NULL, /* hw_control */
+       midi_synth_load_patch,
+       midi_synth_aftertouch,
+       midi_synth_controller,
+       midi_synth_panning,
+       NULL, /* volume method */
+       midi_synth_bender,
+       NULL, /* alloc voice */
+       midi_synth_setup_voice
 };
+#endif OSS_SUPPORT_SEQ
 
-static int wavefront_set_instr (int dev, int channel, int instr_no)
-{
-       return(midi_synth_set_instr (wavefront_configuration.mididev,
-                                    channel,instr_no));
-};
+#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALL
 
-static int wavefront_kill_note (int dev, int channel, int note, int volume)
-{
-       if (note==255)
-               return (midi_synth_start_note (wavefront_configuration.mididev,
-                                              channel, 0, 0));
-       return(midi_synth_kill_note (wavefront_configuration.mididev,
-                                    channel, note, volume));
-};
+void attach_wavefront (struct address_info *hw_config)
 
-static int wavefront_start_note (int dev, int channel, int note, int volume)
 {
-       if (note==255) {
-               midi_synth_aftertouch (wavefront_configuration.mididev,
-                                      channel,volume); 
-               return(0);
-       };
-
-       if (volume==0) {
-               volume=127;
-               midi_synth_aftertouch
-                       (wavefront_configuration.mididev,
-                        channel,0);
-       };
-
-       midi_synth_start_note (wavefront_configuration.mididev,
-                              channel, note, volume);
-       return(0);
-};
+    (void) install_wavefront ();
+}
 
-static void wavefront_setup_voice (int dev, int voice, int chn)
-{
-};
+int probe_wavefront (struct address_info *hw_config)
 
-static void wavefront_reset (int dev)
 {
-       int i;
-
-       for (i = 0; i < 16; i++) {
-               midi_synth_kill_note (dev,i,0,0);
-       };
-};
+    return !detect_wavefront (hw_config->irq, hw_config->io_base);
+}
 
-static struct synth_operations wavefront_operations =
+void unload_wavefront (struct address_info *hw_config) 
 {
-       "WaveFront",
-       &wavefront_info,
-       0,
-       SYNTH_TYPE_SAMPLE,
-       SAMPLE_TYPE_WAVEFRONT,
-       wavefront_open,
-       wavefront_close,
-       wavefront_ioctl,
-       wavefront_kill_note,
-       wavefront_start_note,
-       wavefront_set_instr,
-       wavefront_reset,
-       NULL,
-       wavefront_load_patch,
-       wavefront_aftertouch,
-       wavefront_controller,
-       wavefront_panning,
-       NULL,
-       wavefront_bender,
-       NULL,
-       wavefront_setup_voice
-};
+    (void) uninstall_wavefront ();
+}
 
+#endif OSS_SUPPORT_STATIC_INSTALL
 \f
-/***********************************************************************
-WaveFront: OSS/Free and/or Linux kernel installation interface
-***********************************************************************/
+/***********************************************************************/
+/* WaveFront: Linux modular sound kernel installation interface        */
+/***********************************************************************/
 
 void
 wavefrontintr (int irq, void *dev_id, struct pt_regs *dummy)
 {
-        /* We don't use this handler except during device
-          configuration. While the module is installed, the 
-          interrupt is used to signal MIDI interrupts, and is 
-          handled by the interrupt routine in wf_midi.c
-        */
-          
-       wf_config *hw = (wf_config *) dev_id;
-       hw->irq_ok = 1;
+       struct wf_config *hw = dev_id;
+
+       /*
+          Some comments on interrupts. I attempted a version of this
+          driver that used interrupts throughout the code instead of
+          doing busy and/or sleep-waiting. Alas, it appears that once
+          the Motorola firmware is downloaded, the card *never*
+          generates an RX interrupt. These are successfully generated
+          during firmware loading, and after that wavefront_status()
+          reports that an interrupt is pending on the card from time
+          to time, but it never seems to be delivered to this
+          driver. Note also that wavefront_status() continues to
+          report that RX interrupts are enabled, suggesting that I
+          didn't goof up and disable them by mistake.
+
+          Thus, I stepped back to a prior version of
+          wavefront_wait(), the only place where this really
+          matters. Its sad, but I've looked through the code to check
+          on things, and I really feel certain that the Motorola
+          firmware prevents RX-ready interrupts.
+       */
 
-       if ((wavefront_status(hw) & STAT_INTR_WRITE) ||
-           (wavefront_status(hw) & STAT_INTR_READ)) {
-               wake_up (&hw->interrupt_sleeper);
+       if ((wavefront_status() & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) {
+               return;
        }
+
+       hw->irq_ok = 1;
+       hw->irq_cnt++;
+       wake_up_interruptible (&hw->interrupt_sleeper);
 }
 
 /* STATUS REGISTER 
@@ -2202,16 +2205,6 @@ wavefrontintr (int irq, void *dev_id, struct pt_regs *dummy)
 5 Host Tx Register empty (1=Empty)
 6 Host Tx Interrupt Pending (1=Interrupt)
 7 Unused
-
-11111001 
-  Rx Intr enable
-  nothing to read from board
-  no rx interrupt pending
-  unused
-  tx interrupt enabled
-  space to transmit
-  tx interrupt pending
-
 */
 
 int
@@ -2235,7 +2228,7 @@ wavefront_interrupt_bits (int irq)
                break;
        
        default:
-               printk (KERN_WARNING "WaveFront: invalid IRQ %d\n", irq);
+               printk (KERN_WARNING LOGNAME "invalid IRQ %d\n", irq);
                bits = -1;
        }
 
@@ -2243,42 +2236,78 @@ wavefront_interrupt_bits (int irq)
 }
 
 void
-wavefront_should_cause_interrupt (wf_config *hw, int val, int port, int timeout)
+wavefront_should_cause_interrupt (int val, int port, int timeout)
 
 {
        unsigned long flags;
 
        save_flags (flags);
        cli();
-       hw->irq_ok = 0;
+       dev.irq_ok = 0;
        outb (val,port);
-       interruptible_sleep_on_timeout(&hw->interrupt_sleeper, timeout);
+       interruptible_sleep_on_timeout (&dev.interrupt_sleeper, timeout);
        restore_flags (flags);
 }
 
 static int
-wavefront_hw_reset (wf_config *hw)
+wavefront_hw_reset (void)
 
 {
        int bits;
        int hwv[2];
+       unsigned long irq_mask;
+       short reported_irq;
+
+       /* IRQ already checked in init_module() */
+
+       bits = wavefront_interrupt_bits (dev.irq);
+
+       printk (KERN_DEBUG LOGNAME "autodetecting WaveFront IRQ\n");
+
+       sti ();
 
-       /* Check IRQ is legal */
+       irq_mask = probe_irq_on ();
 
-       if ((bits = wavefront_interrupt_bits (hw->irq)) < 0) {
+       outb (0x0, dev.control_port); 
+       outb (0x80 | 0x40 | bits, dev.data_port);       
+       wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,
+                                        dev.control_port,
+                                        (reset_time*HZ)/100);
+
+       reported_irq = probe_irq_off (irq_mask);
+
+       if (reported_irq != dev.irq) {
+               if (reported_irq == 0) {
+                       printk (KERN_ERR LOGNAME
+                               "No unassigned interrupts detected "
+                               "after h/w reset\n");
+               } else if (reported_irq < 0) {
+                       printk (KERN_ERR LOGNAME
+                               "Multiple unassigned interrupts detected "
+                               "after h/w reset\n");
+               } else {
+                       printk (KERN_ERR LOGNAME "autodetected IRQ %d not the "
+                               "value provided (%d)\n", reported_irq,
+                               dev.irq);
+               }
+               dev.irq = -1;
                return 1;
+       } else {
+               printk (KERN_INFO LOGNAME "autodetected IRQ at %d\n",
+                       reported_irq);
        }
 
-       if (request_irq (hw->irq, wavefrontintr,
-                        0, "WaveFront", (void *) hw) < 0) {
-               printk (KERN_WARNING "WaveFront: IRQ %d not available!\n",
-                       hw->irq);
+       if (request_irq (dev.irq, wavefrontintr,
+                        SA_INTERRUPT|SA_SHIRQ,
+                        "wavefront synth", &dev) < 0) {
+               printk (KERN_WARNING LOGNAME "IRQ %d not available!\n",
+                       dev.irq);
                return 1;
        }
 
        /* try reset of port */
       
-       outb (0x0, hw->control_port); 
+       outb (0x0, dev.control_port); 
   
        /* At this point, the board is in reset, and the H/W initialization
           register is accessed at the same address as the data port.
@@ -2291,8 +2320,8 @@ wavefront_hw_reset (wf_config *hw)
 
           0 - Use the MIDI Input from the 26-pin WaveBlaster
           compatible header as the serial MIDI source
-          1 - Use the MIDI Input from the 9-pin D connector as the serial MIDI 
-          source.
+          1 - Use the MIDI Input from the 9-pin D connector as the
+          serial MIDI source.
      
           Bits 5:3 - IRQ Selection
           0 0 0 - IRQ 2/9
@@ -2316,7 +2345,7 @@ wavefront_hw_reset (wf_config *hw)
           plus external 9-pin MIDI interface selected
        */
 
-       outb (0x80 | 0x40 | bits, hw->data_port);       
+       outb (0x80 | 0x40 | bits, dev.data_port);       
   
        /* CONTROL REGISTER
 
@@ -2329,85 +2358,28 @@ wavefront_hw_reset (wf_config *hw)
           6 Master Interrupt Enable (1=Enabled)      0x40
           7 Master Reset (0=Reset; 1=Run)            0x80
 
-          Take us out of reset, unmute, master + TX + RX interrupts on.
+          Take us out of reset, mute output, master + TX + RX interrupts on.
           
           We'll get an interrupt presumably to tell us that the TX
-          register is clear. However, this doesn't mean that the
-          board is ready. We actually have to send it a command, and
-          wait till it gets back to use. After a cold boot, this can
-          take some time.
-          
-          I think this is because its only after a cold boot that the
-          onboard ROM does its memory check, which can take "up to 4
-          seconds" according to the WaveFront SDK. So, since sleeping
-          doesn't cost us much, we'll give it *plenty* of time. It
-          turns out that with 12MB of RAM, it can take up to 16
-          seconds or so!! See the code after "ABOUT INTERRUPTS"
+          register is clear.
        */
 
-       wavefront_should_cause_interrupt(hw,
-                                        0x80|0x40|0x10|0x1,
-                                        hw->control_port,
-                                        (2*HZ)/100);
+       wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,
+                                        dev.control_port,
+                                        (reset_time*HZ)/100);
 
        /* Note: data port is now the data port, not the h/w initialization
           port.
         */
 
-       if (!hw->irq_ok) {
-               printk (KERN_WARNING
-                       "WaveFront: intr not received after h/w un-reset.\n");
+       if (!dev.irq_ok) {
+               printk (KERN_WARNING LOGNAME
+                       "intr not received after h/w un-reset.\n");
                goto gone_bad;
        } 
 
-       hw->interrupts_on = 1;
+       dev.interrupts_on = 1;
        
-       /* ABOUT INTERRUPTS:
-          -----------------
-          
-          When we talk about interrupts, there are two kinds
-          generated by the ICS2115. The first is to signal MPU data
-          ready to read, and the second is to signal RX or TX status
-          changes. We *always* want interrupts for MPU stuff but we 
-          generally avoid using RX/TX interrupts.
-
-          In theory, we could use the TX and RX interrupts for all
-          communication with the card. However, there are 2 good
-          reasons not to do this.
-
-          First of all, the MIDI interface is going to use the same
-          interrupt. This presents no practical problem since Linux
-          allows us to share IRQ's. However, there are times when it
-          makes sense for a user to ask the driver to disable
-          interrupts, to avoid bothering Linux with a stream of MIDI
-          interrupts that aren't going to be used because nothing
-          cares about them. If we rely on them for communication with
-          the WaveFront synth as well, this disabling would be
-          crippling. Since being able to disable them can save quite
-          a bit of overhead (consider the interrupt frequency of a
-          physical MIDI controller like a modwheel being shunted back
-          and forth - its higher than the mouse, and much of
-          the time is of absolutely no interest to the kernel or any
-          user space processes whatsoever), we don't want to do this.
-
-          Secondly, much of the time, there's no reason to go to
-          sleep on a TX or RX status: the WaveFront gets back to us
-          quickly enough that its a lot more efficient to just busy
-          wait on the relevant status. Once we go to sleep, all is
-          lost anyway, and so interrupts don't really help us much anyway.
-
-          Therefore, we don't use interrupts for communication with
-          the WaveFront synth. We just poll the relevant RX/TX status.
-
-          However, there is one broad exception to this. During module
-          loading, to deal with several situations where timing would
-          be an issue, we use TX/RX interrupts to help us avoid busy
-          waiting for indeterminate and hard to manage periods of
-          time. So, TX/RX interrupts are enabled until the end of 
-          wavefront_init(), and not used again after that.
-
-        */
-
        /* Note: data port is now the data port, not the h/w initialization
           port.
 
@@ -2421,27 +2393,27 @@ wavefront_hw_reset (wf_config *hw)
           subsequent ISC2115 reboots (say, caused by module
           reloading) will get through this much faster.
 
-          Interesting question: why is no RX interrupt received first ?
+          XXX Interesting question: why is no RX interrupt received first ?
        */
-       
-       wavefront_should_cause_interrupt(hw, WFC_HARDWARE_VERSION, 
-                                        hw->data_port, 20*HZ);
 
-       if (!hw->irq_ok) {
-               printk (KERN_WARNING
-                       "WaveFront: post-RAM-check interrupt not received.\n");
+       wavefront_should_cause_interrupt(WFC_HARDWARE_VERSION, 
+                                        dev.data_port, ramcheck_time*HZ);
+
+       if (!dev.irq_ok) {
+               printk (KERN_WARNING LOGNAME
+                       "post-RAM-check interrupt not received.\n");
                goto gone_bad;
        } 
 
-       if (!(wavefront_status(hw) & STAT_CAN_READ)) {
-               printk (KERN_WARNING
-                       "WaveFront: no response to HW version cmd.\n");
+       if (!wavefront_wait (STAT_CAN_READ)) {
+               printk (KERN_WARNING LOGNAME
+                       "no response to HW version cmd.\n");
                goto gone_bad;
        }
        
-       if ((hwv[0] = wavefront_read (hw)) == -1) {
-               printk (KERN_WARNING
-                       "WaveFront: board not responding correctly.\n");
+       if ((hwv[0] = wavefront_read ()) == -1) {
+               printk (KERN_WARNING LOGNAME
+                       "board not responding correctly.\n");
                goto gone_bad;
        }
 
@@ -2451,13 +2423,11 @@ wavefront_hw_reset (wf_config *hw)
                   and tell us about it either way.
                */
                
-               if ((hwv[0] = wavefront_read (hw)) == -1) {
-                       printk (KERN_WARNING 
-                               "WaveFront: on-board RAM test failed "
+               if ((hwv[0] = wavefront_read ()) == -1) {
+                       printk (KERN_WARNING LOGNAME "on-board RAM test failed "
                                "(bad error code).\n");
                } else {
-                       printk (KERN_WARNING 
-                               "WaveFront: on-board RAM test failed "
+                       printk (KERN_WARNING LOGNAME "on-board RAM test failed "
                                "(error code: 0x%x).\n",
                                hwv[0]);
                }
@@ -2466,85 +2436,66 @@ wavefront_hw_reset (wf_config *hw)
 
        /* We're OK, just get the next byte of the HW version response */
 
-       if ((hwv[1] = wavefront_read (hw)) == -1) {
-               printk (KERN_WARNING
-                       "WaveFront: board not responding correctly(2).\n");
+       if ((hwv[1] = wavefront_read ()) == -1) {
+               printk (KERN_WARNING LOGNAME "incorrect h/w response.\n");
                goto gone_bad;
        }
 
-       printk (KERN_INFO "WaveFront: hardware version %d.%d\n",
+       printk (KERN_INFO LOGNAME "hardware version %d.%d\n",
                hwv[0], hwv[1]);
 
        return 0;
 
 
      gone_bad:
-       free_irq (hw->irq, hw);
-       return (1);
+       if (dev.irq >= 0) {
+               free_irq (dev.irq, &dev);
+               dev.irq = -1;
        }
+       return (1);
+}
 
-int
-probe_wavefront (struct address_info *hw_config)
+__initfunc (static int detect_wavefront (int irq, int io_base))
 
 {
        unsigned char   rbuf[4], wbuf[4];
-       wf_config       *hw;
 
-       if (hw_config->irq < 0 || hw_config->irq > 16) {
-           printk (KERN_WARNING "WaveFront: impossible IRQ suggested(%d)\n", 
-                   hw_config->irq);
-           return 0;
-       }
-  
-       /* Yeah yeah, TB docs say 8, but the FX device on the Tropez Plus
-          takes up another 8 ...
+       /* TB docs say the device takes up 8 ports, but we know that
+          if there is an FX device present (i.e. a Tropez+) it really
+          consumes 16.
        */
 
-       if (check_region (hw_config->io_base, 16)) {
-               printk (KERN_ERR "WaveFront: IO address range 0x%x - 0x%x "
-                       "already in use - ignored\n", hw_config->io_base,
-                       hw_config->io_base+15);
-               return 0;
+       if (check_region (io_base, 16)) {
+               printk (KERN_ERR LOGNAME "IO address range 0x%x - 0x%x "
+                       "already in use - ignored\n", dev.base,
+                       dev.base+15);
+               return -1;
        }
   
-       hw = &wavefront_configuration;
-
-       hw->irq = hw_config->irq;
-       hw->base = hw_config->io_base;
-
-       hw->israw = 0;
-       hw->debug = debug_default;
-       hw->interrupts_on = 0;
-       hw->rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */
-
-#ifdef WF_STATS
-       hw->status_found_during_sleep[0] = 0;
-       hw->status_found_during_sleep[1] = 0;
-       hw->status_found_during_sleep[2] = 0;
-       hw->status_found_during_sleep[3] = 0;
-       hw->status_found_during_loop = 0;
-#endif WF_STATS
-
-       hw_config->slots[WF_SYNTH_SLOT] = hw->synthdev = -1;
-       hw_config->slots[WF_INTERNAL_MIDI_SLOT] = hw->mididev = -1;
-       hw_config->slots[WF_EXTERNAL_MIDI_SLOT] = hw->ext_mididev = -1;
-
-       if (wavefront_cmd (hw, WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) {
-
-               hw->fw_version[0] = rbuf[0];
-               hw->fw_version[1] = rbuf[1];
-               printk (KERN_INFO
-                       "WaveFront: firmware %d.%d already loaded.\n",
+       dev.irq = irq;
+       dev.base = io_base;
+       dev.israw = 0;
+       dev.debug = debug_default;
+       dev.interrupts_on = 0;
+       dev.irq_cnt = 0;
+       dev.rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */
+
+       if (wavefront_cmd (WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) {
+
+               dev.fw_version[0] = rbuf[0];
+               dev.fw_version[1] = rbuf[1];
+               printk (KERN_INFO LOGNAME
+                       "firmware %d.%d already loaded.\n",
                        rbuf[0], rbuf[1]);
 
                /* check that a command actually works */
       
-               if (wavefront_cmd (hw, WFC_HARDWARE_VERSION,
+               if (wavefront_cmd (WFC_HARDWARE_VERSION,
                                   rbuf, wbuf) == 0) {
-                       hw->hw_version[0] = rbuf[0];
-                       hw->hw_version[1] = rbuf[1];
+                       dev.hw_version[0] = rbuf[0];
+                       dev.hw_version[1] = rbuf[1];
                } else {
-                       printk (KERN_INFO "WaveFront: not raw, but no "
+                       printk (KERN_WARNING LOGNAME "not raw, but no "
                                "hardware version!\n");
                        return 0;
                }
@@ -2552,25 +2503,30 @@ probe_wavefront (struct address_info *hw_config)
                if (!wf_raw) {
                        return 1;
                } else {
-                       printk (KERN_INFO
-                               "WaveFront: reloading firmware anyway.\n");
+                       printk (KERN_INFO LOGNAME
+                               "reloading firmware anyway.\n");
+                       dev.israw = 1;
                }
 
        } else {
 
-               hw->israw = 1;
-               printk (KERN_INFO "WaveFront: no response to firmware probe, "
-                       "assume raw.\n");
+               dev.israw = 1;
+               printk (KERN_INFO LOGNAME
+                       "no response to firmware probe, assume raw.\n");
 
        }
 
-       init_waitqueue (&hw->interrupt_sleeper);
+       init_waitqueue (&dev.interrupt_sleeper);
 
-       if (wavefront_hw_reset (hw)) {
-               printk (KERN_WARNING "WaveFront: hardware reset failed\n");
+       if (wavefront_hw_reset ()) {
+               printk (KERN_WARNING LOGNAME "hardware reset failed\n");
                return 0;
        }
 
+       /* Check for FX device, present only on Tropez+ */
+
+       dev.has_fx = (detect_wffx () == 0);
+
        return 1;
 }
 
@@ -2585,7 +2541,7 @@ probe_wavefront (struct address_info *hw_config)
 static int errno; 
 
 static int
-wavefront_download_firmware (wf_config *hw, char *path)
+wavefront_download_firmware (char *path)
 
 {
        unsigned char section[WF_SECTION_MAX];
@@ -2610,7 +2566,7 @@ wavefront_download_firmware (wf_config *hw, char *path)
        set_fs (get_ds());
 
        if ((fd = open (path, 0, 0)) < 0) {
-               printk (KERN_WARNING "WaveFront: Unable to load \"%s\".\n",
+               printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n",
                        path);
                return 1;
        }
@@ -2620,7 +2576,7 @@ wavefront_download_firmware (wf_config *hw, char *path)
 
                if ((x = read (fd, &section_length, sizeof (section_length))) !=
                    sizeof (section_length)) {
-                       printk (KERN_ERR "WaveFront: firmware read error.\n");
+                       printk (KERN_ERR LOGNAME "firmware read error.\n");
                        goto failure;
                }
 
@@ -2629,58 +2585,46 @@ wavefront_download_firmware (wf_config *hw, char *path)
                }
 
                if (read (fd, section, section_length) != section_length) {
-                       printk (KERN_ERR "WaveFront: firmware section "
+                       printk (KERN_ERR LOGNAME "firmware section "
                                "read error.\n");
                        goto failure;
                }
 
                /* Send command */
        
-               if (!wavefront_write (hw, WFC_DOWNLOAD_OS)) {
+               if (wavefront_write (WFC_DOWNLOAD_OS)) {
                        goto failure;
                }
        
                for (i = 0; i < section_length; i++) {
-                       if (!wavefront_write (hw, section[i])) {
+                       if (wavefront_write (section[i])) {
                                goto failure;
                        }
                }
        
                /* get ACK */
        
-               if (wavefront_wait (hw, STAT_CAN_READ)) {
+               if (wavefront_wait (STAT_CAN_READ)) {
 
-                       if ((c = inb (hw->data_port)) != WF_ACK) {
+                       if ((c = inb (dev.data_port)) != WF_ACK) {
 
-                               printk (KERN_ERR "WaveFront: download "
+                               printk (KERN_ERR LOGNAME "download "
                                        "of section #%d not "
                                        "acknowledged, ack = 0x%x\n",
                                        section_cnt_downloaded + 1, c);
                                goto failure;
                
-                       } else {
-#ifdef WF_DEBUG
-                           if ((hw->debug & WF_DEBUG_IO) &&
-                                  !(++section_cnt_downloaded % 10)) {
-                               printk (KERN_DEBUG ".");
-                           }
-#endif WF_DEBUG
                        }
 
                } else {
-                       printk (KERN_ERR "WaveFront: timed out "
-                               "for download ACK.\n");
+                       printk (KERN_ERR LOGNAME "time out for firmware ACK.\n");
+                       goto failure;
                }
 
        }
 
        close (fd);
        set_fs (fs);
-#ifdef WF_DEBUG
-       if (hw->debug & WF_DEBUG_IO) {
-               printk (KERN_DEBUG "\n");
-       }
-#endif WF_DEBUG
        return 0;
 
  failure:
@@ -2690,38 +2634,33 @@ wavefront_download_firmware (wf_config *hw, char *path)
        return 1;
 }
 
-static int
-wavefront_config_midi (wf_config *hw, struct address_info *hw_config)
+__initfunc (static int wavefront_config_midi (void)) 
 
 {
        unsigned char rbuf[4], wbuf[4];
     
-       if (!probe_wf_mpu (hw_config)) {
-               printk (KERN_WARNING "WaveFront: could not install "
-                       "MPU-401 device.\n");
-               return 1;
+       if (detect_wf_mpu (dev.irq, dev.base) < 0) {
+               printk (KERN_WARNING LOGNAME
+                       "could not find working MIDI device\n");
+               return -1;
        } 
 
-       /* Attach an modified MPU-401 driver to the master MIDI interface */
-
-       hw_config->name = "WaveFront Internal MIDI";
-       attach_wf_mpu (hw_config);
-
-       if (hw_config->slots[WF_INTERNAL_MIDI_SLOT] == -1) {
-               printk (KERN_WARNING "WaveFront: MPU-401 not configured.\n");
-               return 1;
+       if ((dev.mididev = install_wf_mpu ()) < 0) {
+               printk (KERN_WARNING LOGNAME
+                       "MIDI interfaces not configured\n");
+               return -1;
        }
 
-       hw->mididev = hw_config->slots[WF_INTERNAL_MIDI_SLOT];
-
        /* Route external MIDI to WaveFront synth (by default) */
     
-       if (wavefront_cmd (hw, WFC_MISYNTH_ON, rbuf, wbuf)) {
-               printk (KERN_WARNING
-                       "WaveFront: cannot enable MIDI-IN to synth routing.\n");
+       if (wavefront_cmd (WFC_MISYNTH_ON, rbuf, wbuf)) {
+               printk (KERN_WARNING LOGNAME
+                       "cannot enable MIDI-IN to synth routing.\n");
                /* XXX error ? */
        }
 
+
+#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
        /* Get the regular MIDI patch loading function, so we can
           use it if we ever get handed a SYSEX patch. This is
           unlikely, because its so damn slow, but we may as well
@@ -2730,12 +2669,14 @@ wavefront_config_midi (wf_config *hw, struct address_info *hw_config)
           only use MIDI to do patch loading.
        */
 
-       if (midi_devs[hw->mididev]->converter != NULL) {
-               midi_load_patch = midi_devs[hw->mididev]->converter->load_patch;
-               midi_devs[hw->mididev]->converter->load_patch =
-                   &wavefront_load_patch;
+       if (midi_devs[dev.mididev]->converter != NULL) {
+               midi_load_patch = midi_devs[dev.mididev]->converter->load_patch;
+               midi_devs[dev.mididev]->converter->load_patch =
+                   &wavefront_oss_load_patch;
        }
 
+#endif OSS_SUPPORT_SEQ
+       
        /* Turn on Virtual MIDI, but first *always* turn it off,
           since otherwise consectutive reloads of the driver will
           never cause the hardware to generate the initial "internal" or 
@@ -2747,22 +2688,19 @@ wavefront_config_midi (wf_config *hw, struct address_info *hw_config)
           the internal interface. Duh.
        */
 
-       if (wavefront_cmd (hw, WFC_VMIDI_OFF, rbuf, wbuf)) { 
-               printk (KERN_WARNING "WaveFront: cannot disable "
-                       "virtual MIDI mode\n");
-               /* XXX go ahead and try anyway ? */
+       if (wavefront_cmd (WFC_VMIDI_OFF, rbuf, wbuf)) { 
+               printk (KERN_WARNING LOGNAME
+                       "virtual MIDI mode not disabled\n");
+               return 0; /* We're OK, but missing the external MIDI dev */
        }
 
-       hw_config->name = "WaveFront External MIDI";
-    
-       if (virtual_midi_enable (hw->mididev, hw_config)) {
-               printk (KERN_WARNING "WaveFront: no virtual MIDI access.\n");
+       if ((dev.ext_mididev = virtual_midi_enable ()) < 0) {
+               printk (KERN_WARNING LOGNAME "no virtual MIDI access.\n");
        } else {
-               hw->ext_mididev = hw_config->slots[WF_EXTERNAL_MIDI_SLOT];
-               if (wavefront_cmd (hw, WFC_VMIDI_ON, rbuf, wbuf)) {
-                       printk (KERN_WARNING
-                               "WaveFront: cannot enable virtual MIDI mode.\n");
-                       virtual_midi_disable (hw->mididev);
+               if (wavefront_cmd (WFC_VMIDI_ON, rbuf, wbuf)) {
+                       printk (KERN_WARNING LOGNAME
+                               "cannot enable virtual MIDI mode.\n");
+                       virtual_midi_disable ();
                } 
        }
     
@@ -2770,62 +2708,66 @@ wavefront_config_midi (wf_config *hw, struct address_info *hw_config)
 }
 
 static int
-wavefront_do_reset (wf_config *hw, int atboot)
+wavefront_do_reset (int atboot)
 
 {
        char voices[1];
 
-       if (!atboot && wavefront_hw_reset (hw)) {
-               printk (KERN_WARNING "WaveFront: hw reset failed.\n");
+       if (!atboot && wavefront_hw_reset ()) {
+               printk (KERN_WARNING LOGNAME "hw reset failed.\n");
                goto gone_bad;
        }
 
-       if (hw->israw || wf_raw) {
-               if (wavefront_download_firmware (hw, ospath)) {
+       if (dev.israw) {
+               if (wavefront_download_firmware (ospath)) {
                        goto gone_bad;
                }
 
+               dev.israw = 0;
+
                /* Wait for the OS to get running. The protocol for
                   this is non-obvious, and was determined by
                   using port-IO tracing in DOSemu and some
                   experimentation here.
                   
-                  Rather than busy-wait, use interrupts creatively.
+                  Rather than using timed waits, use interrupts creatively.
                */
 
-               wavefront_should_cause_interrupt (hw, WFC_NOOP,
-                                         hw->data_port, (10*HZ));
-               
-               if (!hw->irq_ok) {
-                       printk (KERN_WARNING
-                               "WaveFront: no post-OS interrupt.\n");
+               wavefront_should_cause_interrupt (WFC_NOOP,
+                                                 dev.data_port,
+                                                 (osrun_time*HZ));
+
+               if (!dev.irq_ok) {
+                       printk (KERN_WARNING LOGNAME
+                               "no post-OS interrupt.\n");
                        goto gone_bad;
                }
                
                /* Now, do it again ! */
                
-               wavefront_should_cause_interrupt (hw, WFC_NOOP,
-                                                 hw->data_port, (10*HZ));
+               wavefront_should_cause_interrupt (WFC_NOOP,
+                                                 dev.data_port, (10*HZ));
                
-               if (!hw->irq_ok) {
-                       printk (KERN_WARNING
-                               "WaveFront: no post-OS interrupt(2).\n");
+               if (!dev.irq_ok) {
+                       printk (KERN_WARNING LOGNAME
+                               "no post-OS interrupt(2).\n");
                        goto gone_bad;
                }
 
                /* OK, no (RX/TX) interrupts any more, but leave mute
-                  on. Master interrupts get enabled when we're done here.
+                  in effect. 
                */
                
-               outb (0x80, hw->control_port); 
-               
+               outb (0x80|0x40, dev.control_port); 
+
                /* No need for the IRQ anymore */
                
-               free_irq (hw->irq, hw);
+               free_irq (dev.irq, &dev);
+
        }
 
-       if (/*XXX has_fx_device() && */ fx_raw) {
-               wffx_init (hw);
+       if (dev.has_fx && fx_raw) {
+               wffx_init ();
        }
 
        /* SETUPSND.EXE asks for sample memory config here, but since i
@@ -2833,118 +2775,130 @@ wavefront_do_reset (wf_config *hw, int atboot)
           about it.
        */
        
-       if ((hw->freemem = wavefront_freemem (hw)) < 0) {
+       if ((dev.freemem = wavefront_freemem ()) < 0) {
                goto gone_bad;
        }
                
-       printk (KERN_INFO "WaveFront: available DRAM %dk\n", hw->freemem / 1024);
+       printk (KERN_INFO LOGNAME "available DRAM %dk\n", dev.freemem / 1024);
 
-       if (!wavefront_write (hw, 0xf0) ||
-           !wavefront_write (hw, 1) ||
-           (wavefront_read (hw) < 0)) {
-               hw->debug = 0;
-               printk (KERN_WARNING "WaveFront: MPU emulation mode not set.\n");
+       if (wavefront_write (0xf0) ||
+           wavefront_write (1) ||
+           (wavefront_read () < 0)) {
+               dev.debug = 0;
+               printk (KERN_WARNING LOGNAME "MPU emulation mode not set.\n");
                goto gone_bad;
        }
 
        voices[0] = 32;
 
-       if (wavefront_cmd (hw, WFC_SET_NVOICES, 0, voices)) {
-               printk (KERN_WARNING
-                       "WaveFront: cannot set number of voices to 32.\n");
+       if (wavefront_cmd (WFC_SET_NVOICES, 0, voices)) {
+               printk (KERN_WARNING LOGNAME
+                       "cannot set number of voices to 32.\n");
+               goto gone_bad;
        }
 
+
        return 0;
 
  gone_bad:
        /* reset that sucker so that it doesn't bother us. */
 
-       outb (0x0, hw->control_port);
-       free_irq (hw->irq, hw);
+       outb (0x0, dev.control_port);
+       dev.interrupts_on = 0;
+       if (dev.irq >= 0) {
+               free_irq (dev.irq, &dev);
+       }
        return 1;
 }
 
 static int
-wavefront_init (wf_config *hw, int atboot)
+wavefront_init (int atboot)
 
 {
        int samples_are_from_rom;
 
-       if (hw->israw || wf_raw) {
+       if (dev.israw) {
                samples_are_from_rom = 1;
        } else {
+               /* XXX is this always true ? */
                samples_are_from_rom = 0;
        }
 
-       if (hw->israw || wf_raw || fx_raw) {
-               if (wavefront_do_reset (hw, atboot)) {
-                       return 1;
+       if (dev.israw || fx_raw) {
+               if (wavefront_do_reset (atboot)) {
+                       return -1;
                }
        }
 
-       wavefront_get_sample_status (hw, samples_are_from_rom);
-       wavefront_get_program_status (hw);
-       wavefront_get_patch_status (hw);
+       wavefront_get_sample_status (samples_are_from_rom);
+       wavefront_get_program_status ();
+       wavefront_get_patch_status ();
 
-       /* Start normal operation: unreset, master interrupt enable
-          (for MPU interrupts) no mute
+       /* Start normal operation: unreset, master interrupt enabled, no mute
        */
 
-       outb (0x80|0x40|0x20, hw->control_port); 
+       outb (0x80|0x40|0x20, dev.control_port); 
 
        return (0);
 }
 
-void
-attach_wavefront (struct address_info *hw_config)
+__initfunc (static int install_wavefront (void))
+
 {
-       int i;
-       struct wf_config *hw = &wavefront_configuration;
+       if ((dev.synth_dev = register_sound_synth (&wavefront_fops, -1)) < 0) {
+               printk (KERN_ERR LOGNAME "cannot register raw synth\n");
+               return -1;
+       }
 
-       if ((i = sound_alloc_synthdev()) == -1) {
-               printk (KERN_ERR "WaveFront: Too many synthesizers\n");
-               return;
+#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+       if ((dev.oss_dev = sound_alloc_synthdev()) == -1) {
+               printk (KERN_ERR LOGNAME "Too many sequencers\n");
+               return -1;
        } else {
-               hw_config->slots[WF_SYNTH_SLOT] = i;
-               hw->synthdev = i;
-               synth_devs[hw->synthdev] = &wavefront_operations;
+               synth_devs[dev.oss_dev] = &wavefront_operations;
        }
+#endif OSS_SUPPORT_SEQ
 
-       if (wavefront_init (hw, 1)) {
-               printk (KERN_WARNING "WaveFront: board could not "
-                       "be initialized.\n");
-               sound_unload_synthdev (i);
-               return;
+       if (wavefront_init (1) < 0) {
+               printk (KERN_WARNING LOGNAME "initialization failed.\n");
+
+#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+               sound_unload_synthdev (dev.oss_dev);
+#endif OSS_SUPPORT_SEQ
+
+               return -1;
        }
     
-       request_region (hw_config->io_base+2, 6, "WaveFront synth");
-       request_region (hw_config->io_base+8, 8, "WaveFront FX");
+       request_region (dev.base+2, 6, "wavefront synth");
 
-       conf_printf2 ("WaveFront Synth", hw_config->io_base, 0, -1, -1);
+       if (dev.has_fx) {
+               request_region (dev.base+8, 8, "wavefront fx");
+       }
 
-#if defined(CONFIG_MIDI)    
-       if (wavefront_config_midi (hw, hw_config)) {
-               printk (KERN_WARNING "WaveFront: could not initialize MIDI.\n");
+       if (wavefront_config_midi ()) {
+               printk (KERN_WARNING LOGNAME "could not initialize MIDI.\n");
        }
-#else
-       printk (KERN_WARNING
-               "WaveFront: MIDI not configured at kernel-config time.\n");
-#endif CONFIG_MIDI
 
-       return;
+       return dev.oss_dev;
 }
+
 void
-unload_wavefront (struct address_info *hw_config)
+uninstall_wavefront (void)
+
 {
-       struct wf_config *hw = &wavefront_configuration;
-
-       /* the first two are freed by the wf_mpu code */
-       release_region (hw->base+2, 6);
-       release_region (hw->base+8, 8);
-       sound_unload_synthdev (hw->synthdev);
-#if defined(CONFIG_MIDI)
-       unload_wf_mpu (hw_config);
-#endif
+       /* the first two i/o addresses are freed by the wf_mpu code */
+       release_region (dev.base+2, 6);
+
+       if (dev.has_fx) {
+               release_region (dev.base+8, 8);
+       }
+
+       unregister_sound_synth (dev.synth_dev);
+
+#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
+       sound_unload_synthdev (dev.oss_dev);
+#endif OSS_SUPPORT_SEQ
+       uninstall_wf_mpu ();
 }
 \f
 /***********************************************************************/
@@ -2961,83 +2915,111 @@ unload_wavefront (struct address_info *hw_config)
 #define FX_AUTO_INCR    0x04    /* auto-increment DSP address after transfer */
 
 static int
-wffx_idle (struct wf_config *hw
+wffx_idle (void
     
 {
        int i;
        unsigned int x = 0x80;
     
        for (i = 0; i < 1000; i++) {
-               x = inb (hw->fx_status);
+               x = inb (dev.fx_status);
                if ((x & 0x80) == 0) {
                        break;
                }
        }
     
        if (x & 0x80) {
-               printk (KERN_ERR "WaveFront: FX device never idle.\n");
+               printk (KERN_ERR LOGNAME "FX device never idle.\n");
                return 0;
        }
     
        return (1);
 }
 
+__initfunc (static int detect_wffx (void))
+
+{
+       /* This is a crude check, but its the best one I have for now.
+          Certainly on the Maui and the Tropez, wffx_idle() will
+          report "never idle", which suggests that this test should
+          work OK.
+       */
+
+       if (inb (dev.fx_status) & 0x80) {
+               printk (KERN_INFO LOGNAME "Hmm, probably a Maui or Tropez.\n");
+               return -1;
+       }
+
+       return 0;
+}      
+
+__initfunc (static int attach_wffx (void))
+
+{
+       if ((dev.fx_mididev = sound_alloc_mididev ()) < 0) {
+               printk (KERN_WARNING LOGNAME "cannot install FX Midi driver\n");
+               return -1;
+       }
+
+       return 0;
+}
+
 static void
-wffx_mute (struct wf_config *hw, int onoff)
+wffx_mute (int onoff)
     
 {
-       if (!wffx_idle(hw)) {
+       if (!wffx_idle()) {
                return;
        }
     
-       outb (onoff ? 0x02 : 0x00, hw->fx_op);
+       outb (onoff ? 0x02 : 0x00, dev.fx_op);
 }
 
 static int
-wffx_memset (struct wf_config *hw, int page,
+wffx_memset (int page,
             int addr, int cnt, unsigned short *data)
 {
        if (page < 0 || page > 7) {
-               printk (KERN_ERR "WaveFront: FX memset: "
+               printk (KERN_ERR LOGNAME "FX memset: "
                        "page must be >= 0 and <= 7\n");
                return -(EINVAL);
        }
 
        if (addr < 0 || addr > 0x7f) {
-               printk (KERN_ERR "WaveFront: FX memset: "
+               printk (KERN_ERR LOGNAME "FX memset: "
                        "addr must be >= 0 and <= 7f\n");
                return -(EINVAL);
        }
 
        if (cnt == 1) {
 
-               outb (FX_LSB_TRANSFER, hw->fx_lcr);
-               outb (page, hw->fx_dsp_page);
-               outb (addr, hw->fx_dsp_addr);
-               outb ((data[0] >> 8), hw->fx_dsp_msb);
-               outb ((data[0] & 0xff), hw->fx_dsp_lsb);
+               outb (FX_LSB_TRANSFER, dev.fx_lcr);
+               outb (page, dev.fx_dsp_page);
+               outb (addr, dev.fx_dsp_addr);
+               outb ((data[0] >> 8), dev.fx_dsp_msb);
+               outb ((data[0] & 0xff), dev.fx_dsp_lsb);
 
-               printk (KERN_INFO "WaveFront: FX: addr %d:%x set to 0x%x\n",
+               printk (KERN_INFO LOGNAME "FX: addr %d:%x set to 0x%x\n",
                        page, addr, data[0]);
        
        } else {
                int i;
 
-               outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-               outb (page, hw->fx_dsp_page);
-               outb (addr, hw->fx_dsp_addr);
+               outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+               outb (page, dev.fx_dsp_page);
+               outb (addr, dev.fx_dsp_addr);
 
                for (i = 0; i < cnt; i++) {
-                       outb ((data[i] >> 8), hw->fx_dsp_msb);
-                       outb ((data[i] & 0xff), hw->fx_dsp_lsb);
-                       if (!wffx_idle (hw)) {
+                       outb ((data[i] >> 8), dev.fx_dsp_msb);
+                       outb ((data[i] & 0xff), dev.fx_dsp_lsb);
+                       if (!wffx_idle ()) {
                                break;
                        }
                }
 
                if (i != cnt) {
-                       printk (KERN_WARNING
-                               "WaveFront: FX memset "
+                       printk (KERN_WARNING LOGNAME
+                               "FX memset "
                                "(0x%x, 0x%x, 0x%x, %d) incomplete\n",
                                page, addr, (int) data, cnt);
                        return -(EIO);
@@ -3048,7 +3030,7 @@ wffx_memset (struct wf_config *hw, int page,
 }
 
 static int
-wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r)
+wffx_ioctl (wavefront_fx_info *r)
 
 {
        unsigned short page_data[256];
@@ -3056,20 +3038,20 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r)
 
        switch (r->request) {
        case WFFX_MUTE:
-               wffx_mute (hw, r->data[0]);
+               wffx_mute (r->data[0]);
                return 0;
 
        case WFFX_MEMSET:
 
                if (r->data[2] <= 0) {
-                       printk (KERN_ERR "WaveFront: cannot write "
+                       printk (KERN_ERR LOGNAME "cannot write "
                                "<= 0 bytes to FX\n");
                        return -(EINVAL);
                } else if (r->data[2] == 1) {
                        pd = (unsigned short *) &r->data[3];
                } else {
                        if (r->data[2] > sizeof (page_data)) {
-                               printk (KERN_ERR "WaveFront: cannot write "
+                               printk (KERN_ERR LOGNAME "cannot write "
                                        "> 255 bytes to FX\n");
                                return -(EINVAL);
                        }
@@ -3078,15 +3060,14 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r)
                        pd = page_data;
                }
 
-               return wffx_memset (hw,
-                                   r->data[0], /* page */
+               return wffx_memset (r->data[0], /* page */
                                    r->data[1], /* addr */
                                    r->data[2], /* cnt */
                                    pd);
 
        default:
-               printk (KERN_WARNING
-                       "WaveFront: FX: ioctl %d not yet supported\n",
+               printk (KERN_WARNING LOGNAME
+                       "FX: ioctl %d not yet supported\n",
                        r->request);
                return -(EINVAL);
        }
@@ -3107,7 +3088,7 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r)
 */
 
 static int
-wffx_init (struct wf_config *hw)
+wffx_init (void)
 
 {
        int i;
@@ -3119,147 +3100,147 @@ wffx_init (struct wf_config *hw)
        for (j = 0; j < 2; j++) {
                for (i = 0x10; i <= 0xff; i++) {
            
-                       if (!wffx_idle (hw)) {
+                       if (!wffx_idle ()) {
                                return (-1);
                        }
            
-                       outb (i, hw->fx_mod_addr);
-                       outb (0x0, hw->fx_mod_data);
+                       outb (i, dev.fx_mod_addr);
+                       outb (0x0, dev.fx_mod_data);
                }
        }
 
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x02, hw->fx_op);                        /* mute on */
-
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x44, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x42, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x43, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x7c, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x7e, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x46, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x49, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x47, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x4a, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x02, dev.fx_op);                        /* mute on */
+
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x44, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x42, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x43, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x7c, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x7e, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x46, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x49, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x47, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x4a, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
 
        /* either because of stupidity by TB's programmers, or because it
           actually does something, rezero the MOD page.
        */
        for (i = 0x10; i <= 0xff; i++) {
        
-               if (!wffx_idle (hw)) {
+               if (!wffx_idle ()) {
                        return (-1);
                }
        
-               outb (i, hw->fx_mod_addr);
-               outb (0x0, hw->fx_mod_data);
+               outb (i, dev.fx_mod_addr);
+               outb (0x0, dev.fx_mod_data);
        }
        /* load page zero */
 
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x00, hw->fx_dsp_page);
-       outb (0x00, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x00, dev.fx_dsp_page);
+       outb (0x00, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_zero); i += 2) {
-               outb (page_zero[i], hw->fx_dsp_msb);
-               outb (page_zero[i+1], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_zero[i], dev.fx_dsp_msb);
+               outb (page_zero[i+1], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
 
        /* Now load page one */
 
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x01, hw->fx_dsp_page);
-       outb (0x00, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x01, dev.fx_dsp_page);
+       outb (0x00, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_one); i += 2) {
-               outb (page_one[i], hw->fx_dsp_msb);
-               outb (page_one[i+1], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_one[i], dev.fx_dsp_msb);
+               outb (page_one[i+1], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
     
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x02, hw->fx_dsp_page);
-       outb (0x00, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x02, dev.fx_dsp_page);
+       outb (0x00, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_two); i++) {
-               outb (page_two[i], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_two[i], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
     
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x03, hw->fx_dsp_page);
-       outb (0x00, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x03, dev.fx_dsp_page);
+       outb (0x00, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_three); i++) {
-               outb (page_three[i], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_three[i], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
     
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x04, hw->fx_dsp_page);
-       outb (0x00, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x04, dev.fx_dsp_page);
+       outb (0x00, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_four); i++) {
-               outb (page_four[i], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_four[i], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
 
        /* Load memory area (page six) */
     
-       outb (FX_LSB_TRANSFER, hw->fx_lcr); 
-       outb (0x06, hw->fx_dsp_page); 
+       outb (FX_LSB_TRANSFER, dev.fx_lcr); 
+       outb (0x06, dev.fx_dsp_page); 
 
        for (i = 0; i < sizeof (page_six); i += 3) {
-               outb (page_six[i], hw->fx_dsp_addr);
-               outb (page_six[i+1], hw->fx_dsp_msb);
-               outb (page_six[i+2], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_six[i], dev.fx_dsp_addr);
+               outb (page_six[i+1], dev.fx_dsp_msb);
+               outb (page_six[i+2], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
     
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x00, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x00, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_seven); i += 2) {
-               outb (page_seven[i], hw->fx_dsp_msb);
-               outb (page_seven[i+1], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_seven[i], dev.fx_dsp_msb);
+               outb (page_seven[i+1], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
 
        /* Now setup the MOD area. We do this algorithmically in order to
@@ -3268,192 +3249,192 @@ wffx_init (struct wf_config *hw)
        */
 
        for (i = 0x00; i <= 0x0f; i++) {
-               outb (0x01, hw->fx_mod_addr);
-               outb (i, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
-               outb (0x02, hw->fx_mod_addr);
-               outb (0x00, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (0x01, dev.fx_mod_addr);
+               outb (i, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
+               outb (0x02, dev.fx_mod_addr);
+               outb (0x00, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
        for (i = 0xb0; i <= 0xbf; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0x20, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0x20, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
        for (i = 0xf0; i <= 0xff; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0x20, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0x20, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
        for (i = 0x10; i <= 0x1d; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0xff, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0xff, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
-       outb (0x1e, hw->fx_mod_addr);
-       outb (0x40, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
+       outb (0x1e, dev.fx_mod_addr);
+       outb (0x40, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
 
        for (i = 0x1f; i <= 0x2d; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0xff, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0xff, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
-       outb (0x2e, hw->fx_mod_addr);
-       outb (0x00, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
+       outb (0x2e, dev.fx_mod_addr);
+       outb (0x00, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
 
        for (i = 0x2f; i <= 0x3e; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0x00, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0x00, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
-       outb (0x3f, hw->fx_mod_addr);
-       outb (0x20, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
+       outb (0x3f, dev.fx_mod_addr);
+       outb (0x20, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
 
        for (i = 0x40; i <= 0x4d; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0x00, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0x00, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
-       outb (0x4e, hw->fx_mod_addr);
-       outb (0x0e, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x4f, hw->fx_mod_addr);
-       outb (0x0e, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
+       outb (0x4e, dev.fx_mod_addr);
+       outb (0x0e, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
+       outb (0x4f, dev.fx_mod_addr);
+       outb (0x0e, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
 
 
        for (i = 0x50; i <= 0x6b; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0x00, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0x00, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
-       outb (0x6c, hw->fx_mod_addr);
-       outb (0x40, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
+       outb (0x6c, dev.fx_mod_addr);
+       outb (0x40, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
 
-       outb (0x6d, hw->fx_mod_addr);
-       outb (0x00, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
+       outb (0x6d, dev.fx_mod_addr);
+       outb (0x00, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
 
-       outb (0x6e, hw->fx_mod_addr);
-       outb (0x40, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
+       outb (0x6e, dev.fx_mod_addr);
+       outb (0x40, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
 
-       outb (0x6f, hw->fx_mod_addr);
-       outb (0x40, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
+       outb (0x6f, dev.fx_mod_addr);
+       outb (0x40, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
 
        for (i = 0x70; i <= 0x7f; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0xc0, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0xc0, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
     
        for (i = 0x80; i <= 0xaf; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0x00, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0x00, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
        for (i = 0xc0; i <= 0xdd; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0x00, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0x00, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
-       outb (0xde, hw->fx_mod_addr);
-       outb (0x10, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0xdf, hw->fx_mod_addr);
-       outb (0x10, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
+       outb (0xde, dev.fx_mod_addr);
+       outb (0x10, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
+       outb (0xdf, dev.fx_mod_addr);
+       outb (0x10, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
 
        for (i = 0xe0; i <= 0xef; i++) {
-               outb (i, hw->fx_mod_addr);
-               outb (0x00, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_mod_addr);
+               outb (0x00, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
        for (i = 0x00; i <= 0x0f; i++) {
-               outb (0x01, hw->fx_mod_addr);
-               outb (i, hw->fx_mod_data);
-               outb (0x02, hw->fx_mod_addr);
-               outb (0x01, hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (0x01, dev.fx_mod_addr);
+               outb (i, dev.fx_mod_data);
+               outb (0x02, dev.fx_mod_addr);
+               outb (0x01, dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
-       outb (0x02, hw->fx_op); /* mute on */
+       outb (0x02, dev.fx_op); /* mute on */
 
        /* Now set the coefficients and so forth for the programs above */
 
        for (i = 0; i < sizeof (coefficients); i += 4) {
-               outb (coefficients[i], hw->fx_dsp_page);
-               outb (coefficients[i+1], hw->fx_dsp_addr);
-               outb (coefficients[i+2], hw->fx_dsp_msb);
-               outb (coefficients[i+3], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (coefficients[i], dev.fx_dsp_page);
+               outb (coefficients[i+1], dev.fx_dsp_addr);
+               outb (coefficients[i+2], dev.fx_dsp_msb);
+               outb (coefficients[i+3], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
 
        /* Some settings (?) that are too small to bundle into loops */
 
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x1e, hw->fx_mod_addr);
-       outb (0x14, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0xde, hw->fx_mod_addr);
-       outb (0x20, hw->fx_mod_data);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0xdf, hw->fx_mod_addr);
-       outb (0x20, hw->fx_mod_data);
+       if (!wffx_idle()) return (-1);
+       outb (0x1e, dev.fx_mod_addr);
+       outb (0x14, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
+       outb (0xde, dev.fx_mod_addr);
+       outb (0x20, dev.fx_mod_data);
+       if (!wffx_idle()) return (-1);
+       outb (0xdf, dev.fx_mod_addr);
+       outb (0x20, dev.fx_mod_data);
     
        /* some more coefficients */
 
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x06, hw->fx_dsp_page);
-       outb (0x78, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x40, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x03, hw->fx_dsp_addr);
-       outb (0x0f, hw->fx_dsp_msb);
-       outb (0xff, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x0b, hw->fx_dsp_addr);
-       outb (0x0f, hw->fx_dsp_msb);
-       outb (0xff, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x02, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x0a, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x46, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
-       if (!wffx_idle(hw)) return (-1);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x49, hw->fx_dsp_addr);
-       outb (0x00, hw->fx_dsp_msb);
-       outb (0x00, hw->fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x06, dev.fx_dsp_page);
+       outb (0x78, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x40, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x03, dev.fx_dsp_addr);
+       outb (0x0f, dev.fx_dsp_msb);
+       outb (0xff, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x0b, dev.fx_dsp_addr);
+       outb (0x0f, dev.fx_dsp_msb);
+       outb (0xff, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x02, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x0a, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x46, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
+       if (!wffx_idle()) return (-1);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x49, dev.fx_dsp_addr);
+       outb (0x00, dev.fx_dsp_msb);
+       outb (0x00, dev.fx_dsp_lsb);
     
        /* Now, for some strange reason, lets reload every page
           and all the coefficients over again. I have *NO* idea
@@ -3461,117 +3442,116 @@ wffx_init (struct wf_config *hw)
           is this phase is omitted.
        */
 
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x00, hw->fx_dsp_page);  
-       outb (0x10, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x00, dev.fx_dsp_page);  
+       outb (0x10, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_zero_v2); i += 2) {
-               outb (page_zero_v2[i], hw->fx_dsp_msb);
-               outb (page_zero_v2[i+1], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_zero_v2[i], dev.fx_dsp_msb);
+               outb (page_zero_v2[i+1], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
     
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x01, hw->fx_dsp_page);
-       outb (0x10, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x01, dev.fx_dsp_page);
+       outb (0x10, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_one_v2); i += 2) {
-               outb (page_one_v2[i], hw->fx_dsp_msb);
-               outb (page_one_v2[i+1], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_one_v2[i], dev.fx_dsp_msb);
+               outb (page_one_v2[i+1], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
     
-       if (!wffx_idle(hw)) return (-1);
-       if (!wffx_idle(hw)) return (-1);
+       if (!wffx_idle()) return (-1);
+       if (!wffx_idle()) return (-1);
     
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x02, hw->fx_dsp_page);
-       outb (0x10, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x02, dev.fx_dsp_page);
+       outb (0x10, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_two_v2); i++) {
-               outb (page_two_v2[i], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_two_v2[i], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x03, hw->fx_dsp_page);
-       outb (0x10, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x03, dev.fx_dsp_page);
+       outb (0x10, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_three_v2); i++) {
-               outb (page_three_v2[i], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_three_v2[i], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
     
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x04, hw->fx_dsp_page);
-       outb (0x10, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x04, dev.fx_dsp_page);
+       outb (0x10, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_four_v2); i++) {
-               outb (page_four_v2[i], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_four_v2[i], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
     
-       outb (FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x06, hw->fx_dsp_page);
+       outb (FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x06, dev.fx_dsp_page);
 
        /* Page six v.2 is algorithmic */
     
        for (i = 0x10; i <= 0x3e; i += 2) {
-               outb (i, hw->fx_dsp_addr);
-               outb (0x00, hw->fx_dsp_msb);
-               outb (0x00, hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (i, dev.fx_dsp_addr);
+               outb (0x00, dev.fx_dsp_msb);
+               outb (0x00, dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
 
-       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, hw->fx_lcr);
-       outb (0x07, hw->fx_dsp_page);
-       outb (0x10, hw->fx_dsp_addr);
+       outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
+       outb (0x07, dev.fx_dsp_page);
+       outb (0x10, dev.fx_dsp_addr);
 
        for (i = 0; i < sizeof (page_seven_v2); i += 2) {
-               outb (page_seven_v2[i], hw->fx_dsp_msb);
-               outb (page_seven_v2[i+1], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (page_seven_v2[i], dev.fx_dsp_msb);
+               outb (page_seven_v2[i+1], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
 
        for (i = 0x00; i < sizeof(mod_v2); i += 2) {
-               outb (mod_v2[i], hw->fx_mod_addr);
-               outb (mod_v2[i+1], hw->fx_mod_data);
-               if (!wffx_idle(hw)) return (-1);
+               outb (mod_v2[i], dev.fx_mod_addr);
+               outb (mod_v2[i+1], dev.fx_mod_data);
+               if (!wffx_idle()) return (-1);
        }
 
        for (i = 0; i < sizeof (coefficients2); i += 4) {
-               outb (coefficients2[i], hw->fx_dsp_page);
-               outb (coefficients2[i+1], hw->fx_dsp_addr);
-               outb (coefficients2[i+2], hw->fx_dsp_msb);
-               outb (coefficients2[i+3], hw->fx_dsp_lsb);
-               if (!wffx_idle(hw)) return (-1);
+               outb (coefficients2[i], dev.fx_dsp_page);
+               outb (coefficients2[i+1], dev.fx_dsp_addr);
+               outb (coefficients2[i+2], dev.fx_dsp_msb);
+               outb (coefficients2[i+3], dev.fx_dsp_lsb);
+               if (!wffx_idle()) return (-1);
        }
 
-       outb (0x00, hw->fx_op);
-       if (!wffx_idle(hw)) return (-1);
-    
        for (i = 0; i < sizeof (coefficients3); i += 2) {
                int x;
 
-               outb (0x07, hw->fx_dsp_page);
+               outb (0x07, dev.fx_dsp_page);
                x = (i % 4) ? 0x4e : 0x4c;
-               outb (x, hw->fx_dsp_addr);
-               outb (coefficients3[i], hw->fx_dsp_msb);
-               outb (coefficients3[i+1], hw->fx_dsp_lsb);
+               outb (x, dev.fx_dsp_addr);
+               outb (coefficients3[i], dev.fx_dsp_msb);
+               outb (coefficients3[i+1], dev.fx_dsp_lsb);
        }
 
-       outb (0x00, hw->fx_op); /* mute off */
+       outb (0x00, dev.fx_op); /* mute off */
+       if (!wffx_idle()) return (-1);
 
        return (0);
 }
 
 EXPORT_NO_SYMBOLS;
-struct address_info cfg;
 
 int io = -1;
 int irq = -1;
 
-MODULE_PARM(io,"i");
-MODULE_PARM(irq,"i");
+MODULE_AUTHOR      ("Paul Barton-Davis <pbd@op.net>");
+MODULE_DESCRIPTION ("Turtle Beach WaveFront Linux Driver");
+MODULE_PARM        (io,"i");
+MODULE_PARM        (irq,"i");
 
 int init_module (void)
 
@@ -3580,19 +3560,27 @@ int init_module (void)
                "Copyright (C) by Hannu Solvainen, "
                "Paul Barton-Davis 1993-1998.\n");
 
+       /* XXX t'would be lovely to ask the CS4232 for these values, eh ? */
+
        if (io == -1 || irq == -1) {
-               printk (KERN_INFO "WaveFront: irq and io "
-                       "options must be set.\n");
+               printk (KERN_INFO LOGNAME "irq and io options must be set.\n");
                return -EINVAL;
        }
 
-       cfg.io_base = io;
-       cfg.irq = irq;
+       if (wavefront_interrupt_bits (irq) < 0) {
+               printk (KERN_INFO LOGNAME
+                       "IRQ must be 9, 5, 12 or 15 (not %d)\n", irq);
+               return -ENODEV;
+       }
 
-       if (probe_wavefront (&cfg) == 0) {
+       if (detect_wavefront (irq, io) < 0) {
                return -ENODEV;
        } 
-       attach_wavefront (&cfg);
+
+       if (install_wavefront () < 0) {
+               return -EIO;
+       }
+
        SOUND_LOCK;
        return 0;
 }
@@ -3600,10 +3588,11 @@ int init_module (void)
 void cleanup_module (void)
 
 {
-       unload_wavefront (&cfg);
+       uninstall_wavefront ();
+
        SOUND_LOCK_END;
 }
 
-#endif CONFIG_SOUND_WAVEFRONT_MODULE_AND_MODULE
+#endif CONFIG_SOUND_WAVEFRONT_MODULE && MODULE
 
 
index ee26fb1ec98afe9165946e2d639a9e804fdd76ec..0fbb9f86a759386ff455a0e6831a70fef9f0b752 100644 (file)
@@ -40,7 +40,7 @@
 
 /*
  * Copyright (C) by Paul Barton-Davis 1998
- * Substantial portions of this file are derived from work that is:
+ * Some portions of this file are derived from work that is:
  *
  *    Copyright (C) by Hannu Savolainen 1993-1996
  *
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include "sound_config.h"
 #include "soundmodule.h"
 
 #include <linux/wavefront.h>
 
-#if (defined(CONFIG_WAVEFRONT) && defined(CONFIG_MIDI)) || defined(MODULE)
+#if defined(CONFIG_SOUND_WAVEFRONT_MODULE) && defined(MODULE)
 
 struct wf_mpu_config {
-       int             base;   /* I/O base */
+       int             base;
+#define        DATAPORT(d)   (d)->base
+#define        COMDPORT(d)   (d)->base+1
+#define        STATPORT(d)   (d)->base+1
+
        int             irq;
-       int             opened; /* Open mode */
+       int             opened;
        int             devno;
        int             synthno;
        int             mode;
@@ -68,69 +73,54 @@ struct wf_mpu_config {
 #define MODE_SYNTH     2
 
        void            (*inputintr) (int dev, unsigned char data);
-    
-       /* Virtual MIDI support */
-    
-       char configured_for_virtual;   /* setup for virtual completed */
        char isvirtual;                /* do virtual I/O stuff */
-       char isexternal;               /* i am an external interface */
-       int internal;                  /* external interface midi_devno */
-       int external;                  /* external interface midi_devno */
 };
 
-#define        DATAPORT(base)   (base)
-#define        COMDPORT(base)   (base+1)
-#define        STATPORT(base)   (base+1)
+static struct wf_mpu_config  devs[2];
+static struct wf_mpu_config *phys_dev = &devs[0];
+static struct wf_mpu_config *virt_dev = &devs[1];
 
-static void     start_uart_mode (struct wf_mpu_config *devc);
+static void start_uart_mode (void);
 
-static int 
-wf_mpu_status (struct wf_mpu_config *devc)
-{
-       return inb (STATPORT (devc->base));
-}
+#define        OUTPUT_READY    0x40
+#define        INPUT_AVAIL     0x80
+#define        MPU_ACK         0xFE
+#define        UART_MODE_ON    0x3F
+
+static inline int 
+wf_mpu_status (void)
 
-static void 
-wf_mpu_cmd (struct wf_mpu_config *devc, unsigned char cmd)
 {
-       outb ((cmd), COMDPORT(devc->base));
+       return inb (STATPORT (phys_dev));
 }
 
-#define input_avail(devc)              (!(wf_mpu_status(devc)&INPUT_AVAIL))
-#define output_ready(devc)             (!(wf_mpu_status(devc)&OUTPUT_READY))
+static inline int 
+input_avail (void)
 
-static int 
-read_data (struct wf_mpu_config *devc)
 {
-       return inb (DATAPORT (devc->base));
+       return !(wf_mpu_status() & INPUT_AVAIL);
 }
 
-static void 
-write_data (struct wf_mpu_config *devc, unsigned char byte)
+static inline int
+output_ready (void)
+
 {
-       outb (byte, DATAPORT (devc->base));
+       return !(wf_mpu_status() & OUTPUT_READY);
 }
 
-#define        OUTPUT_READY    0x40
-#define        INPUT_AVAIL     0x80
-#define        MPU_ACK         0xFE
-#define        MPU_RESET       0xFF
-#define        UART_MODE_ON    0x3F
+static inline int 
+read_data (void)
 
-static struct wf_mpu_config dev_conf[MAX_MIDI_DEV] =
 {
-       {0}
-};
-
-static volatile int irq2dev[17] =
-{-1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1};
+       return inb (DATAPORT (phys_dev));
+}
 
-static struct synth_info wf_mpu_synth_info_proto =
-{"WaveFront MPU-401 interface", 0,
- SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
+static inline void 
+write_data (unsigned char byte)
 
-static struct synth_info wf_mpu_synth_info[MAX_MIDI_DEV];
+{
+       outb (byte, DATAPORT (phys_dev));
+}
 
 /*
  * States for the input scanner (should be in dev_table.h)
@@ -162,11 +152,10 @@ static unsigned char len_tab[] =  /* # of data bytes following a status
 };
 
 static int
-wf_mpu_input_scanner (struct wf_mpu_config *devc, unsigned char midic)
-{
-       struct midi_input_info *mi;
+wf_mpu_input_scanner (int devno, int synthdev, unsigned char midic)
 
-       mi = &midi_devs[devc->devno]->in_info;
+{
+       struct midi_input_info *mi = &midi_devs[devno]->in_info;
 
        switch (mi->m_state) {
        case MST_INIT:
@@ -236,8 +225,7 @@ wf_mpu_input_scanner (struct wf_mpu_config *devc, unsigned char midic)
 
                        if (mi->m_left <= 0) {
                                mi->m_state = MST_INIT;
-                               do_midi_msg (devc->synthno, mi->m_buf,
-                                            mi->m_ptr);
+                               do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
                                mi->m_ptr = 0;
                        }
                } else if (msg == 0xf) {        /* MPU MARK */
@@ -266,8 +254,7 @@ wf_mpu_input_scanner (struct wf_mpu_config *devc, unsigned char midic)
              
                        if (mi->m_left <= 0) {
                                mi->m_state = MST_INIT;
-                               do_midi_msg (devc->synthno, mi->m_buf,
-                                            mi->m_ptr);
+                               do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
                                mi->m_ptr = 0;
                        }
                }
@@ -362,7 +349,7 @@ wf_mpu_input_scanner (struct wf_mpu_config *devc, unsigned char midic)
                mi->m_buf[mi->m_ptr++] = midic;
                if ((--mi->m_left) <= 0) {
                        mi->m_state = MST_INIT;
-                       do_midi_msg (devc->synthno, mi->m_buf, mi->m_ptr);
+                       do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
                        mi->m_ptr = 0;
                }
                break;
@@ -375,78 +362,65 @@ wf_mpu_input_scanner (struct wf_mpu_config *devc, unsigned char midic)
        return 1;
 }
 
-void wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy)
+void
+wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy)
+
 {
-       struct wf_mpu_config *devc;
-       int dev;
-       static struct wf_mpu_config *isrc = 0;
+       struct wf_mpu_config *physical_dev = dev_id;
+       static struct wf_mpu_config *input_dev = 0;
+       struct midi_input_info *mi = &midi_devs[physical_dev->devno]->in_info;
        int n;
-       struct midi_input_info *mi;
 
-       if (irq < 0 || irq > 15) 
-       {
-               printk (KERN_ERR "WF-MPU: bogus interrupt #%d", irq);
+       if (!input_avail()) { /* not for us */
                return;
        }
-       dev = irq2dev[irq];
-       mi = &midi_devs[dev]->in_info;
-       if (mi->m_busy)
-               return;
+
+       if (mi->m_busy) return;
        mi->m_busy = 1;
-       
        sti (); 
 
-       n = 50;
-
-       /* guarantee that we're working with the "real" (internal)
-          interface before doing anything physical.
-       */
+       if (!input_dev) {
+               input_dev = physical_dev;
+       }
 
-       devc = &dev_conf[dev];
-       devc = &dev_conf[devc->internal];
+       n = 50; /* XXX why ? */
 
-       if (isrc == 0) {
-      
-               /* This is just an initial setting. If Virtual MIDI mode is
-                  enabled on the ICS2115, we'll get a switch char before
-                  anything else, and if it isn't, then the guess will be
-                  correct for our purposes.
-               */
-      
-               isrc = &dev_conf[devc->internal];
-       }
-  
-       while (input_avail (devc) && n-- > 0) {
-               unsigned char c = read_data (devc);
+       do {
+               unsigned char c = read_data ();
       
-               if (devc->isvirtual) {
+               if (phys_dev->isvirtual) {
+
                        if (c == WF_EXTERNAL_SWITCH) {
-                               isrc = &dev_conf[devc->external];
+                               input_dev = virt_dev;
                                continue;
                        } else if (c == WF_INTERNAL_SWITCH) { 
-                               isrc = &dev_conf[devc->internal];
+                               input_dev = phys_dev;
                                continue;
                        } /* else just leave it as it is */
+
                } else {
-                       isrc = &dev_conf[devc->internal];
+                       input_dev = phys_dev;
                }
 
-               if (isrc->mode == MODE_SYNTH) {
+               if (input_dev->mode == MODE_SYNTH) {
          
-                       wf_mpu_input_scanner (isrc, c);
+                       wf_mpu_input_scanner (input_dev->devno,
+                                             input_dev->synthno, c);
          
-               } else if (isrc->opened & OPEN_READ) {
+               } else if (input_dev->opened & OPEN_READ) {
          
-                       if (isrc->inputintr) {
-                               isrc->inputintr (isrc->devno, c);
+                       if (input_dev->inputintr) {
+                               input_dev->inputintr (input_dev->devno, c);
                        } 
                }
-       }
+
+       } while (input_avail() && n-- > 0);
 
        mi->m_busy = 0;
 }
 
-static int wf_mpu_open (int dev, int mode,
+static int
+wf_mpu_open (int dev, int mode,
             void            (*input) (int dev, unsigned char data),
             void            (*output) (int dev)
        )
@@ -456,7 +430,14 @@ static int wf_mpu_open (int dev, int mode,
        if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
                return -(ENXIO);
 
-       devc = &dev_conf[dev];
+       if (phys_dev->devno == dev) {
+               devc = phys_dev;
+       } else if (phys_dev->isvirtual && virt_dev->devno == dev) {
+               devc = virt_dev;
+       } else {
+               printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+               return -(EINVAL);
+       }
 
        if (devc->opened) {
                return -(EBUSY);
@@ -475,7 +456,18 @@ wf_mpu_close (int dev)
 {
        struct wf_mpu_config *devc;
 
-       devc = &dev_conf[dev];
+       if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
+               return;
+
+       if (phys_dev->devno == dev) {
+               devc = phys_dev;
+       } else if (phys_dev->isvirtual && virt_dev->devno == dev) {
+               devc = virt_dev;
+       } else {
+               printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+               return;
+       }
+
        devc->mode = 0;
        devc->inputintr = NULL;
        devc->opened = 0;
@@ -487,40 +479,35 @@ wf_mpu_out (int dev, unsigned char midi_byte)
        int             timeout;
        unsigned long   flags;
        static int lastoutdev = -1;
-
-       struct wf_mpu_config *devc;
        unsigned char switchch;
 
-       /* The actual output has to occur using the "internal" config info
-        */
-  
-       devc = &dev_conf[dev_conf[dev].internal];
-  
-       if (devc->isvirtual && lastoutdev != dev) {
+       if (phys_dev->isvirtual && lastoutdev != dev) {
       
-               if (dev == devc->internal) { 
+               if (dev == phys_dev->devno) { 
                        switchch = WF_INTERNAL_SWITCH;
-               } else if (dev == devc->external) { 
+               } else if (dev == virt_dev->devno) { 
                        switchch = WF_EXTERNAL_SWITCH;
                } else {
                        printk (KERN_ERR "WF-MPU: bad device number %d", dev);
                        return (0);
                }
+
+               /* XXX fix me */
       
-               for (timeout = 30000; timeout > 0 && !output_ready (devc);
+               for (timeout = 30000; timeout > 0 && !output_ready ();
                     timeout--);
       
                save_flags (flags);
                cli ();
       
-               if (!output_ready (devc)) {
+               if (!output_ready ()) {
                        printk (KERN_WARNING "WF-MPU: Send switch "
                                "byte timeout\n");
                        restore_flags (flags);
                        return 0;
                }
       
-               write_data (devc, switchch);
+               write_data (switchch);
                restore_flags (flags);
        } 
 
@@ -531,17 +518,19 @@ wf_mpu_out (int dev, unsigned char midi_byte)
         * (After reset). Normally it takes just about 10 loops.
         */
 
-       for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--);
+       /* XXX fix me */
+
+       for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);
 
        save_flags (flags);
        cli ();
-       if (!output_ready (devc)) {
+       if (!output_ready ()) {
                printk (KERN_WARNING "WF-MPU: Send data timeout\n");
                restore_flags (flags);
                return 0;
        }
 
-       write_data (devc, midi_byte);
+       write_data (midi_byte);
        restore_flags (flags);
 
        return 1;
@@ -567,35 +556,63 @@ wf_mpu_ioctl (int dev, unsigned cmd, caddr_t arg)
        return -(EINVAL);
 }
 
-static void
-wf_mpu_kick (int dev)
-{
-}
-
 static int
 wf_mpu_buffer_status (int dev)
 {
-       return 0;                       /*
-                                        * No data in buffers
-                                        */
+       return 0;
 }
 
+static struct synth_operations wf_mpu_synth_operations[2];
+static struct midi_operations  wf_mpu_midi_operations[2];
+
+static struct midi_operations wf_mpu_midi_proto =
+{
+       {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
+       NULL,  /*converter*/
+       {0},   /* in_info */
+       wf_mpu_open,
+       wf_mpu_close,
+       wf_mpu_ioctl,
+       wf_mpu_out,
+       wf_mpu_start_read,
+       wf_mpu_end_read,
+       NULL,
+       NULL,
+       wf_mpu_buffer_status,
+       NULL
+};
+
+static struct synth_info wf_mpu_synth_info_proto =
+{"WaveFront MPU-401 interface", 0,
+ SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
+
+static struct synth_info wf_mpu_synth_info[2];
+
 static int
 wf_mpu_synth_ioctl (int dev,
                    unsigned int cmd, caddr_t arg)
 {
        int             midi_dev;
+       int index;
 
        midi_dev = synth_devs[dev]->midi_dev;
 
        if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL)
                return -(ENXIO);
 
+       if (midi_dev == phys_dev->devno) {
+               index = 0;
+       } else if (phys_dev->isvirtual && midi_dev == virt_dev->devno) {
+               index = 1;
+       } else {
+               return -(EINVAL);
+       }
+
        switch (cmd) {
 
        case SNDCTL_SYNTH_INFO:
                copy_to_user (&((char *) arg)[0],
-                             &wf_mpu_synth_info[midi_dev],
+                             &wf_mpu_synth_info[index],
                              sizeof (struct synth_info));
        
                return 0;
@@ -622,7 +639,15 @@ wf_mpu_synth_open (int dev, int mode)
                return -(ENXIO);
        }
   
-       devc = &dev_conf[midi_dev];
+       if (phys_dev->devno == midi_dev) {
+               devc = phys_dev;
+       } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
+               devc = virt_dev;
+       } else {
+               printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+               return -(EINVAL);
+       }
+
        if (devc->opened) {
                return -(EBUSY);
        }
@@ -642,7 +667,15 @@ wf_mpu_synth_close (int dev)
 
        midi_dev = synth_devs[dev]->midi_dev;
 
-       devc = &dev_conf[midi_dev];
+       if (phys_dev->devno == midi_dev) {
+               devc = phys_dev;
+       } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
+               devc = virt_dev;
+       } else {
+               printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
+               return;
+       }
+
        devc->inputintr = NULL;
        devc->opened = 0;
        devc->mode = 0;
@@ -678,233 +711,145 @@ static struct synth_operations wf_mpu_synth_proto =
        midi_synth_send_sysex
 };
 
-static struct synth_operations wf_mpu_synth_operations[2];
-static struct midi_operations  wf_mpu_midi_operations[2];
-static int wfmpu_cnt = 0;
-
-static struct midi_operations wf_mpu_midi_proto =
-{
-       {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
-       NULL,  /*converter*/
-       {0},   /* in_info */
-       wf_mpu_open,
-       wf_mpu_close,
-       wf_mpu_ioctl,
-       wf_mpu_out,
-       wf_mpu_start_read,
-       wf_mpu_end_read,
-       wf_mpu_kick,
-       NULL,
-       wf_mpu_buffer_status,
-       NULL
-};
-
-
 static int
-config_wf_mpu (int dev, struct address_info *hw_config)
+config_wf_mpu (struct wf_mpu_config *dev)
 
 {
-       struct wf_mpu_config *devc;
-       int                internal;
-
-       if (wfmpu_cnt >= 2) {
-               printk (KERN_ERR "WF-MPU: more MPU devices than cards ?!!\n");
-               return (-1);
-       }
-  
-       /* There is no synth available on the external interface,
-          so do the synth stuff to the internal interface only.
-       */
-
-       internal = dev_conf[dev].internal;
-       devc = &dev_conf[internal];
-
-       if (!dev_conf[dev].isexternal) {
-               memcpy ((char *) &wf_mpu_synth_operations[wfmpu_cnt],
+       int is_external;
+       char *name;
+       int index;
+
+       if (dev == phys_dev) {
+               name = "WaveFront internal MIDI";
+               is_external = 0;
+               index = 0;
+               memcpy ((char *) &wf_mpu_synth_operations[index],
                        (char *) &wf_mpu_synth_proto,
                        sizeof (struct synth_operations));
-       }
-
-       memcpy ((char *) &wf_mpu_midi_operations[wfmpu_cnt],
-               (char *) &wf_mpu_midi_proto,
-               sizeof (struct midi_operations));
-  
-       if (dev_conf[dev].isexternal) {
-               wf_mpu_midi_operations[wfmpu_cnt].converter = NULL;
        } else {
-               wf_mpu_midi_operations[wfmpu_cnt].converter =
-                       &wf_mpu_synth_operations[wfmpu_cnt];
+               name = "WaveFront external MIDI";
+               is_external = 1;
+               index = 1;
+               /* no synth operations for an external MIDI interface */
        }
 
-       memcpy ((char *) &wf_mpu_synth_info[dev],
+       memcpy ((char *) &wf_mpu_synth_info[dev->devno],
                (char *) &wf_mpu_synth_info_proto,
                sizeof (struct synth_info));
 
-       strcpy (wf_mpu_synth_info[dev].name, hw_config->name);
-       strcpy (wf_mpu_midi_operations[wfmpu_cnt].info.name, hw_config->name);
+       strcpy (wf_mpu_synth_info[index].name, name);
 
-       conf_printf (hw_config->name, hw_config);
+       wf_mpu_synth_operations[index].midi_dev = dev->devno;
+       wf_mpu_synth_operations[index].info = &wf_mpu_synth_info[index];
 
-       if (!dev_conf[dev].isexternal) {
-               wf_mpu_synth_operations[wfmpu_cnt].midi_dev = dev;
+       memcpy ((char *) &wf_mpu_midi_operations[index],
+               (char *) &wf_mpu_midi_proto,
+               sizeof (struct midi_operations));
+  
+       if (is_external) {
+               wf_mpu_midi_operations[index].converter = NULL;
+       } else {
+               wf_mpu_midi_operations[index].converter =
+                       &wf_mpu_synth_operations[index];
        }
-       wf_mpu_synth_operations[wfmpu_cnt].info = &wf_mpu_synth_info[dev];
-
-       midi_devs[dev] = &wf_mpu_midi_operations[wfmpu_cnt];
 
-       dev_conf[dev].opened = 0;
-       dev_conf[dev].mode = 0;
-       dev_conf[dev].configured_for_virtual = 0;
-       dev_conf[dev].devno = dev;
+       strcpy (wf_mpu_midi_operations[index].info.name, name);
 
-       midi_devs[dev]->in_info.m_busy = 0;
-       midi_devs[dev]->in_info.m_state = MST_INIT;
-       midi_devs[dev]->in_info.m_ptr = 0;
-       midi_devs[dev]->in_info.m_left = 0;
-       midi_devs[dev]->in_info.m_prev_status = 0;
+       midi_devs[dev->devno] = &wf_mpu_midi_operations[index];
+       midi_devs[dev->devno]->in_info.m_busy = 0;
+       midi_devs[dev->devno]->in_info.m_state = MST_INIT;
+       midi_devs[dev->devno]->in_info.m_ptr = 0;
+       midi_devs[dev->devno]->in_info.m_left = 0;
+       midi_devs[dev->devno]->in_info.m_prev_status = 0;
 
-       wfmpu_cnt++;
+       devs[index].opened = 0;
+       devs[index].mode = 0;
 
        return (0);
 }
 
-int
-virtual_midi_enable (int dev, struct address_info *hw_config)
+int virtual_midi_enable (void)
 
 {
-       int idev;
-       int edev;
-       struct wf_mpu_config *devc;
-
-       devc = &dev_conf[dev];
-       
-       if (devc->configured_for_virtual) {
-
-               idev = devc->internal;
-               edev = devc->external;
-
-       } else {
-
-               if (hw_config == NULL) {
-                       printk (KERN_ERR
-                               "WF-MPU: virtual midi first "
-                               "enabled without hw_config!\n");
-                       return -EINVAL;
-               }
+       if ((virt_dev->devno < 0) &&
+           (virt_dev->devno = sound_alloc_mididev()) == -1) {
+               printk (KERN_ERR
+                       "WF-MPU: too many midi devices detected\n");
+               return -1;
+       }
 
-               idev = devc->internal;
+       config_wf_mpu (virt_dev);
 
-               if ((edev = sound_alloc_mididev()) == -1) {
-                       printk (KERN_ERR
-                               "WF-MPU: too many midi devices detected\n");
-                       return -1;
-               }
+       phys_dev->isvirtual = 1;
+       return virt_dev->devno;
+}
 
-               hw_config->slots[WF_EXTERNAL_MIDI_SLOT] = edev;
-       }
+int
+virtual_midi_disable (void)
 
-       dev_conf[edev].isvirtual = 1;
-       dev_conf[idev].isvirtual = 1;
-    
-       if (dev_conf[idev].configured_for_virtual) {
-               return 0;
-       } 
+{
+       unsigned long flags;
 
-       /* Configure external interface struct */
+       save_flags (flags);
+       cli();
 
-       devc = &dev_conf[edev];
-       devc->internal = idev;
-       devc->external = edev;
-       devc->isexternal = 1;
+       wf_mpu_close (virt_dev->devno);
+       /* no synth on virt_dev, so no need to call wf_mpu_synth_close() */
+       phys_dev->isvirtual = 0;
 
-       /* Configure external interface struct 
-          (devc->isexternal and devc->internal set in attach_wf_mpu())
-       */
+       restore_flags (flags);
 
-       devc = &dev_conf[idev];
-       devc->external = edev;
+       return 0;
+}
 
-       /* Configure the tables for the external */
+__initfunc (static int detect_wf_mpu (int irq, int io_base))
 
-       if (config_wf_mpu (edev, hw_config)) {
-               printk (KERN_WARNING "WF-MPU: configuration for MIDI "
-                       "device %d failed\n", edev);
-               return (-1);
+{
+       if (check_region (io_base, 2)) {
+               printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n",
+                       io_base);
+               return -1;
        }
 
-       /* Don't bother to do this again if we are toggled back and
-          forth between virtual MIDI mode and "normal" operation.
-       */
-
-       dev_conf[edev].configured_for_virtual = 1;
-       dev_conf[idev].configured_for_virtual = 1;
+       phys_dev->base = io_base;
+       phys_dev->irq = irq;
+       phys_dev->devno = -1;
+       virt_dev->devno = -1;
 
        return 0;
 }
 
-void
-virtual_midi_disable (int dev)
+__initfunc (int install_wf_mpu (void)) 
 
 {
-       struct wf_mpu_config *devc;
-       unsigned long flags;
+       if ((phys_dev->devno = sound_alloc_mididev()) < 0){
 
-       save_flags (flags);
-       cli();
-
-       /* Assumes for logical purposes that the caller has taken
-          care of fiddling with WaveFront hardware commands to
-          turn off Virtual MIDI mode. 
-       */
-    
-       devc = &dev_conf[dev];
+               printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n");
+               return -1;
 
-       devc = &dev_conf[devc->internal];
-       devc->isvirtual = 0;
+       }
 
-       devc = &dev_conf[devc->external];
-       devc->isvirtual = 0;
+       request_region (phys_dev->base, 2, "wavefront midi");
+       phys_dev->isvirtual = 0;
 
-       restore_flags (flags);
-}
+       if (config_wf_mpu (phys_dev)) {
 
-void
-attach_wf_mpu (struct address_info *hw_config)
-{
-       int m;
-       struct wf_mpu_config *devc;
-
-       if (request_irq (hw_config->irq, wf_mpuintr,
-                        0, "WaveFront MIDI", NULL) < 0) {
-               printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n",
-                       hw_config->irq);
-               return;
-       }
+               printk (KERN_WARNING
+                       "WF-MPU: configuration for MIDI device %d failed\n",
+                       phys_dev->devno);
+               sound_unload_mididev (phys_dev->devno);
 
-       if ((m = sound_alloc_mididev()) == -1){
-               printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n");
-               free_irq (hw_config->irq, NULL);
-               release_region (hw_config->io_base, 2);
-               return;
        }
 
-       request_region (hw_config->io_base, 2, "WaveFront MPU");
+       /* OK, now we're configured to handle an interrupt ... */
 
-       hw_config->slots[WF_INTERNAL_MIDI_SLOT] = m;
-       devc = &dev_conf[m];
-       devc->base = hw_config->io_base;
-       devc->irq = hw_config->irq;
-       devc->isexternal = 0;
-       devc->internal = m;
-       devc->external = -1;
-       devc->isvirtual = 0;
+       if (request_irq (phys_dev->irq, wf_mpuintr, SA_INTERRUPT|SA_SHIRQ,
+                        "wavefront midi", phys_dev) < 0) {
 
-       irq2dev[devc->irq] = m;
+               printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n",
+                       phys_dev->irq);
+               return -1;
 
-       if (config_wf_mpu (m, hw_config)) {
-               printk (KERN_WARNING
-                       "WF-MPU: configuration for MIDI device %d failed\n", m);
-               sound_unload_mididev (m);
        }
 
        /* This being a WaveFront (ICS-2115) emulated MPU-401, we have
@@ -912,64 +857,43 @@ attach_wf_mpu (struct address_info *hw_config)
           won't do anything at all.
        */
   
-       start_uart_mode (devc);
+       start_uart_mode ();
 
+       return phys_dev->devno;
 }
-
-int
-probe_wf_mpu (struct address_info *hw_config)
-
-{
-       if (hw_config->irq < 0 || hw_config->irq > 16) {
-               printk (KERN_WARNING "WF-MPU: bogus IRQ value requested (%d)\n",
-                       hw_config->irq);
-               return 0;
-       }
-
-       if (check_region (hw_config->io_base, 2)) {
-               printk (KERN_WARNING "WF-MPU: I/O port %x already in use\n\n",
-                       hw_config->io_base);
-               return 0;
-       }
-
-       if (inb (hw_config->io_base + 1) == 0xff) { /* Just bus float? */
-               printk ("WF-MPU: Port %x looks dead.\n", hw_config->io_base);
-               return 0;
-       }
-
-       return 1;
-}
-
 void
-unload_wf_mpu (struct address_info *hw_config)
+uninstall_wf_mpu (void)
+
 {
+       release_region (phys_dev->base, 2); 
+       free_irq (phys_dev->irq, phys_dev);
+       sound_unload_mididev (phys_dev->devno);
 
-       release_region (hw_config->io_base, 2); 
-       sound_unload_mididev (hw_config->slots[WF_INTERNAL_MIDI_SLOT]);
-       if (hw_config->irq > 0) {
-               free_irq (hw_config->irq, NULL);
-       }
-       if (hw_config->slots[WF_EXTERNAL_MIDI_SLOT] > 0) {
-               sound_unload_mididev (hw_config->slots[WF_EXTERNAL_MIDI_SLOT]);
+       if (virt_dev->devno >= 0) {
+               sound_unload_mididev (virt_dev->devno);
        }
 }
 
 static void
-start_uart_mode (struct wf_mpu_config *devc)
+start_uart_mode (void)
+
 {
-       int             ok, timeout;
+       int             ok, i;
        unsigned long   flags;
 
        save_flags (flags);
        cli ();
 
-       for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--);
+       /* XXX fix me */
 
-       wf_mpu_cmd (devc, UART_MODE_ON);
+       for (i = 0; i < 30000 && !output_ready (); i++);
 
-       for (ok = 0, timeout = 50000; timeout > 0 && !ok; timeout--) {
-               if (input_avail (devc)) {
-                       if (read_data (devc) == MPU_ACK) {
+       outb (UART_MODE_ON, COMDPORT(phys_dev));
+
+       for (ok = 0, i = 50000; i > 0 && !ok; i--) {
+               if (input_avail ()) {
+                       if (read_data () == MPU_ACK) {
                                ok = 1;
                        }
                }
@@ -978,6 +902,30 @@ start_uart_mode (struct wf_mpu_config *devc)
        restore_flags (flags);
 }
 
-#endif
+#ifdef OSS_SUPPORT
+
+int
+probe_wf_mpu (struct address_info *hw_config)
+
+{
+       return !detect_wf_mpu (hw_config->irq, hw_config->io_base);
+}
+
+void
+attach_wf_mpu (struct address_info *hw_config)
+
+{
+       (void) install_wf_mpu ();
+}
+
+void
+unload_wf_mpu (void)
+{
+       uninstall_wf_mpu ();
+}
+
+#endif OSS_SUPPORT
+
+#endif CONFIG_SOUND_WAVEFRONT_MODULE_AND_MODULE
 
 
index 84585f6fea5afb4ecc25886fdf38873df4a5d969..13724a387b6532a6d0bc21dd02fc329ebd2a2ac5 100644 (file)
@@ -2752,6 +2752,7 @@ __initfunc(void atyfb_init(void))
                addr = pdev->base_address[1];
            if (!addr)
                continue;
+           addr &= PCI_BASE_ADDRESS_MEM_MASK;
 
 #ifdef __sparc__
            /*
index 04735949e496a6579619609873ec4fb38208cf25..eb5d8931c166d4c7eb92eb23b88125e39beda0d4 100644 (file)
@@ -53,11 +53,14 @@ struct fb_info_chips {
        struct {
                __u8 red, green, blue;
        } palette[256];
+       unsigned long frame_buffer_phys;
        __u8 *frame_buffer;
-       __u8 *blitter_regs;
+       unsigned long blitter_regs_phys;
+       __u32 *blitter_regs;
+       unsigned long blitter_data_phys;
+       __u8 *blitter_data;
+       unsigned long io_base_phys;
        __u8 *io_base;
-       unsigned long chips_base_phys;
-       unsigned long chips_io_phys;
        struct fb_info_chips *next;
 #ifdef CONFIG_PMAC_PBOOK
        unsigned char *save_framebuffer;
@@ -214,27 +217,28 @@ static int chips_get_cmap(struct fb_cmap *cmap, int kspc, int con,
        if (con == currcon)             /* current console? */
                return fb_get_cmap(cmap, kspc, chipsfb_getcolreg, info);
        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);
+               fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+       else {
+               int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+               fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+       }
        return 0;
 }
 
 static int chips_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                         struct fb_info *info)
 {
-       struct display *disp = &fb_display[con];
        int err;
 
-       if (disp->cmap.len == 0) {
-               err = fb_alloc_cmap(&disp->cmap, 256, 0);
-               if (err)
+       if (!fb_display[con].cmap.len) {        /* no colormap allocated? */
+               int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+               if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
                        return err;
        }
-
-       if (con == currcon)
+       if (con == currcon)                     /* current console? */
                return fb_set_cmap(cmap, kspc, chipsfb_setcolreg, info);
-       fb_copy_cmap(cmap, &disp->cmap, kspc==0);
+       else
+               fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
        return 0;
 }
 
@@ -244,24 +248,21 @@ static int chips_ioctl(struct inode *inode, struct file *file, u_int cmd,
        return -EINVAL;
 }
 
-static int chipsfb_switch(int con, struct fb_info *info)
+static int chipsfbcon_switch(int con, struct fb_info *info)
 {
        struct fb_info_chips *p = (struct fb_info_chips *) info;
-       struct display* old_disp = &fb_display[currcon];
-       struct display* new_disp = &fb_display[con];
-       int     bit_depth;
+       int new_bpp, old_bpp;
 
+       /* Do we have to save the colormap? */
        if (fb_display[currcon].cmap.len)
-               fb_get_cmap(&old_disp->cmap, 1, chipsfb_getcolreg, info);
+               fb_get_cmap(&fb_display[currcon].cmap, 1, chipsfb_getcolreg, info);
 
-       bit_depth = new_disp->var.bits_per_pixel;
-       if (old_disp->var.bits_per_pixel != bit_depth)
-       {
-         currcon = con;
-         chips_set_bitdepth(p, new_disp, con, bit_depth);
-       }
-       else
-         currcon = con;
+       new_bpp = fb_display[con].var.bits_per_pixel;
+       old_bpp = fb_display[currcon].var.bits_per_pixel;
+       currcon = con;
+
+       if (new_bpp != old_bpp)
+               chips_set_bitdepth(p, &fb_display[con], con, new_bpp);
        
        do_install_cmap(con, info);
        return 0;
@@ -277,9 +278,10 @@ static void chipsfb_blank(int blank, struct fb_info *info)
        struct fb_info_chips *p = (struct fb_info_chips *) info;
        int i;
 
-       if (blank > 1) {
+       // used to disable backlight only for blank > 1, but it seems
+       // useful at blank = 1 too (saves battery, extends backlight life)
+       if (blank) {
                pmu_enable_backlight(0);
-       } else if (blank) {
                for (i = 0; i < 256; ++i) {
                        out_8(p->io_base + 0x3c8, i);
                        udelay(1);
@@ -311,10 +313,8 @@ static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                             u_int transp, struct fb_info *info)
 {
        struct fb_info_chips *p = (struct fb_info_chips *) info;
-       int hr;
 
-       hr = (p->fix.visual != FB_VISUAL_PSEUDOCOLOR)? (regno << 3): regno;
-       if (hr > 255)
+       if (regno > 255)
                return 1;
        red >>= 8;
        green >>= 8;
@@ -322,18 +322,18 @@ static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        p->palette[regno].red = red;
        p->palette[regno].green = green;
        p->palette[regno].blue = blue;
-       out_8(p->io_base + 0x3c8, hr);
+       out_8(p->io_base + 0x3c8, regno);
        udelay(1);
        out_8(p->io_base + 0x3c9, red);
        out_8(p->io_base + 0x3c9, green);
        out_8(p->io_base + 0x3c9, blue);
 
 #ifdef FBCON_HAS_CFB16
-       if (regno < 16)
-               p->fbcon_cfb16_cmap[regno] = (red << 10) | (green << 5) | blue;
+       if (regno < 16) p->fbcon_cfb16_cmap[regno] =
+               ((red & 0xf8) << 7) | ((green & 0xf8) << 2) | ((blue & 0xf8) >> 3);
 #endif
 
-    return 0;
+       return 0;
 }
 
 static void do_install_cmap(int con, struct fb_info *info)
@@ -356,14 +356,14 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in
        
        if (bpp == 16) {
                if (con == currcon) {
-                       write_cr(0x13, 200);            // 16 bit display width (decimal)
-                       write_xr(0x81, 0x14);           // 15 bit (TrueColor) color mode
-                       write_xr(0x82, 0x00);           // disable palettes
+                       write_cr(0x13, 200);            // Set line length (doublewords)
+                       write_xr(0x81, 0x14);           // 15 bit (555) color mode
+                       write_xr(0x82, 0x00);           // Disable palettes
                        write_xr(0x20, 0x10);           // 16 bit blitter mode
                }
 
                fix->line_length = 800*2;
-               fix->visual = FB_VISUAL_DIRECTCOLOR;
+               fix->visual = FB_VISUAL_TRUECOLOR;
 
                var->red.offset = 10;
                var->green.offset = 5;
@@ -378,7 +378,7 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in
 #endif
        } else if (bpp == 8) {
                if (con == currcon) {
-                       write_cr(0x13, 100);            // 8 bit display width (decimal)
+                       write_cr(0x13, 100);            // Set line length (doublewords)
                        write_xr(0x81, 0x12);           // 8 bit color mode
                        write_xr(0x82, 0x08);           // Graphics gamma enable
                        write_xr(0x20, 0x00);           // 8 bit blitter mode
@@ -402,7 +402,7 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in
        disp->visual = fix->visual;
        disp->var = *var;
 
-#ifdef CONFIG_PMAC_PBOOK
+#if (defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_FB_COMPAT_XPMAC))
        display_info.depth = bpp;
        display_info.pitch = fix->line_length;
 #endif
@@ -549,9 +549,17 @@ __initfunc(static void init_chips(struct fb_info_chips *p))
        int i;
 
        strcpy(p->fix.id, "C&T 65550");
-       p->fix.smem_start = (char *) p->chips_base_phys;
-       p->fix.smem_len = 800 * 600;
-       p->fix.mmio_start = (char *) p->chips_io_phys;
+       p->fix.smem_start = (char *) p->frame_buffer_phys;
+
+// FIXME: Assumes 1MB frame buffer, but 65550 supports 1MB or 2MB.
+// * "3500" PowerBook G3 (the original PB G3) has 2MB.
+// * 2400 has 1MB composed of 2 Mitsubishi M5M4V4265CTP DRAM chips.
+//   Motherboard actually supports 2MB -- there are two blank locations
+//   for a second pair of DRAMs.  (Thanks, Apple!)
+// * 3400 has 1MB (I think).  Don't know if it's expandable.
+// -- Tim Seufert
+       p->fix.smem_len = 0x100000;     // 1MB
+       p->fix.mmio_start = (char *) p->io_base_phys;
        p->fix.type = FB_TYPE_PACKED_PIXELS;
        p->fix.visual = FB_VISUAL_PSEUDOCOLOR;
        p->fix.line_length = 800;
@@ -574,7 +582,7 @@ __initfunc(static void init_chips(struct fb_info_chips *p))
        p->disp.cmap.green = NULL;
        p->disp.cmap.blue = NULL;
        p->disp.cmap.transp = NULL;
-       p->disp.screen_base = (char *) p->frame_buffer;
+       p->disp.screen_base = p->frame_buffer;
        p->disp.visual = p->fix.visual;
        p->disp.type = p->fix.type;
        p->disp.type_aux = p->fix.type_aux;
@@ -589,7 +597,7 @@ __initfunc(static void init_chips(struct fb_info_chips *p))
        p->info.disp = &p->disp;
        p->info.fontname[0] = 0;
        p->info.changevar = NULL;
-       p->info.switch_con = &chipsfb_switch;
+       p->info.switch_con = &chipsfbcon_switch;
        p->info.updatevar = &chipsfb_updatevar;
        p->info.blank = &chipsfb_blank;
        p->info.flags = FBINFO_FLAG_DEFAULT;
@@ -606,7 +614,8 @@ __initfunc(static void init_chips(struct fb_info_chips *p))
                return;
        }
 
-       printk("fb%d: Chips 65550 frame buffer\n", GET_FB_IDX(p->info.node));
+       printk("fb%d: Chips 65550 frame buffer (%dK RAM detected)\n",
+               GET_FB_IDX(p->info.node), p->fix.smem_len / 1024);
 
        chips_hw_init(p);
 
@@ -619,10 +628,10 @@ __initfunc(static void init_chips(struct fb_info_chips *p))
                display_info.mode = VMODE_800_600_60;
                strncpy(display_info.name, "chips65550",
                        sizeof(display_info.name));
-               display_info.fb_address = p->chips_base_phys + 0x800000;
-               display_info.cmap_adr_address = p->chips_io_phys + 0x3c8;
-               display_info.cmap_data_address = p->chips_io_phys + 0x3c9;
-               display_info.disp_reg_address = p->chips_base_phys + 0xc00000;
+               display_info.fb_address = p->frame_buffer_phys;
+               display_info.cmap_adr_address = p->io_base_phys + 0x3c8;
+               display_info.cmap_data_address = p->io_base_phys + 0x3c9;
+               display_info.disp_reg_address = p->blitter_regs_phys;
                console_fb_info = &p->info;
        }
 #endif /* CONFIG_FB_COMPAT_XPMAC */
@@ -661,17 +670,23 @@ __initfunc(void chips_of_init(struct device_node *dp))
                return;
        memset(p, 0, sizeof(*p));
        addr = dp->addrs[0].address;
-       p->chips_base_phys = addr;
-       p->frame_buffer = __ioremap(addr+0x800000, 0x100000, _PAGE_NO_CACHE);
-       p->blitter_regs = ioremap(addr + 0xC00000, 0x1000);
+#ifdef __BIG_ENDIAN
+       addr += 0x800000;       // Use big-endian aperture
+#endif
+       p->frame_buffer_phys = addr;
+       p->frame_buffer = __ioremap(addr, 0x200000, _PAGE_NO_CACHE);
+       p->blitter_regs_phys = addr + 0x400000;
+       p->blitter_regs = ioremap(addr + 0x400000, 0x1000);
+       p->blitter_data_phys = addr + 0x410000;
+       p->blitter_data = ioremap(addr + 0x410000, 0x10000);
 
        if (pci_device_loc(dp, &bus, &devfn) == 0) {
                pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
                cmd |= 3;       /* enable memory and IO space */
                pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
-               p->io_base = (unsigned char *) pci_io_base(bus);
+               p->io_base = (__u8 *) pci_io_base(bus);
                /* XXX really want the physical address here */
-               p->chips_io_phys = (unsigned long) pci_io_base(bus);
+               p->io_base_phys = (unsigned long) pci_io_base(bus);
        }
 
        /* Clear the entire framebuffer */
index 42f72a33a904f6606aa74be4351b58f37277f09d..b658e96cfe39726442450bde8b70974b3e8e173d 100644 (file)
@@ -2,9 +2,9 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique and G200
  *
- * (c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.8 1998/12/11
+ * Version: 1.9 1999/01/04
  *
  * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
  *
@@ -4841,7 +4841,7 @@ static int nopan = 0;                     /* "matrox:nopan" */
 static int no_pci_retry = 0;           /* "matrox:nopciretry" */
 static int novga = 0;                  /* "matrox:novga" */
 static int nobios = 0;                 /* "matrox:nobios" */
-static int noinit = 0;                 /* "matrox:noinit" */
+static int noinit = 1;                 /* "matrox:noinit" */
 static int inverse = 0;                        /* "matrox:inverse" */
 static int hwcursor = 1;               /* "matrox:nohwcursor" */
 static int blink = 1;                  /* "matrox:noblink" */
index bafcc23bc4bc93849a7965d01ee2c27a89f249ed..8a78f6524007f1daddd9e59c8274f2eb00ec663d 100644 (file)
@@ -68,7 +68,6 @@ struct fb_info_offb {
 
 static int ofonly = 0;
 
-
     /*
      *  Interface used by the world
      */
@@ -251,8 +250,10 @@ static int offb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
     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(1<<fb_display[con].var.bits_per_pixel),
-                    cmap, kspc ? 0 : 2);
+    {
+       int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+       fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+    }
     return 0;
 }
 
@@ -270,8 +271,8 @@ static int offb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        return -ENOSYS;
 
     if (!fb_display[con].cmap.len) {   /* no colormap allocated? */
-       if ((err = fb_alloc_cmap(&fb_display[con].cmap,
-                                1<<fb_display[con].var.bits_per_pixel, 0)))
+       int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+       if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
            return err;
     }
     if (con == currcon)                        /* current console? */
@@ -522,18 +523,20 @@ __initfunc(static void offb_init_fb(const char *name, const char *full_name,
     fix->type = FB_TYPE_PACKED_PIXELS;
     fix->type_aux = 0;
 
-       /* XXX kludge for ati */
-    if (strncmp(name, "ATY,", 4) == 0) {
-       unsigned long base = address & 0xff000000UL;
-       info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
-       info->cmap_data = info->cmap_adr + 1;
-    }
-
     if (depth == 8)
-       fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
+    {
+       /* XXX kludge for ati */
+       if (strncmp(name, "ATY,", 4) == 0) {
+               unsigned long base = address & 0xff000000UL;
+               info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
+               info->cmap_data = info->cmap_adr + 1;
+       }
+        fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
                                     : FB_VISUAL_STATIC_PSEUDOCOLOR;
+    }
     else
-       fix->visual = FB_VISUAL_TRUECOLOR;
+       fix->visual = /*info->cmap_adr ? FB_VISUAL_DIRECTCOLOR
+                                    : */FB_VISUAL_TRUECOLOR;
 
     var->xoffset = var->yoffset = 0;
     var->bits_per_pixel = depth;
@@ -611,10 +614,14 @@ __initfunc(static void offb_init_fb(const char *name, const char *full_name,
             disp->dispsw = &fbcon_cfb16;
             disp->dispsw_data = info->fbcon_cmap.cfb16;
             for (i = 0; i < 16; i++)
-               info->fbcon_cmap.cfb16[i] =
-                   (((default_blu[i] >> 3) & 0x1f) << 10) |
-                   (((default_grn[i] >> 3) & 0x1f) << 5) |
-                   ((default_red[i] >> 3) & 0x1f);
+               if (fix->visual == FB_VISUAL_TRUECOLOR)
+                   info->fbcon_cmap.cfb16[i] =
+                           (((default_blu[i] >> 3) & 0x1f) << 10) |
+                           (((default_grn[i] >> 3) & 0x1f) << 5) |
+                           ((default_red[i] >> 3) & 0x1f);
+               else
+                   info->fbcon_cmap.cfb16[i] =
+                           (i << 10) | (i << 5) | i;
             break;
 #endif
 #ifdef FBCON_HAS_CFB32
@@ -622,9 +629,14 @@ __initfunc(static void offb_init_fb(const char *name, const char *full_name,
             disp->dispsw = &fbcon_cfb32;
             disp->dispsw_data = info->fbcon_cmap.cfb32;
             for (i = 0; i < 16; i++)
-               info->fbcon_cmap.cfb32[i] = (default_blu[i] << 16) |
-                                           (default_grn[i] << 8) |
-                                           default_red[i];
+               if (fix->visual == FB_VISUAL_TRUECOLOR)
+                   info->fbcon_cmap.cfb32[i] =
+                       (default_blu[i] << 16) |
+                       (default_grn[i] << 8) |
+                       default_red[i];
+               else
+                   info->fbcon_cmap.cfb32[i] =
+                           (i << 16) | (i << 8) | i;
             break;
 #endif
         default:
@@ -791,7 +803,7 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
     info2->palette[regno].green = green;
     info2->palette[regno].blue = blue;
 
-    *info2->cmap_adr = regno;
+    *info2->cmap_adr = regno;/* On some chipsets, add << 3 in 15 bits */
     mach_eieio();
     *info2->cmap_data = red;
     mach_eieio();
@@ -804,8 +816,7 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        switch (info2->var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB16
            case 16:
-               info2->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) |
-                                                regno;
+               info2->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno;
                break;
 #endif
 #ifdef FBCON_HAS_CFB32
@@ -827,8 +838,10 @@ static void do_install_cmap(int con, struct fb_info *info)
     if (fb_display[con].cmap.len)
        fb_set_cmap(&fb_display[con].cmap, 1, offb_setcolreg, info);
     else
-       fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-                                   1, offb_setcolreg, info);
+    {
+       int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+       fb_set_cmap(fb_default_cmap(size), 1, offb_setcolreg, info);
+    }
 }
 
 
index ba950b0838906ed251872f7eea2c82a872af8c6c..412fef04ffb65e19502888d03503fcedcb41a09e 100644 (file)
@@ -22,12 +22,15 @@ dep_tristate '  VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
 tristate 'ISO 9660 CDROM filesystem support' CONFIG_ISO9660_FS
 if [ "$CONFIG_ISO9660_FS" != "n" ]; then
   bool 'Microsoft Joliet CDROM extensions' CONFIG_JOLIET
+else
+  # needed by nls/Config.in
+  define_bool CONFIG_JOLIET n
 fi
 
 tristate 'Minix fs support' CONFIG_MINIX_FS
 tristate 'NTFS filesystem support (read only)' CONFIG_NTFS_FS
 if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool '   NTFS read-write support (experimental)' CONFIG_NTFS_RW
+  bool '   NTFS read-write support (DANGEROUS)' CONFIG_NTFS_RW
 fi
 tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 bool '/proc filesystem support' CONFIG_PROC_FS
@@ -44,8 +47,12 @@ tristate 'ROM filesystem support' CONFIG_ROMFS_FS
 tristate 'Second extended fs support' CONFIG_EXT2_FS
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
 tristate 'UFS filesystem support' CONFIG_UFS_FS
+if [ "$CONFIG_UFS_FS" != "n" ]; then
+  bool '   UFS filesystem write support (experimental)' CONFIG_UFS_FS_WRITE
+fi
 
 
+if [ "$CONFIG_NET" = "y" ]; then
 
 mainmenu_option next_comment
 comment 'Network File Systems'
@@ -87,6 +94,7 @@ if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
 fi
 
 endmenu
+fi
 
 if [ "$CONFIG_AFFS_FS" != "n" ]; then
   define_bool CONFIG_AMIGA_PARTITION y
index 3644d393077b2abffc5f7cc87974c7f3965009b3..99a8b9b1a9b649c16607f1b99da18c1869bde591 100644 (file)
@@ -76,8 +76,6 @@ static int nr_buffers = 0;
 static int nr_buffers_type[NR_LIST] = {0,};
 static int nr_buffer_heads = 0;
 static int nr_unused_buffer_heads = 0;
-static int refilled = 0;       /* Set NZ when a buffer freelist is refilled 
-                                 this is used by the loop device */
 
 /* This is used by some architectures to estimate available memory. */
 int buffermem = 0;
@@ -113,8 +111,8 @@ union bdflush_param{
 } bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
 
 /* These are the min and max parameter values that we will allow to be assigned */
-int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   100,   100, 1, 1};
-int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 60000, 60000, 2047, 5};
+int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   1*HZ, 1, 1};
+int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 600*HZ, 600*HZ, 2047, 5};
 
 void wakeup_bdflush(int);
 
@@ -1607,7 +1605,7 @@ void wakeup_bdflush(int wait)
  * and superblocks so that we could write back only the old ones as well
  */
 
-asmlinkage int sync_old_buffers(void)
+static int sync_old_buffers(void)
 {
        int i;
        int ndirty, nwritten;
@@ -1774,7 +1772,6 @@ int bdflush(void * unused)
 #endif
                 {
                         ndirty = 0;
-                        refilled = 0;
                 repeat:
 
                         bh = lru_list[nlist];
@@ -1801,8 +1798,6 @@ int bdflush(void * unused)
                                          major = MAJOR(bh->b_dev);
                                          /* Should we write back buffers that are shared or not??
                                             currently dirty buffers are not shared, so it does not matter */
-                                         if (refilled && major == LOOP_MAJOR)
-                                                  continue;
                                          next->b_count++;
                                          bh->b_count++;
                                          ndirty++;
index 89140d928757b94eb455246fad24105c5ca2e2b0..6f676d46d1543161fa1cf79b74b99aef26cb1f70 100644 (file)
@@ -190,9 +190,9 @@ int d_invalidate(struct dentry * dentry)
 int select_dcache(int inode_count, int page_count)
 {
        struct list_head *next, *tail = &dentry_unused;
-       int found = 0, forward = 0, young = 8;
+       int found = 0;
        int depth = dentry_stat.nr_unused >> 1;
-       unsigned long min_value = 0, max_value = 4;
+       unsigned long max_value = 4;
 
        if (page_count)
                max_value = -1;
@@ -205,39 +205,12 @@ int select_dcache(int inode_count, int page_count)
                unsigned long value = 0;        
 
                next = tmp->prev;
-               if (forward)
-                       next = tmp->next;
                if (dentry->d_count) {
                        dentry_stat.nr_unused--;
                        list_del(tmp);
                        INIT_LIST_HEAD(tmp);
                        continue;
                }
-               /*
-                * Check the dentry's age to see whether to change direction.
-                */
-               if (!forward) {
-                       int age = (jiffies - dentry->d_reftime) / HZ;
-                       if (age < dentry_stat.age_limit) {
-                               if (!--young) {
-                                       forward = 1;
-                                       next = dentry_unused.next;
-                                       /*
-                                        * Update the limits -- we don't want
-                                        * files with too few or too many pages.
-                                        */
-                                       if (page_count) {
-                                               min_value = 3;
-                                               max_value = 15;
-                                       }
-#ifdef DCACHE_DEBUG
-printk("select_dcache: %s/%s age=%d, scanning forward\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, age);
-#endif
-                               }
-                               continue;
-                       }
-               } 
 
                /*
                 * Select dentries based on the page cache count ...
@@ -247,7 +220,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, age);
                 */
                if (inode) {
                        value = inode->i_nrpages;       
-                       if (value >= max_value || value < min_value)
+                       if (value >= max_value)
                                continue;
                        if (inode->i_state || inode->i_count > 1)
                                continue;
index bc67350cec9bc6dd333d741515af966d5fd059c5..e018eb880c6c5ae895920f62ca547b139637acef 100644 (file)
@@ -243,16 +243,16 @@ static int parse_options(char *options,int *fat, int *blksize, int *debug,
                                        ret = 0;
                        }
                }
-                else if (!strcmp(this_char,"cvf_format")) {
-                        if (!value)
-                                return 0;
-                        strncpy(cvf_format,value,20);
-                }
-                else if (!strcmp(this_char,"cvf_options")) {
-                        if (!value)
-                                return 0;
-                        strncpy(cvf_options,value,100);
-                }
+               else if (!strcmp(this_char,"cvf_format")) {
+                       if (!value)
+                               return 0;
+                       strncpy(cvf_format,value,20);
+               }
+               else if (!strcmp(this_char,"cvf_options")) {
+                       if (!value)
+                               return 0;
+                       strncpy(cvf_options,value,100);
+               }
 
                if (this_char != options) *(this_char-1) = ',';
                if (value) *savep = save;
@@ -302,7 +302,7 @@ fat_read_super(struct super_block *sb, void *data, int silent)
 
        opts.isvfat = MSDOS_SB(sb)->options.isvfat;
        if (!parse_options((char *) data, &fat, &blksize, &debug, &opts, 
-                          cvf_format, cvf_options)
+                          cvf_format, cvf_options)
            || (blksize != 512 && blksize != 1024 && blksize != 2048))
                goto out_fail;
        /* N.B. we should parse directly into the sb structure */
@@ -364,8 +364,8 @@ fat_read_super(struct super_block *sb, void *data, int silent)
                MSDOS_SB(sb)->root_cluster = CF_LE_L(b->root_cluster);
                MSDOS_SB(sb)->fsinfo_offset =
                        CF_LE_W(b->info_sector) * logical_sector_size + 0x1e0;
-               if (MSDOS_SB(sb)->fsinfo_offset + sizeof(MSDOS_SB(sb)->fsinfo_offset) > sb->s_blocksize) {
-                       printk("fat_read_super: Bad fsinfo_offset 0x%x\n", MSDOS_SB(sb)->fsinfo_offset);
+               if (MSDOS_SB(sb)->fsinfo_offset + sizeof(struct fat_boot_fsinfo) > sb->s_blocksize) {
+                       printk("fat_read_super: Bad fsinfo_offset\n");
                        fat_brelse(sb, bh);
                        goto out_invalid;
                }
@@ -524,10 +524,10 @@ int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
        int free,nr;
        struct statfs tmp;
        
-        if (MSDOS_SB(sb)->cvf_format &&
+       if (MSDOS_SB(sb)->cvf_format &&
            MSDOS_SB(sb)->cvf_format->cvf_statfs)
                return MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,bufsiz);
-          
+         
        lock_fat(sb);
        if (MSDOS_SB(sb)->free_clusters != -1)
                free = MSDOS_SB(sb)->free_clusters;
index e1fae751e300f7741f4bbed804f721fe29f9c1ce..1a9bd3456beb47a95e8c1a2ff338dd8198787a94 100644 (file)
@@ -147,12 +147,8 @@ static inline void sync_one(struct inode *inode)
                __wait_on_inode(inode);
                spin_lock(&inode_lock);
        } else {
-               struct list_head *insert = &inode_in_use;
-               if (!inode->i_count)
-                       insert = inode_in_use.prev;
                list_del(&inode->i_list);
-               list_add(&inode->i_list, insert);
-
+               list_add(&inode->i_list, &inode_in_use);
                /* Set I_LOCK, reset I_DIRTY */
                inode->i_state ^= I_DIRTY | I_LOCK;
                spin_unlock(&inode_lock);
@@ -705,7 +701,7 @@ void iput(struct inode *inode)
                        }
                        else if (!(inode->i_state & I_DIRTY)) {
                                list_del(&inode->i_list);
-                               list_add(&inode->i_list, inode_in_use.prev);
+                               list_add(&inode->i_list, &inode_in_use);
                        }
 #ifdef INODE_PARANOIA
 if (inode->i_flock)
index b1edd0953550110a702cd823fc058e4898eb0c1d..a9be4b80267f91ddead83fc26ff93bfd4f4f6b04 100644 (file)
@@ -71,12 +71,7 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp)
         * a 1 minute timeout would do. See the comment before
         * nlmclnt_lock for an explanation.
         */
-       /*
-        * FIXME, can we be not interruptible and so be allowed to use
-        * a timeout here? -arca
-        */
-/*     current->timeout = jiffies + 30 * HZ; */
-       sleep_on(&block.b_wait);
+       sleep_on_timeout(&block.b_wait, 30*HZ);
 
        for (head = &nlm_blocked; *head; head = &(*head)->b_next) {
                if (*head == &block) {
index 9689f815820d3439fdd86253d25b456d1a25ba38..72130244aee5cfb95ed3339a58866b924c87af82 100644 (file)
@@ -474,7 +474,7 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
         * unhashed inode to avoid aliasing problems.
         */
        if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) ||
-           (IS_ROOT(dentry->d_parent) && dentry->d_name.len == 9 &&
+           (dentry->d_name.len == 9 &&
             memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
                struct inode *inode = get_empty_inode();
                if (!inode)
index 13af76aba5e191b926f9e9fd5b4f8b459d983768..32d382d5742f517dce1cb347e9b9d09048dd46de 100644 (file)
@@ -71,7 +71,7 @@
 #define NTFS_PUTU64(p,v)     ((*(ntfs_u64*)(p))=CPU_TO_LE64(v))
  
  /* Macros reading signed integers */
-#define NTFS_GETS8(p)        ((*(ntfs_u8*)(p)))
+#define NTFS_GETS8(p)        ((*(ntfs_s8*)(p)))
 #define NTFS_GETS16(p)       ((ntfs_s16)LE16_TO_CPU(*(short*)(p)))
 #define NTFS_GETS24(p)       (NTFS_GETU24(p) < 0x800000 ? (int)NTFS_GETU24(p) : (int)(NTFS_GETU24(p) - 0x1000000))
 #define NTFS_GETS32(p)       ((ntfs_s32)LE32_TO_CPU(*(int*)(p)))
index 8eef1f77adb03526156b844c17a3639f599312af..ad3e5cf08c48b7996f43590480d016ddec1f5f99 100644 (file)
@@ -1397,6 +1397,7 @@ static int process_unauthorized(int type, int pid)
                case PROC_PID_STAT:
                case PROC_PID_MAPS:
                case PROC_PID_CMDLINE:
+               case PROC_PID_CPU:
                        return 0;       
        }
        if(capable(CAP_DAC_OVERRIDE) || current->fsuid == euid)
index 36679c52a575f627484a8cc15fd835b369ab2019..083042d711d6d2d5cc46a68bd915c7425d6aa982 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/uaccess.h>
 
 static int qnx4_readlink(struct dentry *, char *, int);
-static struct dentry *qnx4_follow_link(struct dentry *, struct dentry *);
+static struct dentry *qnx4_follow_link(struct dentry *, struct dentry *, unsigned int follow);
 
 /*
  * symlinks can't do much...
@@ -50,7 +50,7 @@ struct inode_operations qnx4_symlink_inode_operations =
 };
 
 static struct dentry *qnx4_follow_link(struct dentry *dentry,
-                                      struct dentry *base)
+                                      struct dentry *base, unsigned int follow)
 {
 #if 0
        struct inode *inode = dentry->d_inode;
index 2b67683527b64b36133540d00b38d7b2897eb387..b002d33987856d4a980de835319a14cea7cf81a6 100644 (file)
@@ -58,8 +58,11 @@ int ufs_permission (struct inode * inode, int mask)
         * Access is always granted for root. We now check last,
         * though, for BSD process accounting correctness
         */
-       if (((mode & mask & S_IRWXO) == mask) || fsuser())
+       if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
                return 0;
-       else
-               return -EACCES;
+       if ((mask == S_IROTH) ||
+           (S_ISDIR(mode)  && !(mask & ~(S_IROTH | S_IXOTH))))
+               if (capable(CAP_DAC_READ_SEARCH))
+                       return 0;
+       return -EACCES;
 }
index c20f2293ec10175419cf44a2c6faa871c81acd33..0cb8ac00022d51348e156f7de1c12204ae8afa6e 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/stat.h>
 #include <linux/string.h>
 #include <linux/locks.h>
+#include <linux/quotaops.h>
 
 #include "swab.h"
 #include "util.h"
 #define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
 
 /*
- * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure.
+ * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
+ *
+ * Len <= UFS_MAXNAMLEN' is guaranteed by caller.
+ * De != NULL' is guaranteed by caller.
  */
-static int ufs_match (int len, const char * const name,
+static inline int ufs_match (int len, const char * const name,
        struct ufs_dir_entry * de, unsigned flags, unsigned swab)
 {
-       if (!de || !SWAB32(de->d_ino) || len > UFS_MAXNAMLEN)
-               return 0;
-       /*
-        * "" means "." ---> so paths like "/usr/lib//libc.a" work
-        */
-       if (!len && ufs_get_de_namlen(de) == 1 && (de->d_name[0] == '.') &&
-          (de->d_name[1] == '\0'))
-               return 1;
        if (len != ufs_get_de_namlen(de))
                return 0;
+       if (!de->d_ino)
+               return 0;
        return !memcmp(name, de->d_name, len);
 }
 
@@ -128,8 +126,9 @@ static struct buffer_head * ufs_find_entry (struct inode * dir,
                }
                bh = bh_use[block % NAMEI_RA_SIZE];
                if (!bh) {
-                       ufs_error (sb, "ufs_find_entry",
-                               "directory #%lu contains a hole at offset %lu", dir->i_ino, offset);
+                       ufs_error (sb, "ufs_find_entry", 
+                               "directory #%lu contains a hole at offset %lu",
+                               dir->i_ino, offset);
                        offset += sb->s_blocksize;
                        continue;
                }
@@ -144,20 +143,30 @@ static struct buffer_head * ufs_find_entry (struct inode * dir,
                de = (struct ufs_dir_entry *) bh->b_data;
                dlimit = bh->b_data + sb->s_blocksize;
                while ((char *) de < dlimit && offset < dir->i_size) {
-                       if (!ufs_check_dir_entry ("ufs_find_entry", dir, de, bh, offset))
-                               goto failed;
-                       if (SWAB32(de->d_ino) != 0 && ufs_match (namelen, name, de, flags, swab)) {
+                       /* this code is executed quadratically often */
+                       /* do minimal checking by hand' */
+                       int de_len;
+
+                       if ((char *) de + namelen <= dlimit &&
+                           ufs_match (namelen, name, de, flags, swab)) {
+                               /* found a match -
+                               just to be sure, do a full check */
+                               if (!ufs_check_dir_entry("ufs_find_entry",
+                                   dir, de, bh, offset))
+                                       goto failed;
                                for (i = 0; i < NAMEI_RA_SIZE; ++i) {
                                        if (bh_use[i] != bh)
                                                brelse (bh_use[i]);
                                }
                                *res_dir = de;
-                               UFSD(("EXIT\n"))
                                return bh;
                        }
-                       offset += SWAB16(de->d_reclen);
-                       de = (struct ufs_dir_entry *)
-                               ((char *) de + SWAB16(de->d_reclen));
+                        /* prevent looping on a bad block */
+                       de_len = SWAB16(de->d_reclen);
+                       if (de_len <= 0)
+                               goto failed;
+                       offset += de_len;
+                       de = (struct ufs_dir_entry *) ((char *) de + de_len);
                }
 
                brelse (bh);
@@ -173,7 +182,7 @@ static struct buffer_head * ufs_find_entry (struct inode * dir,
 
 failed:
        for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]);
-       UFSD(("EXIT (FAILED)\n"))
+       UFSD(("EXIT\n"))
        return NULL;
 }
 
@@ -298,7 +307,7 @@ static struct buffer_head * ufs_add_entry (struct inode * dir,
                        brelse (bh);
                        return NULL;
                }
-               if (SWAB32(de->d_ino) != 0 && ufs_match (namelen, name, de, flags, swab)) {
+               if (ufs_match (namelen, name, de, flags, swab)) {
                                *err = -EEXIST;
                                brelse (bh);
                                return NULL;
@@ -673,8 +682,7 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry)
                goto end_rmdir;
 
        inode = dentry->d_inode;
-       if (inode->i_sb->dq_op)
-               inode->i_sb->dq_op->initialize (inode, -1);
+       DQUOT_INIT(inode);
 
        retval = -EIO;
        if (SWAB32(de->d_ino) != inode->i_ino)
@@ -741,8 +749,7 @@ int ufs_unlink(struct inode * dir, struct dentry *dentry)
                goto end_unlink;
 
        inode = dentry->d_inode;
-       if (inode->i_sb->dq_op)
-               inode->i_sb->dq_op->initialize (inode, -1);
+       DQUOT_INIT(inode);
 
        retval = -EIO;
        if (SWAB32(de->d_ino) != inode->i_ino)
@@ -778,49 +785,6 @@ out:
 }
 
 
-int ufs_link (struct dentry * old_dentry, struct inode * dir,
-       struct dentry *dentry)
-{
-       struct super_block * sb;
-       struct inode *inode = old_dentry->d_inode;
-       struct ufs_dir_entry * de;
-       struct buffer_head * bh;
-       int err;
-       unsigned swab;
-
-       inode = old_dentry->d_inode;
-       sb = inode->i_sb;
-       swab = sb->u.ufs_sb.s_swab;
-       
-       if (S_ISDIR(inode->i_mode))
-               return -EPERM;
-
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               return -EPERM;
-
-       if (inode->i_nlink >= UFS_LINK_MAX)
-               return -EMLINK;
-
-       bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
-       if (!bh)
-               return err;
-
-       de->d_ino = SWAB32(inode->i_ino);
-       dir->i_version = ++event;
-       mark_buffer_dirty(bh, 1);
-       if (IS_SYNC(dir)) {
-               ll_rw_block (WRITE, 1, &bh);
-               wait_on_buffer (bh);
-       }
-       brelse (bh);
-       inode->i_nlink++;
-       inode->i_ctime = CURRENT_TIME;
-       mark_inode_dirty(inode);
-       inode->i_count++;
-       d_instantiate(dentry, inode);
-       return 0;
-}
-
 /*
  * Create symbolic link. We use only slow symlinks at this time.
  */
@@ -901,6 +865,49 @@ out_no_entry:
        goto out;
 }
 
+int ufs_link (struct dentry * old_dentry, struct inode * dir,
+       struct dentry *dentry)
+{
+       struct super_block * sb;
+       struct inode *inode = old_dentry->d_inode;
+       struct ufs_dir_entry * de;
+       struct buffer_head * bh;
+       int err;
+       unsigned swab;
+
+       inode = old_dentry->d_inode;
+       sb = inode->i_sb;
+       swab = sb->u.ufs_sb.s_swab;
+       
+       if (S_ISDIR(inode->i_mode))
+               return -EPERM;
+
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               return -EPERM;
+
+       if (inode->i_nlink >= UFS_LINK_MAX)
+               return -EMLINK;
+
+       bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+       if (!bh)
+               return err;
+
+       de->d_ino = SWAB32(inode->i_ino);
+       dir->i_version = ++event;
+       mark_buffer_dirty(bh, 1);
+       if (IS_SYNC(dir)) {
+               ll_rw_block (WRITE, 1, &bh);
+               wait_on_buffer (bh);
+       }
+       brelse (bh);
+       inode->i_nlink++;
+       inode->i_ctime = CURRENT_TIME;
+       mark_inode_dirty(inode);
+       inode->i_count++;
+       d_instantiate(dentry, inode);
+       return 0;
+}
+
 
 #define PARENT_INO(buffer) \
        ((struct ufs_dir_entry *) ((char *) buffer + \
@@ -939,27 +946,26 @@ static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
        if (old_dentry->d_name.len > UFS_MAXNAMLEN)
                goto end_rename;
 
-       UFSD(("name %s, len %u\n", old_dentry->d_name.name, old_dentry->d_name.len)) 
        old_bh = ufs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
-       UFSD(("ino %u, reclen %u, namlen %u, name %s\n", SWAB32(old_de->d_ino),
-               SWAB16(old_de->d_reclen), ufs_get_de_namlen(old_de), old_de->d_name))
-
-       /* Arrrgh. See comments in ext2 */
+       /*
+        *  Check for inode number is _not_ due to possible IO errors.
+        *  We might rmdir the source, keep it as pwd of some process
+        *  and merrily kill the link to whatever was created under the
+        *  same name. Goodbye sticky bit ;-<
+        */
        retval = -ENOENT;
+       old_inode = old_dentry->d_inode;
        if (!old_bh || SWAB32(old_de->d_ino) != old_inode->i_ino)
                goto end_rename;
-       old_inode = old_dentry->d_inode;
 
        new_inode = new_dentry->d_inode;
-       UFSD(("name %s, len %u\n", new_dentry->d_name.name, new_dentry->d_name.len)) 
        new_bh = ufs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de);
        if (new_bh) {
                if (!new_inode) {
                        brelse (new_bh);
                        new_bh = NULL;
                } else {
-                       if (new_inode->i_sb->dq_op)
-                               new_inode->i_sb->dq_op->initialize (new_inode, -1);
+                       DQUOT_INIT(new_inode);
                }
        }
        retval = 0;
@@ -970,6 +976,7 @@ static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
                if (is_subdir(new_dentry, old_dentry))
                        goto end_rename;
                if (new_inode) {
+                       /* Prune any children before testing for busy */
                        if (new_dentry->d_count > 1)
                                shrink_dcache_parent(new_dentry);
                        retval = -EBUSY;
index dd481546997b7f6bda3112265db37ae2ccba8ea1..d08e51e80b9b85ab05eda530688258e5c8bcd4ca 100644 (file)
@@ -449,6 +449,9 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
        MOD_INC_USE_COUNT;
        lock_super (sb);
 
+#ifndef CONFIG_UFS_FS_WRITE
+       sb->s_flags |= MS_RDONLY;
+#endif
        /*
         * Set default mount options
         * Parse mount options
@@ -527,9 +530,6 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
                goto failed;
        }
        
-       if (!(sb->s_flags & MS_RDONLY))
-               printk("!!! warning !!! write support of ufs is still in experimental state\n"); 
-
 again: 
        set_blocksize (sb->s_dev, block_size);
 
index c77443e84b59eb3e31cb89f4a49773ed3639de78..87043b4447bc880d93e5d71859fd46b7dc33b50c 100644 (file)
@@ -1549,8 +1549,10 @@ int vfat_rmdir(struct inode *dir,struct dentry* dentry)
        res = -EBUSY;
        if (list_empty(&dentry->d_hash)) {
                res = vfat_rmdirx(dir, dentry);
-               if (res >= 0)
+               if (res >= 0) {
                        drop_replace_inodes(dentry, NULL);
+                       d_delete(dentry);
+               }
        }
        return res;
 }
index 9d366561ab00d5c33af9e2fc34433c379ab3b182..2ac7af4eb96fc4b59e5a16a8e6882d97a00a64df 100644 (file)
@@ -15,6 +15,9 @@
 #define __FINIT                .previous
 #define __INITDATA     .section        ".data.init",#alloc,#write
 
+#define __cacheline_aligned __attribute__ \
+                        ((__section__ (".data.cacheline_aligned")))
+
 #else
 
 /* gdb doesn't like it all if the code for one source file isn't together in
@@ -27,6 +30,7 @@
 #define __INIT
 #define __FINIT
 #define __INITDATA
+#define __cacheline_aligned
 
 #endif /* CONFIG_KGDB */
        
index f94ce2708dfb318226f9f9057bff1c690ef256f4..09ae4cfd25fbfc40ec2834502c76131dde185d43 100644 (file)
@@ -25,7 +25,7 @@
   {LONG_MAX, LONG_MAX}, \
   {LONG_MAX, LONG_MAX}, \
   {LONG_MAX, LONG_MAX}, \
-  {_STK_LIM, _STK_LIM}, \
+  {_STK_LIM, LONG_MAX}, \
   {       0, LONG_MAX}, \
   {LONG_MAX, LONG_MAX}, \
   {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \
index 89c786665bf47bbe012ce53a8c01c05a7ac678b3..dc5f567282cb4522e2fe184265b69468c0987be4 100644 (file)
@@ -13,7 +13,7 @@
 extern inline void init_bh(int nr, void (*routine)(void))
 {
        bh_base[nr] = routine;
-       bh_mask_count[nr] = 0;
+       atomic_set(&bh_mask_count[nr], 0);
        bh_mask |= 1 << nr;
 }
 
@@ -29,12 +29,12 @@ extern inline void mark_bh(int nr)
 extern inline void disable_bh(int nr)
 {
        bh_mask &= ~(1 << nr);
-       bh_mask_count[nr]++;
+       atomic_inc(&bh_mask_count[nr]);
 }
 
 extern inline void enable_bh(int nr)
 {
-       if (!--bh_mask_count[nr])
+       if (atomic_dec_and_test(&bh_mask_count[nr]))
                bh_mask |= 1 << nr;
 }
 
index fe5cff581140d0f66937a5365564e53dc5c43624..7a05262f29a1ccf4200bd4c1887c2c6ab5bfd242 100644 (file)
        (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
                << (SHIFT_SCALE-SHIFT_HZ)) / HZ)
 
+typedef unsigned long cycles_t;
+
+static inline cycles_t get_cycles(void)
+{
+       return 0;
+}
+
 #endif
index 115219878de0c7ed5814a1004f42584efc473c1d..aa1b4494fc62255b8b766d88cbd24604819b7a00 100644 (file)
@@ -184,7 +184,7 @@ __generic_copy_from_user(void *to, const void *from, unsigned long n)
         "   .long 5b,9b\n"
         ".previous"
         : "=a"(to), "=a"(from), "=d"(n), "=&d"(tmp)
-        : "r"(n & 3), "0"(to), "1"(from), "2"(n/4)
+        : "d"(n & 3), "0"(to), "1"(from), "2"(n/4)
         : "d0", "memory");
     return n;
 }
index f4662fc3de83fcbe7fd9e4c44345cf671f37d1fc..25c4495980f8a68b52eb86de66aad54eec2d836d 100644 (file)
@@ -76,8 +76,6 @@ extern struct in_device *inetdev_init(struct device *dev);
 extern struct in_device        *inetdev_by_index(int);
 extern u32             inet_select_addr(struct device *dev, u32 dst, int scope);
 extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
-extern int             inet_add_bootp_addr(struct device *dev);
-extern void            inet_del_bootp_addr(struct device *dev);
 extern void            inet_forward_change(void);
 
 extern __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
index ac7ca606eefa185a605f1e315f738c72d725013d..ba89313830234c9b8a39d90ccfd17151e0b4e3cc 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *     IP_MASQ user space control interface
- *     $Id: ip_masq.h,v 1.1 1998/08/29 23:50:56 davem Exp $
+ *     $Id: ip_masq.h,v 1.2 1998/12/08 05:41:48 davem Exp $
  */
 
 #ifndef _LINUX_IP_MASQ_H
@@ -90,16 +90,19 @@ struct ip_portfw_user {
 };
 
 /* 
- *     MARKFW stuff 
+ *     MFW stuff 
  */
-struct ip_markfw_user {
+struct ip_mfw_user {
        u_int32_t           fwmark;     /* Firewalling mark */
        u_int32_t           raddr;      /* remote port */
        u_int16_t           rport;      /* remote port */
        u_int16_t           dummy;          /* Make up to multiple of 4 */
        int             pref;           /* Preference value */
+       unsigned        flags;          /* misc flags */
 };
 
+#define IP_MASQ_MFW_SCHED      0x01
+
 #define IP_FW_MASQCTL_MAX 256
 #define IP_MASQ_TNAME_MAX  32
 
@@ -110,7 +113,7 @@ struct ip_masq_ctl {
        union {
                struct ip_portfw_user portfw_user;
                struct ip_autofw_user autofw_user;
-               struct ip_markfw_user markfw_user;
+               struct ip_mfw_user mfw_user;
                struct ip_masq_user user;
                unsigned char m_raw[IP_FW_MASQCTL_MAX];
        } u;
@@ -123,14 +126,14 @@ struct ip_masq_ctl {
 #define IP_MASQ_TARGET_USER    3       
 #define IP_MASQ_TARGET_LAST    4
 
-#define IP_MASQ_CMD_NONE       0
+#define IP_MASQ_CMD_NONE       0       /* just peek */
 #define IP_MASQ_CMD_INSERT     1
 #define IP_MASQ_CMD_ADD                2
 #define IP_MASQ_CMD_SET                3
 #define IP_MASQ_CMD_DEL                4
 #define IP_MASQ_CMD_GET                5
 #define IP_MASQ_CMD_FLUSH      6
-#define IP_MASQ_CMD_LIST       7
+#define IP_MASQ_CMD_LIST       7       /* actually fake: done via /proc */
 #define IP_MASQ_CMD_ENABLE     8
 #define IP_MASQ_CMD_DISABLE    9
 
index e1d772c00ed77fbacabb29efa616d75d6623de6e..95f519ad4dadc8e7d3409c9412db0b7b6df1ce78 100644 (file)
@@ -130,20 +130,22 @@ typedef struct page {
 #define PG_locked               0
 #define PG_error                1
 #define PG_referenced           2
-#define PG_uptodate             3
-#define PG_free_after           4
-#define PG_decr_after           5
-#define PG_swap_unlock_after    6
-#define PG_DMA                  7
-#define PG_Slab                         8
-#define PG_swap_cache           9
-#define PG_skip                        10
+#define PG_dirty                3
+#define PG_uptodate             4
+#define PG_free_after           5
+#define PG_decr_after           6
+#define PG_swap_unlock_after    7
+#define PG_DMA                  8
+#define PG_Slab                         9
+#define PG_swap_cache          10
+#define PG_skip                        11
 #define PG_reserved            31
 
 /* Make it prettier to test the above... */
 #define PageLocked(page)       (test_bit(PG_locked, &(page)->flags))
 #define PageError(page)                (test_bit(PG_error, &(page)->flags))
 #define PageReferenced(page)   (test_bit(PG_referenced, &(page)->flags))
+#define PageDirty(page)                (test_bit(PG_dirty, &(page)->flags))
 #define PageUptodate(page)     (test_bit(PG_uptodate, &(page)->flags))
 #define PageFreeAfter(page)    (test_bit(PG_free_after, &(page)->flags))
 #define PageDecrAfter(page)    (test_bit(PG_decr_after, &(page)->flags))
@@ -155,12 +157,17 @@ typedef struct page {
 
 #define PageSetSlab(page)      (set_bit(PG_Slab, &(page)->flags))
 #define PageSetSwapCache(page) (set_bit(PG_swap_cache, &(page)->flags))
+
+#define PageTestandSetDirty(page)      \
+                       (test_and_set_bit(PG_dirty, &(page)->flags))
 #define PageTestandSetSwapCache(page)  \
                        (test_and_set_bit(PG_swap_cache, &(page)->flags))
 
 #define PageClearSlab(page)    (clear_bit(PG_Slab, &(page)->flags))
 #define PageClearSwapCache(page)(clear_bit(PG_swap_cache, &(page)->flags))
 
+#define PageTestandClearDirty(page) \
+                       (test_and_clear_bit(PG_dirty, &(page)->flags))
 #define PageTestandClearSwapCache(page)        \
                        (test_and_clear_bit(PG_swap_cache, &(page)->flags))
 
index dbb0289fd756c416775372a7a31575a1095d1a7a..cab27748c86a08be08f92691c8c79925894d6750 100644 (file)
@@ -5,13 +5,17 @@
 struct ntfs_attribute;
 struct ntfs_sb_info;
 
-/* Duplicate definitions from ntfs/types.h */
+/* Duplicate definitions from ntfs/ntfstypes.h */
 #ifndef NTFS_INTEGRAL_TYPES
 #define NTFS_INTEGRAL_TYPES
-typedef unsigned char      ntfs_u8;
-typedef unsigned short     ntfs_u16;
-typedef unsigned int       ntfs_u32;
-typedef unsigned long long ntfs_u64;
+typedef u8  ntfs_u8;
+typedef u16 ntfs_u16;
+typedef u32 ntfs_u32;
+typedef u64 ntfs_u64;
+typedef s8  ntfs_s8;
+typedef s16 ntfs_s16;
+typedef s32 ntfs_s32;
+typedef s64 ntfs_s64;
 #endif
 
 #ifndef NTMODE_T
index 8038b4b98423d10bda8694899775dcf50a06d58d..88f02369eb17e26b97311448942a384d11d184d6 100644 (file)
 
 #define PCI_VENDOR_ID_ADAPTEC2         0x9005
 #define PCI_DEVICE_ID_ADAPTEC2_2940U2  0x0010
+#define PCI_DEVICE_ID_ADAPTEC2_78902   0x0013
 #define PCI_DEVICE_ID_ADAPTEC2_7890    0x001f
 #define PCI_DEVICE_ID_ADAPTEC2_3940U2  0x0050
 #define PCI_DEVICE_ID_ADAPTEC2_3950U2D 0x0051
index 8660f30f5b4ea6ebbe1007171e430ec0b0d6c435..69b6634e31782aaabf2cc7b58e94a7f8f753eaf3 100644 (file)
@@ -458,6 +458,8 @@ extern unsigned long prof_shift;
 
 extern void FASTCALL(__wake_up(struct wait_queue ** p, unsigned int mode));
 extern void FASTCALL(sleep_on(struct wait_queue ** p));
+extern long FASTCALL(sleep_on_timeout(struct wait_queue ** p,
+                                     signed long timeout));
 extern void FASTCALL(interruptible_sleep_on(struct wait_queue ** p));
 extern long FASTCALL(interruptible_sleep_on_timeout(struct wait_queue ** p,
                                                    signed long timeout));
index bc9335801e9b7a80626c32b4e3e0ccf1a3b2f166..4921b90e2cbb2e024fc90a13dddd177c662b609e 100644 (file)
@@ -2,11 +2,11 @@
  *     Sound core interface functions
  */
  
-extern int register_sound_special(struct file_operations *, int);
-extern int register_sound_mixer(struct file_operations *fops);
-extern int register_sound_midi(struct file_operations *fops);
-extern int register_sound_dsp(struct file_operations *fops);
-extern int register_sound_synth(struct file_operations *fops);
+extern int register_sound_special(struct file_operations *fops, int unit);
+extern int register_sound_mixer(struct file_operations *fops, int dev);
+extern int register_sound_midi(struct file_operations *fops, int dev);
+extern int register_sound_dsp(struct file_operations *fops, int dev);
+extern int register_sound_synth(struct file_operations *fops, int dev);
 
 extern void unregister_sound_special(int unit);
 extern void unregister_sound_mixer(int unit);
index 4b7a5ca699dc06135add58928b6b744b93113c64..720fb97c4d1afae9d77da0ed71b5acc2c1bb46c0 100644 (file)
@@ -166,12 +166,7 @@ static inline int is_page_shared(struct page *page)
                return 1;
        count = atomic_read(&page->count);
        if (PageSwapCache(page))
-       {
-               /* PARANOID */
-               if (page->inode != &swapper_inode)
-                       panic("swap cache page has wrong inode\n");
                count += swap_count(page->offset) - 2;
-       }
        if (PageFreeAfter(page))
                count--;
        return  count > 1;
index a976c74693207d198dc7c3c925d364f485165860..413864d4065e4b8027960f44de1764a9ab2f4bfd 100644 (file)
@@ -207,7 +207,8 @@ enum
        NET_IPV4_ICMP_TIMEEXCEED_RATE=61,
        NET_IPV4_ICMP_PARAMPROB_RATE=62,
        NET_IPV4_ICMP_ECHOREPLY_RATE=63,
-       NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64
+       NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64,
+       NET_IPV4_IGMP_MAX_MEMBERSHIPS=65
 };
 
 enum {
index f5f4052d665b9722c8bf661d9f37401facc59ad8..f96c52d04fa1e015425dc73dc9ddd32b46724f86 100644 (file)
@@ -307,7 +307,7 @@ struct wf_layer
     UCHAR8 mute:1;
 
     UCHAR8 split_point:7;
-    UCHAR8 updown:1;
+    UCHAR8 play_below:1;
 
     UCHAR8 pan_mod_src:2;
     UCHAR8 pan_or_mod:1;
@@ -507,9 +507,16 @@ typedef union wf_any {
 
 typedef struct wf_patch_info {
     
+    /* the first two fields are used by the OSS "patch loading" interface
+       only, and are unused by the current user-level library.
+    */
+
     INT16   key;               /* Use WAVEFRONT_PATCH here */
     UINT16  devno;             /* fill in when sending */
     UCHAR8  subkey;            /* WF_ST_{SAMPLE,ALIAS,etc.} */
+
+#define WAVEFRONT_FIND_FREE_SAMPLE_SLOT 999
+
     UINT16  number;            /* patch/sample/prog number */
 
     UINT32  size;              /* size of any data included in 
@@ -548,13 +555,15 @@ typedef struct wf_patch_info {
  */
 
 typedef struct wavefront_control {
-    int devno;                         /* from /dev/sequencer interface */
     int cmd;                           /* WFC_* */
     char status;                       /* return status to user-space */
     unsigned char rbuf[WF_MAX_READ];   /* bytes read from card */
     unsigned char wbuf[WF_MAX_WRITE];  /* bytes written to card */
 } wavefront_control;
 
+#define WFCTL_WFCMD    0x1
+#define WFCTL_LOAD_SPP 0x2
+
 /* Modulator table */
 
 #define WF_MOD_LFO1      0
index db64243a6742ba58a9786e9d6a899f945e3f8fea..f93569461531a84a4361ddae79d54cef6778976b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.h,v 1.2 1997/10/17 12:41:16 mj Exp $
+ *  $Id: ipconfig.h,v 1.3 1999/01/04 20:13:29 davem Exp $
  *
  *  Copyright (C) 1997 Martin Mares
  *
@@ -12,8 +12,10 @@ extern u32 ic_myaddr;
 extern u32 ic_servaddr;
 extern u32 ic_gateway;
 extern u32 ic_netmask;
-extern int ic_bootp_flag;
-extern int ic_rarp_flag;
 extern int ic_enable;
 extern int ic_host_name_set;
 extern int ic_set_manually;
+extern int ic_proto_enabled;
+
+#define IC_BOOTP 1
+#define IC_RARP 2
index dd8576b0cf5be2b54097d5b1f80edabfc85fc504..3fbd14833dd2094bf09c379a289135a25f1a46ee 100644 (file)
@@ -13,8 +13,6 @@
 #include <linux/shm.h>
 #include <linux/init.h>
 #include <linux/msg.h>
-#include <asm/ipc.h>
-#include <asm/uaccess.h>
 
 #if defined(CONFIG_SYSVIPC)
 
index 93b13bac3b84743e683939e7e97b8ff85ffbacc6..fe587fd279df43bada67d639353b4d5233ad6c14 100644 (file)
@@ -106,8 +106,10 @@ EXPORT_SYMBOL(update_vm_cache);
 EXPORT_SYMBOL(vmtruncate);
 
 /* filesystem internal functions */
+EXPORT_SYMBOL(in_group_p);
 EXPORT_SYMBOL(update_atime);
 EXPORT_SYMBOL(get_super);
+EXPORT_SYMBOL(get_fs_type);
 EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(__fput);
 EXPORT_SYMBOL(iget);
@@ -128,6 +130,7 @@ EXPORT_SYMBOL(d_path);
 EXPORT_SYMBOL(__mark_inode_dirty);
 EXPORT_SYMBOL(get_empty_filp);
 EXPORT_SYMBOL(init_private_file);
+EXPORT_SYMBOL(filp_open);
 EXPORT_SYMBOL(fput);
 EXPORT_SYMBOL(put_filp);
 EXPORT_SYMBOL(check_disk_change);
@@ -296,6 +299,7 @@ EXPORT_SYMBOL(release_region);
 /* process management */
 EXPORT_SYMBOL(__wake_up);
 EXPORT_SYMBOL(sleep_on);
+EXPORT_SYMBOL(sleep_on_timeout);
 EXPORT_SYMBOL(interruptible_sleep_on);
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
 EXPORT_SYMBOL(schedule);
index d511160e6284e0cb62aa6231dd7c1965439a69f8..12df4c963f73a867fede1e3c0ab534781ee41063 100644 (file)
@@ -161,8 +161,10 @@ send:
  * In particular, if p1 and p2 both want the kernel
  * lock, there is no point in trying to make them
  * extremely parallel..
+ *
+ * (No lock - lock_depth < 0)
  */
-#define related(p1,p2) ((p1)->lock_depth && (p2)->lock_depth)
+#define related(p1,p2) ((p1)->lock_depth >= 0 && (p2)->lock_depth >= 0)
 
 static inline void reschedule_idle(struct task_struct * p)
 {
@@ -854,56 +856,64 @@ void __up(struct semaphore *sem)
  * Either form may be used in conjunction with "up()".
  *
  */
-static inline int __do_down(struct semaphore * sem, int task_state)
-{
-       struct task_struct *tsk = current;
-       struct wait_queue wait = { tsk, NULL };
-       int               ret = 0;
 
-       tsk->state = task_state;
-       add_wait_queue(&sem->wait, &wait);
+#define DOWN_VAR                               \
+       struct task_struct *tsk = current;      \
+       struct wait_queue wait = { tsk, NULL };
 
-       /*
-        * Ok, we're set up.  sem->count is known to be less than zero
-        * so we must wait.
-        *
-        * We can let go the lock for purposes of waiting.
-        * We re-acquire it after awaking so as to protect
-        * all semaphore operations.
-        *
-        * If "up()" is called before we call waking_non_zero() then
-        * we will catch it right away.  If it is called later then
-        * we will have to go through a wakeup cycle to catch it.
-        *
-        * Multiple waiters contend for the semaphore lock to see
-        * who gets to gate through and who has to wait some more.
-        */
-       for (;;) {
-               if (waking_non_zero(sem))       /* are we waking up?  */
+#define DOWN_HEAD(task_state)                                           \
+                                                                        \
+                                                                        \
+       tsk->state = (task_state);                                       \
+       add_wait_queue(&sem->wait, &wait);                               \
+                                                                        \
+       /*                                                               \
+        * Ok, we're set up.  sem->count is known to be less than zero   \
+        * so we must wait.                                              \
+        *                                                               \
+        * We can let go the lock for purposes of waiting.               \
+        * We re-acquire it after awaking so as to protect               \
+        * all semaphore operations.                                     \
+        *                                                               \
+        * If "up()" is called before we call waking_non_zero() then     \
+        * we will catch it right away.  If it is called later then      \
+        * we will have to go through a wakeup cycle to catch it.        \
+        *                                                               \
+        * Multiple waiters contend for the semaphore lock to see        \
+        * who gets to gate through and who has to wait some more.       \
+        */                                                              \
+       for (;;) {                                                       \
+               if (waking_non_zero(sem))       /* are we waking up?  */ \
                        break;                  /* yes, exit loop */
 
-               if (task_state == TASK_INTERRUPTIBLE && signal_pending(tsk)) {
-                       ret = -EINTR;                   /* interrupted */
-                       atomic_inc(&sem->count);        /* give up on down operation */
-                       break;
-               }
-
-               schedule();
-               tsk->state = task_state;
-       }
-       tsk->state = TASK_RUNNING;
+#define DOWN_TAIL(task_state)                  \
+               tsk->state = (task_state);      \
+       }                                       \
+       tsk->state = TASK_RUNNING;              \
        remove_wait_queue(&sem->wait, &wait);
-       return ret;
-}
 
 void __down(struct semaphore * sem)
 {
-       __do_down(sem,TASK_UNINTERRUPTIBLE);
+       DOWN_VAR
+       DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+       schedule();
+       DOWN_TAIL(TASK_UNINTERRUPTIBLE)
 }
 
 int __down_interruptible(struct semaphore * sem)
 {
-       return __do_down(sem,TASK_INTERRUPTIBLE);
+       DOWN_VAR
+       int ret = 0;
+       DOWN_HEAD(TASK_INTERRUPTIBLE)
+       if (signal_pending(tsk))
+       {
+               ret = -EINTR;                   /* interrupted */
+               atomic_inc(&sem->count);        /* give up on down operation */
+               break;
+       }
+       schedule();
+       DOWN_TAIL(TASK_INTERRUPTIBLE)
+       return ret;
 }
 
 #define        SLEEP_ON_VAR                            \
@@ -956,6 +966,19 @@ void sleep_on(struct wait_queue **p)
        SLEEP_ON_TAIL
 }
 
+long sleep_on_timeout(struct wait_queue **p, long timeout)
+{
+       SLEEP_ON_VAR
+       
+       current->state = TASK_UNINTERRUPTIBLE;
+
+       SLEEP_ON_HEAD
+       timeout = schedule_timeout(timeout);
+       SLEEP_ON_TAIL
+
+       return timeout;
+}
+
 void scheduling_functions_end_here(void) { }
 
 static inline void cascade_timers(struct timer_vec *tv)
index 67e6f334ef82e9149f5996d064d7410e8ec8e9a7..18c792d4adae41a5ff8ae0e9777a6c30143a0572 100644 (file)
@@ -44,6 +44,9 @@ extern char modprobe_path[];
 #ifdef CONFIG_CHR_DEV_SG
 extern int sg_big_buff;
 #endif
+#ifdef CONFIG_SYSVIPC
+extern int shmmax;
+#endif
 
 #ifdef __sparc__
 extern char reboot_command [];
@@ -205,6 +208,10 @@ static ctl_table kern_table[] = {
         0444, NULL, &proc_dointvec},
        {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
         0644, NULL, &proc_dointvec},
+#ifdef CONFIG_SYSVIPC
+       {KERN_SHMMAX, "shmmax", &shmmax, sizeof (int),
+        0644, NULL, &proc_dointvec},
+#endif
        {0}
 };
 
index 15b5547371d9453390b30dfb176f338322a321c9..ca98cc5324f762a1f595acb940481318a063d5f3 100644 (file)
@@ -125,10 +125,16 @@ int shrink_mmap(int priority, int gfp_mask)
        struct page * page;
        int count;
 
-       count = limit >> priority;
+       count = (limit << 1) >> priority;
 
        page = mem_map + clock;
        do {
+               int referenced;
+
+               /* This works even in the presence of PageSkip because
+                * the first two entries at the beginning of a hole will
+                * be marked, not just the first.
+                */
                page++;
                clock++;
                if (clock >= max_mapnr) {
@@ -141,11 +147,9 @@ int shrink_mmap(int priority, int gfp_mask)
                        clock = page->map_nr;
                }
                
-               if (test_and_clear_bit(PG_referenced, &page->flags))
-                       continue;
-
-               /* Decrement count only for non-referenced pages */
                count--;
+               referenced = test_and_clear_bit(PG_referenced, &page->flags);
+
                if (PageLocked(page))
                        continue;
 
@@ -156,6 +160,21 @@ int shrink_mmap(int priority, int gfp_mask)
                if (atomic_read(&page->count) != 1)
                        continue;
 
+               /*
+                * Is it a page swap page? If so, we want to
+                * drop it if it is no longer used, even if it
+                * were to be marked referenced..
+                */
+               if (PageSwapCache(page)) {
+                       if (referenced && swap_count(page->offset) != 1)
+                               continue;
+                       delete_from_swap_cache(page);
+                       return 1;
+               }       
+
+               if (referenced)
+                       continue;
+
                /* Is it a buffer page? */
                if (page->buffers) {
                        if (buffer_under_min())
@@ -165,14 +184,10 @@ int shrink_mmap(int priority, int gfp_mask)
                        return 1;
                }
 
-               /* is it a swap-cache or page-cache page? */
+               /* is it a page-cache page? */
                if (page->inode) {
                        if (pgcache_under_min())
                                continue;
-                       if (PageSwapCache(page)) {
-                               delete_from_swap_cache(page);
-                               return 1;
-                       }
                        remove_inode_page(page);
                        return 1;
                }
index db1808432fe20b7aa9b554db60ed8a0c5c39cac4..83c79e0e2e5b6ce535e0be8cf70c8aeffc06a0c9 100644 (file)
@@ -642,37 +642,47 @@ static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
        page_map = mem_map + MAP_NR(old_page);
        
        /*
-        * Do we need to copy?
+        * We can avoid the copy if:
+        * - we're the only user (count == 1)
+        * - the only other user is the swap cache,
+        *   and the only swap cache user is itself,
+        *   in which case we can remove the page
+        *   from the swap cache.
         */
-       if (is_page_shared(page_map)) {
+       switch (atomic_read(&page_map->count)) {
+       case 2:
+               if (!PageSwapCache(page_map))
+                       break;
+               if (swap_count(page_map->offset) != 1)
+                       break;
+               delete_from_swap_cache(page_map);
+               /* FallThrough */
+       case 1:
+               /* We can release the kernel lock now.. */
                unlock_kernel();
-               if (!new_page)
-                       return 0;
 
-               if (PageReserved(mem_map + MAP_NR(old_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))));
-               free_page(old_page);
+               set_pte(page_table, pte_mkdirty(pte_mkwrite(pte)));
                flush_tlb_page(vma, address);
+end_wp_page:
+               if (new_page)
+                       free_page(new_page);
                return 1;
        }
-
-       if (PageSwapCache(page_map))
-               delete_from_swap_cache(page_map);
-
-       /* We can release the kernel lock now.. */
+               
        unlock_kernel();
+       if (!new_page)
+               return 0;
 
+       if (PageReserved(mem_map + MAP_NR(old_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_mkdirty(pte_mkwrite(pte)));
+       set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
+       free_page(old_page);
        flush_tlb_page(vma, address);
-end_wp_page:
-       if (new_page)
-               free_page(new_page);
        return 1;
 
 bad_wp_page:
index 8197368e3e14b975d98cc50302b057681a529c30..822def38cec0b098b6a1efcd2f6d4dabbade941c 100644 (file)
@@ -244,6 +244,14 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order)
                        goto nopage;
                }
 
+               /*
+                * If this is a recursive call, we'd better
+                * do our best to just allocate things without
+                * further thought.
+                */
+               if (current->flags & PF_MEMALLOC)
+                       goto ok_to_allocate;
+
                /*
                 * Avoid going back-and-forth between allocating
                 * memory and trying to free it. If we get into
@@ -271,8 +279,14 @@ unsigned long __get_free_pages(int gfp_mask, unsigned long order)
                 * memory.
                 */
                current->trashing_memory = 1;
-               if (!try_to_free_pages(gfp_mask, SWAP_CLUSTER_MAX) && !(gfp_mask & (__GFP_MED | __GFP_HIGH)))
-                       goto nopage;
+               {
+                       int freed;
+                       current->flags |= PF_MEMALLOC;
+                       freed = try_to_free_pages(gfp_mask, SWAP_CLUSTER_MAX);
+                       current->flags &= ~PF_MEMALLOC;
+                       if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH)))
+                               goto nopage;
+               }
        }
 ok_to_allocate:
        spin_lock_irqsave(&page_alloc_lock, flags);
index 0536ff1ab41962f57c3f370624b64986e03c8d2e..7aa7f32ea3ff96e6e307853549424fb2a50e6ba3 100644 (file)
 
 #include <asm/pgtable.h>
 
-/* 
- * The wait queue for waking up the pageout daemon:
- */
-static struct task_struct * kswapd_task = NULL;
-
-static void init_swap_timer(void);
-
 /*
  * The swap-out functions return 1 if they successfully
  * threw something out, and we got a free page. It returns
@@ -38,7 +31,7 @@ static void init_swap_timer(void);
  * using a process that no longer actually exists (it might
  * have died while we slept).
  */
-static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
+static int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
        unsigned long address, pte_t * page_table, int gfp_mask)
 {
        pte_t pte;
@@ -59,50 +52,6 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc
            || ((gfp_mask & __GFP_DMA) && !PageDMA(page_map)))
                return 0;
 
-       /* 
-        * Deal with page aging.  There are several special cases to
-        * consider:
-        * 
-        * Page has been accessed, but is swap cached.  If the page is
-        * getting sufficiently "interesting" --- its age is getting
-        * high --- then if we are sufficiently short of free swap
-        * pages, then delete the swap cache.  We can only do this if
-        * the swap page's reference count is one: ie. there are no
-        * other references to it beyond the swap cache (as there must
-        * still be PTEs pointing to it if count > 1).
-        * 
-        * If the page has NOT been touched, and its age reaches zero,
-        * then we are swapping it out:
-        *
-        *   If there is already a swap cache page for this page, then
-        *   another process has already allocated swap space, so just
-        *   dereference the physical page and copy in the swap entry
-        *   from the swap cache.  
-        * 
-        * Note, we rely on all pages read in from swap either having
-        * the swap cache flag set, OR being marked writable in the pte,
-        * but NEVER BOTH.  (It IS legal to be neither cached nor dirty,
-        * however.)
-        *
-        * -- Stephen Tweedie 1998 */
-
-       if (PageSwapCache(page_map)) {
-               if (pte_write(pte)) {
-                       struct page *found;
-                       printk ("VM: Found a writable swap-cached page!\n");
-                       /* Try to diagnose the problem ... */
-                       found = find_page(&swapper_inode, page_map->offset);
-                       if (found) {
-                               printk("page=%p@%08lx, found=%p, count=%d\n",
-                                       page_map, page_map->offset,
-                                       found, atomic_read(&found->count));
-                               __free_page(found);
-                       } else 
-                               printk ("Spurious, page not in cache\n");
-                       return 0;
-               }
-       }
-       
        if (pte_young(pte)) {
                /*
                 * Transfer the "accessed" bit from the page
@@ -110,109 +59,101 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc
                 */
                set_pte(page_table, pte_mkold(pte));
                set_bit(PG_referenced, &page_map->flags);
-
-               /* 
-                * We should test here to see if we want to recover any
-                * swap cache page here.  We do this if the page seeing
-                * enough activity, AND we are sufficiently low on swap
-                *
-                * We need to track both the number of available swap
-                * pages and the total number present before we can do
-                * this...  
-                */
                return 0;
        }
 
-       if (pte_dirty(pte)) {
-               if (vma->vm_ops && vma->vm_ops->swapout) {
-                       pid_t pid = tsk->pid;
-                       vma->vm_mm->rss--;
-                       if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table))
-                               kill_proc(pid, SIGBUS, 1);
-               } else {
-                       /*
-                        * This is a dirty, swappable page.  First of all,
-                        * get a suitable swap entry for it, and make sure
-                        * we have the swap cache set up to associate the
-                        * page with that swap entry.
-                        */
-                       entry = in_swap_cache(page_map);
-                       if (!entry) {
-                               entry = get_swap_page();
-                               if (!entry)
-                                       return 0; /* No swap space left */
-                       }
-                       
-                       vma->vm_mm->rss--;
-                       tsk->nswap++;
-                       flush_cache_page(vma, address);
-                       set_pte(page_table, __pte(entry));
-                       flush_tlb_page(vma, address);
-                       swap_duplicate(entry);
-
-                       /* Now to write back the page.  We have two
-                        * cases: if the page is already part of the
-                        * swap cache, then it is already on disk.  Just
-                        * free the page and return (we release the swap
-                        * cache on the last accessor too).
-                        *
-                        * If we have made a new swap entry, then we
-                        * start the write out to disk.  If the page is
-                        * shared, however, we still need to keep the
-                        * copy in memory, so we add it to the swap
-                        * cache. */
-                       if (PageSwapCache(page_map)) {
-                               __free_page(page_map);
-                               return (atomic_read(&page_map->count) == 0);
-                       }
-                       add_to_swap_cache(page_map, entry);
-                       /* We checked we were unlocked way up above, and we
-                          have been careful not to stall until here */
-                       set_bit(PG_locked, &page_map->flags);
-                       /* OK, do a physical write to swap.  */
-                       rw_swap_page(WRITE, entry, (char *) page, (gfp_mask & __GFP_WAIT));
-               }
-               /* Now we can free the current physical page.  We also
-                * free up the swap cache if this is the last use of the
-                * page.  Note that there is a race here: the page may
-                * still be shared COW by another process, but that
-                * process may exit while we are writing out the page
-                * asynchronously.  That's no problem, shrink_mmap() can
-                * correctly clean up the occassional unshared page
-                * which gets left behind in the swap cache. */
+       /*
+        * Is the page already in the swap cache? If so, then
+        * we can just drop our reference to it without doing
+        * any IO - it's already up-to-date on disk.
+        *
+        * Return 0, as we didn't actually free any real
+        * memory, and we should just continue our scan.
+        */
+       if (PageSwapCache(page_map)) {
+               entry = page_map->offset;
+               swap_duplicate(entry);
+               set_pte(page_table, __pte(entry));
+drop_pte:
+               vma->vm_mm->rss--;
+               tsk->nswap++;
+               flush_tlb_page(vma, address);
                __free_page(page_map);
-               return 1;       /* we slept: the process may not exist any more */
+               return 0;
+       }
+
+       /*
+        * Is it a clean page? Then it must be recoverable
+        * by just paging it in again, and we can just drop
+        * it..
+        *
+        * However, this won't actually free any real
+        * memory, as the page will just be in the page cache
+        * somewhere, and as such we should just continue
+        * our scan.
+        *
+        * Basically, this just makes it possible for us to do
+        * some real work in the future in "shrink_mmap()".
+        */
+       if (!pte_dirty(pte)) {
+               pte_clear(page_table);
+               goto drop_pte;
        }
 
-       /* The page was _not_ dirty, but still has a zero age.  It must
-        * already be uptodate on disk.  If it is in the swap cache,
-        * then we can just unlink the page now.  Remove the swap cache
-        * too if this is the last user.  */
-        if ((entry = in_swap_cache(page_map)))  {
+       /*
+        * Ok, it's really dirty. That means that
+        * we should either create a new swap cache
+        * entry for it, or we should write it back
+        * to its own backing store.
+        *
+        * Note that in neither case do we actually
+        * know that we make a page available, but
+        * as we potentially sleep we can no longer
+        * continue scanning, so we migth as well
+        * assume we free'd something.
+        *
+        * NOTE NOTE NOTE! This should just set a
+        * dirty bit in page_map, and just drop the
+        * pte. All the hard work would be done by
+        * shrink_mmap().
+        *
+        * That would get rid of a lot of problems.
+        */
+       if (vma->vm_ops && vma->vm_ops->swapout) {
+               pid_t pid = tsk->pid;
                vma->vm_mm->rss--;
-               flush_cache_page(vma, address);
-               set_pte(page_table, __pte(entry));
-               flush_tlb_page(vma, address);
-               swap_duplicate(entry);
+               if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table))
+                       kill_proc(pid, SIGBUS, 1);
                __free_page(page_map);
-               return (atomic_read(&page_map->count) == 0);
-       } 
-       /* 
-        * A clean page to be discarded?  Must be mmap()ed from
-        * somewhere.  Unlink the pte, and tell the filemap code to
-        * discard any cached backing page if this is the last user.
-        */
-       if (PageSwapCache(page_map)) {
-               printk ("VM: How can this page _still_ be cached?");
-               return 0;
+               return 1;
        }
+
+       /*
+        * This is a dirty, swappable page.  First of all,
+        * get a suitable swap entry for it, and make sure
+        * we have the swap cache set up to associate the
+        * page with that swap entry.
+        */
+       entry = get_swap_page();
+       if (!entry)
+               return 0; /* No swap space left */
+               
        vma->vm_mm->rss--;
+       tsk->nswap++;
        flush_cache_page(vma, address);
-       pte_clear(page_table);
+       set_pte(page_table, __pte(entry));
        flush_tlb_page(vma, address);
-       entry = (atomic_read(&page_map->count) == 1);
+       swap_duplicate(entry);  /* One for the process, one for the swap cache */
+       add_to_swap_cache(page_map, entry);
+       /* We checked we were unlocked way up above, and we
+          have been careful not to stall until here */
+       set_bit(PG_locked, &page_map->flags);
+
+       /* OK, do a physical asynchronous write to swap.  */
+       rw_swap_page(WRITE, entry, (char *) page, 0);
+
        __free_page(page_map);
-       return entry;
+       return 1;
 }
 
 /*
@@ -409,11 +350,7 @@ static int swap_out(unsigned int priority, int gfp_mask)
                        goto out;
                }
 
-               /*
-                * Nonzero means we cleared out something, but only "1" means
-                * that we actually free'd up a page as a result.
-                */
-               if (swap_out_process(pbest, gfp_mask) == 1)
+               if (swap_out_process(pbest, gfp_mask))
                        return 1;
        }
 out:
@@ -441,71 +378,36 @@ void __init kswapd_setup(void)
        printk ("Starting kswapd v%.*s\n", i, s);
 }
 
-#define free_memory(fn) \
-       count++; do { if (!--count) goto done; } while (fn)
-
-static int kswapd_free_pages(int kswapd_state)
-{
-       unsigned long end_time;
-
-       /* Always trim SLAB caches when memory gets low. */
-       kmem_cache_reap(0);
-
-       /* max one hundreth of a second */
-       end_time = jiffies + (HZ-1)/100;
-       do {
-               int priority = 8;
-               int count = pager_daemon.swap_cluster;
-
-               switch (kswapd_state) {
-                       do {
-                       default:
-                               free_memory(shrink_mmap(priority, 0));
-                               free_memory(swap_out(priority, 0));
-                               kswapd_state++;
-                       case 1:
-                               free_memory(shm_swap(priority, 0));
-                               shrink_dcache_memory(priority, 0);
-                               kswapd_state = 0;
-                       } while (--priority >= 0);
-                       return kswapd_state;
-               }
-done:
-               if (nr_free_pages > freepages.high + pager_daemon.swap_cluster)
-                       break;
-       } while (time_before_eq(jiffies,end_time));
-       return kswapd_state;
-}
-
 /*
- * The background pageout daemon.
- * Started as a kernel thread from the init process.
+ * The background pageout daemon, started as a kernel thread
+ * from the init process. 
+ *
+ * This basically executes once a second, trickling out pages
+ * so that we have _some_ free memory available even if there
+ * is no other activity that frees anything up. This is needed
+ * for things like routing etc, where we otherwise might have
+ * all activity going on in asynchronous contexts that cannot
+ * page things out.
+ *
+ * If there are applications that are active memory-allocators
+ * (most normal use), this basically shouldn't matter.
  */
 int kswapd(void *unused)
 {
        current->session = 1;
        current->pgrp = 1;
        strcpy(current->comm, "kswapd");
-       sigfillset(&current->blocked);
-       
-       /*
-        *      As a kernel thread we want to tamper with system buffers
-        *      and other internals and thus be subject to the SMP locking
-        *      rules. (On a uniprocessor box this does nothing).
-        */
-       lock_kernel();
 
        /*
-        * Set the base priority to something smaller than a
-        * regular process. We will scale up the priority
-        * dynamically depending on how much memory we need.
+        * Hey, if somebody wants to kill us, be our guest. 
+        * Don't come running to mama if things don't work.
         */
-       current->priority = (DEF_PRIORITY * 2) / 3;
-
+       siginitsetinv(&current->blocked, sigmask(SIGKILL));
+       
        /*
         * Tell the memory management that we're a "memory allocator",
         * and that if we need more memory we should get access to it
-        * regardless (see "try_to_free_pages()"). "kswapd" should
+        * regardless (see "__get_free_pages()"). "kswapd" should
         * never get caught in the normal page freeing logic.
         *
         * (Kswapd normally doesn't need memory anyway, but sometimes
@@ -516,21 +418,23 @@ int kswapd(void *unused)
         */
        current->flags |= PF_MEMALLOC;
 
-       init_swap_timer();
-       kswapd_task = current;
        while (1) {
-               int state = 0;
-
+               if (signal_pending(current))
+                       break;
                current->state = TASK_INTERRUPTIBLE;
-               flush_signals(current);
                run_task_queue(&tq_disk);
-               schedule();
-               swapstats.wakeups++;
-               state = kswapd_free_pages(state);
+               schedule_timeout(HZ);
+
+               /*
+                * kswapd isn't even meant to keep up with anything,
+                * so just a few pages per second is plenty: the only
+                * point is to make sure that the system doesn't stay
+                * forever in a really bad memory squeeze.
+                */
+               if (nr_free_pages < freepages.high)
+                       try_to_free_pages(0, 16);
        }
-       /* As if we could ever get here - maybe we want to make this killable */
-       kswapd_task = NULL;
-       unlock_kernel();
+
        return 0;
 }
 
@@ -539,111 +443,42 @@ int kswapd(void *unused)
  * now we need this so that we can do page allocations
  * without holding the kernel lock etc.
  *
- * The "PF_MEMALLOC" flag protects us against recursion:
- * if we need more memory as part of a swap-out effort we
- * will just silently return "success" to tell the page
- * allocator to accept the allocation.
- *
  * We want to try to free "count" pages, and we need to 
  * cluster them so that we get good swap-out behaviour. See
  * the "free_memory()" macro for details.
  */
 int try_to_free_pages(unsigned int gfp_mask, int count)
 {
-       int retval;
+       int priority;
 
        lock_kernel();
 
        /* Always trim SLAB caches when memory gets low. */
        kmem_cache_reap(gfp_mask);
 
-       retval = 1;
-       if (!(current->flags & PF_MEMALLOC)) {
-               int priority;
+       priority = 6;
+       do {
+               while (shrink_mmap(priority, gfp_mask)) {
+                       if (!--count)
+                               goto done;
+               }
 
-               current->flags |= PF_MEMALLOC;
+               /* Try to get rid of some shared memory pages.. */
+               while (shm_swap(priority, gfp_mask)) {
+                       if (!--count)
+                               goto done;
+               }
        
-               priority = 8;
-               do {
-                       free_memory(shrink_mmap(priority, gfp_mask));
-                       free_memory(shm_swap(priority, gfp_mask));
-                       free_memory(swap_out(priority, gfp_mask));
-                       shrink_dcache_memory(priority, gfp_mask);
-               } while (--priority >= 0);
-               retval = 0;
+               /* Then, try to page stuff out.. */
+               while (swap_out(priority, gfp_mask)) {
+                       if (!--count)
+                               goto done;
+               }
+
+               shrink_dcache_memory(priority, gfp_mask);
+       } while (--priority >= 0);
 done:
-               current->flags &= ~PF_MEMALLOC;
-       }
        unlock_kernel();
 
-       return retval;
-}
-
-/*
- * Wake up kswapd according to the priority
- *     0 - no wakeup
- *     1 - wake up as a low-priority process
- *     2 - wake up as a normal process
- *     3 - wake up as an almost real-time process
- *
- * This plays mind-games with the "goodness()"
- * function in kernel/sched.c.
- */
-static inline void kswapd_wakeup(struct task_struct *p, int priority)
-{
-       if (priority) {
-               p->counter = p->priority << priority;
-               wake_up_process(p);
-       }
-}
-
-/* 
- * The swap_tick function gets called on every clock tick.
- */
-void swap_tick(void)
-{
-       struct task_struct *p = kswapd_task;
-
-       /*
-        * Only bother to try to wake kswapd up
-        * if the task exists and can be woken.
-        */
-       if (p && (p->state & TASK_INTERRUPTIBLE)) {
-               unsigned int pages;
-               int want_wakeup;
-
-               /*
-                * Schedule for wakeup if there isn't lots
-                * of free memory or if there is too much
-                * of it used for buffers or pgcache.
-                *
-                * "want_wakeup" is our priority: 0 means
-                * not to wake anything up, while 3 means
-                * that we'd better give kswapd a realtime
-                * priority.
-                */
-               want_wakeup = 0;
-               pages = nr_free_pages;
-               if (pages < freepages.high)
-                       want_wakeup = 1;
-               if (pages < freepages.low)
-                       want_wakeup = 2;
-               if (pages < freepages.min)
-                       want_wakeup = 3;
-       
-               kswapd_wakeup(p,want_wakeup);
-       }
-
-       timer_active |= (1<<SWAP_TIMER);
-}
-
-/* 
- * Initialise the swap timer
- */
-
-void init_swap_timer(void)
-{
-       timer_table[SWAP_TIMER].expires = jiffies;
-       timer_table[SWAP_TIMER].fn = swap_tick;
-       timer_active |= (1<<SWAP_TIMER);
+       return priority >= 0;
 }
index db1bda57bca0e27992fbf76ff31bebec6dc72336..b853cc42b64aa6558e424f0e8f99aeca56c662be 100644 (file)
@@ -41,7 +41,7 @@ ARP_TIMEOUT           Timeout on an ARP (tunable)
 ARP_CHECK_INTERVAL     Check interval to refresh an arp (tunable)
 ARP_CONFIRM_INTERVAL   Confirm poll time (tunable)
 ARP_TABLE_SIZE         Hash table size for ARP (tunable)
-IP_MAX_MEMBERSHIPS     Largest number of groups per socket (BSD style)
+IP_MAX_MEMBERSHIPS     Largest number of groups per socket (BSD style) (tunable)
 16                     Hard coded constant for amount of room allowed for
                        cache align and faster forwarding (tunable)
 IPFRAG_HIGH_THRESH     Limit on fragments, we free fragments until we reach
index ebb381b52251d95ea4f66fa41f5b14bd5af8a7e3..73582584232da40a9ad9638b9c510a768aad53f1 100644 (file)
@@ -2154,7 +2154,7 @@ __initfunc(void atalk_proto_init(struct net_proto *pro))
        atalk_register_sysctl();
 #endif /* CONFIG_SYSCTL */
 
-       printk(KERN_INFO "AppleTalk 0.18 for Linux NET3.037\n");
+       printk(KERN_INFO "NET4: AppleTalk 0.18 for Linux NET4.0\n");
 }
 
 #ifdef MODULE
index 32d679cae71d6a29ef0f1565de6ee2da56523ca2..f9392fe34527b779acc6eb03286a0ab65dd0675f 100644 (file)
@@ -1806,7 +1806,7 @@ __initfunc(void ax25_proto_init(struct net_proto *pro))
        proc_net_register(&proc_ax25_calls);
 #endif
 
-       printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.37 for Linux NET3.038 (Linux 2.1)\n");
+       printk(KERN_INFO "NET4: G4KLX/GW4PTS AX.25 for Linux. Version 0.37 for Linux NET4.0\n");
 }
 
 #ifdef MODULE
index e86b8a54dac356e34083f8539bdd6b740d6d6c21..c4b35889bfb4fd8983b3375bdeaf87e613b6ed1b 100644 (file)
@@ -842,7 +842,7 @@ __initfunc(void br_init(void))
 {                                                /* (4.8.1)     */
        int port_no;
 
-       printk(KERN_INFO "Ethernet Bridge 005 for NET3.037 (Linux 2.1)\n");
+       printk(KERN_INFO "NET4: Ethernet Bridge 005 for NET4.0\n");
 
        /*
         * Form initial topology change time.
index e0379e69b1c67b7aa1c05e54949c76c8fcbaa8ac..57b1d38aa9f62197b57f9aa88e37177d808631fb 100644 (file)
@@ -47,6 +47,7 @@ if [ "$CONFIG_IP_FIREWALL" = "y" ]; then
         if [ "$CONFIG_IP_MASQUERADE_MOD" = "y" ]; then
           tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW
           tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW
+          tristate 'IP: ip fwmark masq-forwarding support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_MFW
        fi
       fi
     fi
index ad2a0a65061c4ec75e342b1677c34d19ae0d6e57..8ab280deba5ccc693c38995247f89f5511a17c4a 100644 (file)
@@ -81,6 +81,14 @@ ifeq ($(CONFIG_IP_MASQUERADE_MOD),y)
     endif
   endif
   
+  ifeq ($(CONFIG_IP_MASQUERADE_MFW),y)
+  IPV4_OBJS += ip_masq_mfw.o
+  else
+    ifeq ($(CONFIG_IP_MASQUERADE_MFW),m)
+    M_OBJS += ip_masq_mfw.o
+    endif
+  endif
+
 endif
 
 M_OBJS += ip_masq_user.o
index 54a4578caccdaf20ebdb1f9573aa7219ac6a7da4..3520b0c52d7409ae502d068614e11a4994355180 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             PF_INET protocol family socket handler.
  *
- * Version:    $Id: af_inet.c,v 1.80 1998/11/08 11:17:03 davem Exp $
+ * Version:    $Id: af_inet.c,v 1.82 1999/01/04 20:36:44 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -190,8 +190,9 @@ static __inline__ void kill_sk_later(struct sock *sk)
         * [PR]
         */
                  
-       printk(KERN_DEBUG "Socket destroy delayed (r=%d w=%d)\n",
-              atomic_read(&sk->rmem_alloc), atomic_read(&sk->wmem_alloc));
+       NETDEBUG(printk(KERN_DEBUG "Socket destroy delayed (r=%d w=%d)\n",
+                       atomic_read(&sk->rmem_alloc),
+                       atomic_read(&sk->wmem_alloc)));
 
        sk->destroy = 1;
        sk->ack_backlog = 0;
@@ -1059,7 +1060,7 @@ __initfunc(void inet_proto_init(struct net_proto *pro))
        struct sk_buff *dummy_skb;
        struct inet_protocol *p;
 
-       printk(KERN_INFO "Swansea University Computer Society TCP/IP for NET3.037\n");
+       printk(KERN_INFO "NET4: Linux TCP/IP 1.0 for NET4.0\n");
 
        if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb))
        {
index dc0c426f5bb4eb2cd8876a6a83460c0dbf320e27..b1aa1a04e42a7a5bdddbd73e71a8f89afad2c1a6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     NET3    IP device support routines.
  *
- *     Version: $Id: devinet.c,v 1.23 1998/08/26 12:03:21 davem Exp $
+ *     Version: $Id: devinet.c,v 1.25 1999/01/04 20:14:33 davem Exp $
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -208,16 +208,9 @@ inet_insert_ifa(struct in_device *in_dev, struct in_ifaddr *ifa)
 {
        struct in_ifaddr *ifa1, **ifap, **last_primary;
 
-       /* Allow 0.0.0.0, but it must be the only address to avoid
-           multiple matches. */
-       if (in_dev->ifa_list) {
-               if (ifa->ifa_local == 0) {
-                       inet_free_ifa(ifa);
-                       return 0;
-               }
-
-               if (in_dev->ifa_list->ifa_local == 0)
-                       inet_del_ifa(in_dev, &in_dev->ifa_list, 1);
+       if (ifa->ifa_local == 0) {
+               inet_free_ifa(ifa);
+               return 0;
        }
 
        ifa->ifa_flags &= ~IFA_F_SECONDARY;
@@ -997,33 +990,6 @@ static void devinet_sysctl_unregister(struct ipv4_devconf *p)
 }
 #endif
 
-#ifdef CONFIG_IP_PNP_BOOTP
-
-/*
- *     Addition and deletion of fake interface addresses
- *     for sending of BOOTP packets. In this case, we must
- *     set the local address to zero which is not permitted
- *     otherwise.
- */
-
-__initfunc(int inet_add_bootp_addr(struct device *dev))
-{
-       struct in_ifaddr *ifa;
-
-       if (!(ifa = inet_alloc_ifa()))
-               return -ENOBUFS;
-
-       return inet_set_ifa(dev, ifa);
-}
-
-__initfunc(void inet_del_bootp_addr(struct device *dev))
-{
-       if (dev->ip_ptr)
-               inetdev_destroy(dev->ip_ptr);
-}
-
-#endif
-
 __initfunc(void devinet_init(void))
 {
        register_gifconf(PF_INET, inet_gifconf);
index 0308bbc247c93ff11779c4154265838d4e6543d1..a3585cc0c63f2a546181c7c4655487820ce2dbb3 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             IPv4 Forwarding Information Base: FIB frontend.
  *
- * Version:    $Id: fib_frontend.c,v 1.12 1998/08/26 12:03:24 davem Exp $
+ * Version:    $Id: fib_frontend.c,v 1.14 1999/01/04 20:13:55 davem Exp $
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -443,13 +443,13 @@ static void fib_add_ifaddr(struct in_ifaddr *ifa)
        if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
                fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
 
-       if (!(ifa->ifa_flags&IFA_F_SECONDARY) &&
+       if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
            (prefix != addr || ifa->ifa_prefixlen < 32)) {
                fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
                          RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
 
                /* Add network specific broadcasts, when it takes a sense */
-               if (!ZERONET(prefix) && ifa->ifa_prefixlen < 31) {
+               if (ifa->ifa_prefixlen < 31) {
                        fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
                        fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim);
                }
index 47547e92fc701c35c60898a0ab79ef67cc4e55d5..5ac2d9a53cffe5b8ae4690fcde2e7306e893fcc9 100644 (file)
@@ -3,7 +3,7 @@
  *     
  *             Alan Cox, <alan@cymru.net>
  *
- *     Version: $Id: icmp.c,v 1.47 1998/10/21 05:32:24 davem Exp $
+ *     Version: $Id: icmp.c,v 1.48 1999/01/02 16:51:41 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
index af49104b3a1683c26d9762817ea11b086076cd8a..b0e7b6d01aebd58d15a83f6edf2e9505aeb76e30 100644 (file)
@@ -8,7 +8,7 @@
  *     the older version didn't come out right using gcc 2.5.8, the newer one
  *     seems to fall out with gcc 2.6.2.
  *
- *     Version: $Id: igmp.c,v 1.27 1998/08/26 12:03:39 davem Exp $
+ *     Version: $Id: igmp.c,v 1.28 1998/11/30 15:53:13 davem Exp $
  *
  *     Authors:
  *             Alan Cox <Alan.Cox@linux.org>
@@ -538,6 +538,7 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
 /*
  *     Join a socket to a group
  */
+int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS;
 
 int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
 {
@@ -578,7 +579,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
                count++;
        }
        err = -ENOBUFS;
-       if (iml == NULL || count >= IP_MAX_MEMBERSHIPS)
+       if (iml == NULL || count >= sysctl_igmp_max_memberships)
                goto done;
        memcpy(&iml->multi, imr, sizeof(*imr));
        iml->next = sk->ip_mc_list;
index 5044e7b458a3d08d5fb146a868588c80e474fa9c..2baf45d21d40d68e550e3ba840c7b78e91badc32 100644 (file)
  * UP.
  *
  * For backchains and counters, we use an array, indexed by
- * [smp_processor_id()*2 + !in_interrupt()]; the array is of size
- * [smp_num_cpus*2].  For v2.0, smp_num_cpus is effectively 1.  So,
+ * [cpu_number_map[smp_processor_id()]*2 + !in_interrupt()]; the array is of 
+ * size [smp_num_cpus*2].  For v2.0, smp_num_cpus is effectively 1.  So,
  * confident of uniqueness, we modify counters even though we only
  * have a read lock (to read the counters, you need a write lock,
  * though).  */
 static struct sock *ipfwsk;
 #endif
 
-#define SLOT_NUMBER() (smp_processor_id()*2 + !in_interrupt())
+#ifdef __SMP__
+#define SLOT_NUMBER() (cpu_number_map[smp_processor_id()]*2 + !in_interrupt())
+#else
+#define SLOT_NUMBER() (!in_interrupt())
+#endif
 #define NUM_SLOTS (smp_num_cpus*2)
 
 #define SIZEOF_STRUCT_IP_CHAIN (sizeof(struct ip_chain) \
index a80cc16275184d8967e7d2d6d66a15777f11d918..2f7b46ea67cfb4e5c101606fcaf125b7c36b017c 100644 (file)
@@ -4,7 +4,7 @@
  *
  *     Copyright (c) 1994 Pauline Middelink
  *
- *     $Id: ip_masq.c,v 1.28 1998/11/21 00:33:30 davem Exp $
+ *     $Id: ip_masq.c,v 1.32 1999/01/04 20:37:05 davem Exp $
  *
  *
  *     See ip_fw.c for original log
@@ -44,6 +44,8 @@
  *     Juan Jose Ciarlante     :       fixed stupid SMP locking bug
  *     Juan Jose Ciarlante     :       fixed "tap"ing in demasq path by copy-on-w
  *     Juan Jose Ciarlante     :       make masq_proto_doff() robust against fake sized/corrupted packets
+ *     Kai Bankett             :       do not toss other IP protos in proto_doff()
+ *     Dan Kegel               :       pointed correct NAT behavior for UDP streams
  *     
  */
 
@@ -391,6 +393,20 @@ EXPORT_SYMBOL(ip_masq_expire);
 struct ip_fw_masq *ip_masq_expire = &ip_masq_dummy;
 #endif
 
+/*
+ *     These flags enable non-strict d{addr,port} checks
+ *     Given that both (in/out) lookup tables are hashed
+ *     by m{addr,port} and s{addr,port} this is quite easy 
+ */
+
+#define MASQ_DADDR_PASS        (IP_MASQ_F_NO_DADDR|IP_MASQ_F_DLOOSE)
+#define MASQ_DPORT_PASS        (IP_MASQ_F_NO_DPORT|IP_MASQ_F_DLOOSE)
+
+/*
+ *     By default enable dest loose semantics
+ */
+#define CONFIG_IP_MASQ_LOOSE_DEFAULT 1
+
 
 /*
  *     Set masq expiration (deletion) and adds timer,
@@ -522,12 +538,12 @@ static struct ip_masq * __ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_por
 
         hash = ip_masq_hash_key(protocol, d_addr, d_port);
 
-
         for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
-               if (protocol==ms->protocol &&
-                   ((s_addr==ms->daddr || ms->flags & IP_MASQ_F_NO_DADDR)) &&
-                   (s_port==ms->dport || ms->flags & IP_MASQ_F_NO_DPORT) &&
-                   (d_addr==ms->maddr && d_port==ms->mport)) {
+               if (protocol==ms->protocol && 
+                   (d_addr==ms->maddr && d_port==ms->mport) &&
+                   (s_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) &&
+                   (s_port==ms->dport || ms->flags & MASQ_DPORT_PASS)
+                   ) {
                        IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX OK\n",
                               protocol,
                               s_addr,
@@ -578,7 +594,9 @@ static struct ip_masq * __ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_po
         for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
                if (protocol == ms->protocol &&
                    s_addr == ms->saddr && s_port == ms->sport &&
-                    d_addr == ms->daddr && d_port == ms->dport ) {
+                   (d_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) &&
+                   (d_port==ms->dport || ms->flags & MASQ_DPORT_PASS)
+                   ) {
                        IP_MASQ_DEBUG(2, "lk/out1 %d %08X:%04hX->%08X:%04hX OK\n",
                               protocol,
                               s_addr,
@@ -600,7 +618,9 @@ static struct ip_masq * __ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_po
                if (ms->flags & IP_MASQ_F_NO_SPORT &&
                    protocol == ms->protocol &&
                    s_addr == ms->saddr && 
-                    d_addr == ms->daddr && d_port == ms->dport ) {
+                   (d_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) &&
+                   (d_port==ms->dport || ms->flags & MASQ_DPORT_PASS)
+                    ) {
                        IP_MASQ_DEBUG(2, "lk/out2 %d %08X:%04hX->%08X:%04hX OK\n",
                               protocol,
                               s_addr,
@@ -623,7 +643,7 @@ out:
         return ms;
 }
 
-#ifdef CONFIG_IP_MASQUERADE_NREUSE
+#ifdef CONFIG_IP_MASQ_NREUSE
 /*
  *     Returns ip_masq for given proto,m_addr,m_port.
  *      called by allocation routine to find an unused m_port.
@@ -841,7 +861,15 @@ struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, _
        atomic_set(&ms->refcnt,0);
 
         if (proto == IPPROTO_UDP && !mport)
+#ifdef CONFIG_IP_MASQ_LOOSE_DEFAULT
+               /*
+                *      Flag this tunnel as "dest loose"
+                *      
+                */
+               ms->flags |= IP_MASQ_F_DLOOSE;
+#else
                 ms->flags |= IP_MASQ_F_NO_DADDR;
+#endif
 
         
         /* get masq address from rif */
@@ -916,7 +944,7 @@ struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, _
                else
                        write_lock(&__ip_masq_lock);
 
-#ifdef CONFIG_IP_MASQUERADE_NREUSE
+#ifdef CONFIG_IP_MASQ_NREUSE
                mst = __ip_masq_getbym(proto, maddr, mport);
 #else
                mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport);
@@ -966,6 +994,9 @@ mport_nono:
 
 /*
  *     Get transport protocol data offset, check against size
+ *     return:
+ *             0  if other IP proto
+ *             -1 if error
  */
 static __inline__ int proto_doff(unsigned proto, char *th, unsigned size)
 {
@@ -993,6 +1024,9 @@ static __inline__ int proto_doff(unsigned proto, char *th, unsigned size)
                        }
 
                        break;
+               default:
+                       /*      Other proto: nothing to say, by now :) */
+                       ret = 0;
        }
        if (ret < 0)
                IP_MASQ_DEBUG(0, "mess proto_doff for proto=%d, size =%d\n",
@@ -1024,11 +1058,16 @@ int ip_fw_masquerade(struct sk_buff **skb_p, __u32 maddr)
        h.raw = (char*) iph + iph->ihl * 4;
        size = ntohs(iph->tot_len) - (iph->ihl * 4);
 
+
        doff = proto_doff(iph->protocol, h.raw, size);
-       if (doff < 0) {
-               IP_MASQ_DEBUG(0, "O-pkt invalid packet data size\n");
+       if (doff <= 0) {
+               /*      
+                *      Output path: do not pass other IP protos nor
+                *      invalid packets.
+                */
                return -1;
        }
+
        switch (iph->protocol) {
        case IPPROTO_ICMP:
                return(ip_fw_masq_icmp(skb_p, maddr));
@@ -1131,6 +1170,13 @@ int ip_fw_masquerade(struct sk_buff **skb_p, __u32 maddr)
                        IP_MASQ_DEBUG(1, "ip_fw_masquerade(): filled sport=%d\n",
                               ntohs(ms->sport));
                }
+               if (ms->flags & IP_MASQ_F_DLOOSE) {
+                       /*
+                        *      update dest loose values
+                        */
+                       ms->dport = h.portp[1];
+                       ms->daddr = iph->daddr;
+               }
         } else {
                /*
                 *      Nope, not found, create a new entry for it
@@ -1431,8 +1477,8 @@ int ip_fw_masq_icmp(struct sk_buff **skb_p, __u32 maddr)
        if (ip_compute_csum((unsigned char *) icmph, len))
        {
                /* Failed checksum! */
-               IP_MASQ_WARNING( "forward ICMP: failed checksum from %d.%d.%d.%d!\n",
-                      NIPQUAD(iph->saddr));
+               IP_MASQ_DEBUG(0, "forward ICMP: failed checksum from %d.%d.%d.%d!\n",
+                             NIPQUAD(iph->saddr));
                return(-1);
        }
 
@@ -1776,9 +1822,17 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
        size = ntohs(iph->tot_len) - (iph->ihl * 4);
 
        doff = proto_doff(iph->protocol, h.raw, size);
-       if (doff < 0) {
-               IP_MASQ_DEBUG(0, "I-pkt invalid packet data size\n");
-               return -1;
+
+       switch (doff) {
+               case 0:
+                       /*
+                        *      Input path: other IP protos Ok, will
+                        *      reach local sockets path.
+                        */
+                       return 0;
+               case -1:
+                       IP_MASQ_DEBUG(0, "I-pkt invalid packet data size\n");
+                       return -1;
        }
 
        maddr = iph->daddr;
@@ -1870,10 +1924,18 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
                  */
                 ms->flags &= ~IP_MASQ_F_NO_REPLY;
                 
-                /*
-                 *     Set dport if not defined yet.
+               /*
+                *      Set daddr,dport if not defined yet
+                *      and tunnel is not setup as "dest loose"
                  */
 
+               if (ms->flags & IP_MASQ_F_DLOOSE) {
+                       /*
+                        *      update dest loose values
+                        */
+                       ms->dport = h.portp[0];
+                       ms->daddr = iph->saddr;
+               } else {
                 if ( ms->flags & IP_MASQ_F_NO_DPORT ) { /*  && ms->protocol == IPPROTO_TCP ) { */
                         ms->flags &= ~IP_MASQ_F_NO_DPORT;
                         ms->dport = h.portp[0];
@@ -1890,6 +1952,7 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
                                ntohl(ms->daddr));
 
                 }
+               }
                if ((skb=masq_skb_cow(skb_p, &iph, &h.raw)) == NULL) {
                        ip_masq_put(ms);
                        return -1;
@@ -2309,8 +2372,8 @@ __initfunc(int ip_masq_init(void))
 #ifdef CONFIG_IP_MASQUERADE_IPPORTFW
        ip_portfw_init();
 #endif
-#ifdef CONFIG_IP_MASQUERADE_IPMARKFW
-       ip_markfw_init();
+#ifdef CONFIG_IP_MASQUERADE_MFW
+       ip_mfw_init();
 #endif
         ip_masq_app_init();
 
diff --git a/net/ipv4/ip_masq_mfw.c b/net/ipv4/ip_masq_mfw.c
new file mode 100644 (file)
index 0000000..0dfbba5
--- /dev/null
@@ -0,0 +1,776 @@
+/*
+ *             IP_MASQ_MARKFW masquerading module
+ *
+ *     Does (reverse-masq) forwarding based on skb->fwmark value
+ *
+ *     $Id: ip_masq_mfw.c,v 1.2 1998/12/12 02:40:42 davem Exp $
+ *
+ * Author:     Juan Jose Ciarlante   <jjciarla@raiz.uncu.edu.ar>
+ *               based on Steven Clarke's portfw
+ *
+ * Fixes:      
+ *     JuanJo Ciarlante:       added u-space sched support
+ *     JuanJo Ciarlante:       if rport==0, use packet dest port *grin*
+ *     JuanJo Ciarlante:       fixed tcp syn&&!ack creation
+ *
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <net/ip.h>
+#include <linux/ip_fw.h>
+#include <linux/ip_masq.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/softirq.h>
+#include <asm/spinlock.h>
+#include <asm/atomic.h>
+
+static struct ip_masq_mod *mmod_self = NULL;
+#ifdef CONFIG_IP_MASQ_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
+
+/*
+ *  Lists structure:
+ *     There is a "main" linked list with entries hashed
+ *     by fwmark value (struct ip_masq_mfw, the "m-entries").
+ *
+ *     Each of this m-entry holds a double linked list
+ *     of "forward-to" hosts (struct ip_masq_mfw_host, the "m.host"),
+ *     the round-robin scheduling takes place by rotating m.host entries
+ *     "inside" its m-entry.
+ */
+
+/*
+ *     Each forwarded host (addr:port) is stored here
+ */
+struct ip_masq_mfw_host {
+       struct  list_head list;
+       __u32   addr;
+       __u16   port;
+       __u16   pad0;
+       __u32   fwmark;
+       int     pref;
+       atomic_t        pref_cnt;
+};
+
+#define IP_MASQ_MFW_HSIZE      16
+/*
+ *     This entries are indexed by fwmark, 
+ *     they hold a list of forwarded addr:port
+ */    
+
+struct ip_masq_mfw {
+       struct ip_masq_mfw *next;       /* linked list */
+       __u32 fwmark;                   /* key: firewall mark */
+       struct list_head hosts;         /* list of forward-to hosts */
+       atomic_t nhosts;                /* number of "" */
+#ifdef __SMP__
+       rwlock_t lock;
+#endif
+};
+
+
+static struct semaphore mfw_sema;
+#ifdef __SMP__
+static rwlock_t mfw_lock = RW_LOCK_UNLOCKED;
+#endif
+
+static struct ip_masq_mfw *ip_masq_mfw_table[IP_MASQ_MFW_HSIZE];
+
+static __inline__ int mfw_hash_val(int fwmark)
+{
+       return fwmark & 0x0f;
+}
+
+/*
+ *     Get m-entry by "fwmark"
+ *     Caller must lock tables.
+ */
+
+static struct ip_masq_mfw *__mfw_get(int fwmark)
+{
+       struct ip_masq_mfw* mfw;
+       int hash = mfw_hash_val(fwmark);
+
+       for (mfw=ip_masq_mfw_table[hash];mfw;mfw=mfw->next) {
+               if (mfw->fwmark==fwmark) {
+                       goto out;
+               }
+       }
+out:
+       return mfw;
+}
+
+/*
+ *     Links m-entry.
+ *     Caller should have checked if already present for same fwmark
+ *
+ *     Caller must lock tables.
+ */
+static int __mfw_add(struct ip_masq_mfw *mfw)
+{
+       int fwmark = mfw->fwmark;
+       int hash = mfw_hash_val(fwmark);
+
+       mfw->next = ip_masq_mfw_table[hash];
+       ip_masq_mfw_table[hash] = mfw;
+       ip_masq_mod_inc_nent(mmod_self);
+
+       return 0;
+}
+
+/*
+ *     Creates a m-entry (doesn't link it)
+ */
+
+static struct ip_masq_mfw * mfw_new(int fwmark)
+{
+       struct ip_masq_mfw *mfw;
+
+       mfw = kmalloc(sizeof(*mfw), GFP_KERNEL);
+       if (mfw == NULL) 
+               goto out;
+
+       MOD_INC_USE_COUNT;
+       memset(mfw, 0, sizeof(*mfw));
+       mfw->fwmark = fwmark;
+#ifdef __SMP__
+       mfw->lock = (rwlock_t) RW_LOCK_UNLOCKED;
+#endif
+
+       INIT_LIST_HEAD(&mfw->hosts);
+out:
+       return mfw;
+}
+
+static void mfw_host_to_user(struct ip_masq_mfw_host *h, struct ip_mfw_user *mu)
+{
+       mu->raddr = h->addr;
+       mu->rport = h->port;
+       mu->fwmark = h->fwmark;
+       mu->pref = h->pref;
+}
+
+/*
+ *     Creates a m.host (doesn't link it in a m-entry)
+ */
+static struct ip_masq_mfw_host * mfw_host_new(struct ip_mfw_user *mu)
+{
+       struct ip_masq_mfw_host * mfw_host;
+       mfw_host = kmalloc(sizeof (*mfw_host), GFP_KERNEL);
+       if (!mfw_host)
+               return NULL;
+
+       MOD_INC_USE_COUNT;
+       memset(mfw_host, 0, sizeof(*mfw_host));
+       mfw_host->addr = mu->raddr;
+       mfw_host->port = mu->rport;
+       mfw_host->fwmark = mu->fwmark;
+       mfw_host->pref = mu->pref;
+       atomic_set(&mfw_host->pref_cnt, mu->pref);
+
+       return mfw_host;
+}
+
+/*
+ *     Create AND link m.host to m-entry.
+ *     It locks m.lock.
+ */
+static int mfw_addhost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu, int attail)
+{
+       struct ip_masq_mfw_host *mfw_host;
+
+       mfw_host = mfw_host_new(mu);
+       if (!mfw_host) 
+               return -ENOMEM;
+
+       write_lock_bh(&mfw->lock);
+       list_add(&mfw_host->list, attail? mfw->hosts.prev : &mfw->hosts);
+       atomic_inc(&mfw->nhosts);
+       write_unlock_bh(&mfw->lock);
+
+       return 0;
+}
+
+/*
+ *     Unlink AND destroy m.host(s) from m-entry.
+ *     Wildcard (nul host or addr) ok.
+ *     It uses m.lock.
+ */
+static int mfw_delhost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu)
+{
+
+       struct list_head *l,*e;
+       struct ip_masq_mfw_host *h;
+       int n_del = 0;
+       l = &mfw->hosts;
+
+       write_lock_bh(&mfw->lock);
+       for (e=l->next; e!=l; e=e->next)
+       {
+               h = list_entry(e, struct ip_masq_mfw_host, list);
+               if ((!mu->raddr || h->addr == mu->raddr) && 
+                       (!mu->rport || h->port == mu->rport)) {
+                       /* HIT */
+                       atomic_dec(&mfw->nhosts);
+                       list_del(&h->list);
+                       kfree_s(h, sizeof(*h));
+                       MOD_DEC_USE_COUNT;
+                       n_del++;
+               }
+                               
+       }
+       write_unlock_bh(&mfw->lock);
+       return n_del? 0 : -ESRCH;
+}
+
+/*
+ *     Changes m.host parameters
+ *     Wildcards ok
+ *
+ *     Caller must lock tables.
+ */
+static int __mfw_edithost(struct ip_masq_mfw *mfw, struct ip_mfw_user *mu)
+{
+
+       struct list_head *l,*e;
+       struct ip_masq_mfw_host *h;
+       int n_edit = 0;
+       l = &mfw->hosts;
+
+       for (e=l->next; e!=l; e=e->next)
+       {
+               h = list_entry(e, struct ip_masq_mfw_host, list);
+               if ((!mu->raddr || h->addr == mu->raddr) && 
+                       (!mu->rport || h->port == mu->rport)) {
+                       /* HIT */
+                       h->pref = mu->pref;
+                       atomic_set(&h->pref_cnt, mu->pref);
+                       n_edit++;
+               }
+                               
+       }
+       return n_edit? 0 : -ESRCH;
+}
+
+/*
+ *     Destroys m-entry.
+ *     Caller must have checked that it doesn't hold any m.host(s)
+ */
+static void mfw_destroy(struct ip_masq_mfw *mfw)
+{
+       kfree_s(mfw, sizeof(*mfw));
+       MOD_DEC_USE_COUNT;
+}
+
+/* 
+ *     Unlink m-entry.
+ *
+ *     Caller must lock tables.
+ */
+static int __mfw_del(struct ip_masq_mfw *mfw)
+{
+       struct ip_masq_mfw **mfw_p;
+       int ret = -EINVAL;
+
+
+       for(mfw_p=&ip_masq_mfw_table[mfw_hash_val(mfw->fwmark)]; 
+                       *mfw_p; 
+                       mfw_p = &((*mfw_p)->next)) 
+       {
+               if (mfw==(*mfw_p)) {
+                       *mfw_p = mfw->next;
+                       ip_masq_mod_dec_nent(mmod_self);
+                       ret = 0;
+                       goto out;
+               }
+       }
+out:
+       return ret;
+}
+
+/*
+ *     Crude m.host scheduler
+ *     This interface could be exported to allow playing with 
+ *     other sched policies.
+ *
+ *     Caller must lock m-entry.
+ */
+static struct ip_masq_mfw_host * __mfw_sched(struct ip_masq_mfw *mfw, int force)
+{
+       struct ip_masq_mfw_host *h = NULL;
+
+       if (atomic_read(&mfw->nhosts) == 0)
+               goto out;
+
+       /*
+        *      Here resides actual sched policy: 
+        *      When pref_cnt touches 0, entry gets shifted to tail and
+        *      its pref_cnt reloaded from h->pref (actual value
+        *      passed from u-space).
+        *
+        *      Exception is pref==0: avoid scheduling.
+        */
+
+       h = list_entry(mfw->hosts.next, struct ip_masq_mfw_host, list);
+
+       if (atomic_read(&mfw->nhosts) <= 1)
+               goto out;
+
+       if ((h->pref && atomic_dec_and_test(&h->pref_cnt)) || force) {
+               atomic_set(&h->pref_cnt, h->pref);
+               list_del(&h->list);
+               list_add(&h->list, mfw->hosts.prev);
+       }
+out:
+       return h;
+}
+
+/*
+ *     Main lookup routine.
+ *     HITs fwmark and schedules m.host entries if required
+ */
+static struct ip_masq_mfw_host * mfw_lookup(int fwmark)
+{
+       struct ip_masq_mfw *mfw;
+       struct ip_masq_mfw_host *h = NULL;
+
+       read_lock(&mfw_lock);
+       mfw = __mfw_get(fwmark);
+
+       if (mfw) {
+               write_lock(&mfw->lock);
+               h = __mfw_sched(mfw, 0);
+               write_unlock(&mfw->lock);
+       }
+
+       read_unlock(&mfw_lock);
+       return h;
+}
+
+#ifdef CONFIG_PROC_FS
+static int mfw_procinfo(char *buffer, char **start, off_t offset,
+                             int length, int dummy)
+{
+       struct ip_masq_mfw *mfw;
+       struct ip_masq_mfw_host *h;
+       struct list_head *l,*e;
+       off_t pos=0, begin;
+       char temp[129];
+        int idx = 0;
+       int len=0;
+
+       MOD_INC_USE_COUNT;
+
+       IP_MASQ_DEBUG(1-debug, "Entered mfw_info\n");
+
+       if (offset < 64)
+       {
+                sprintf(temp, "FwMark > RAddr    RPort PrCnt  Pref");
+               len = sprintf(buffer, "%-63s\n", temp);
+       }
+       pos = 64;
+
+        for(idx = 0; idx < IP_MASQ_MFW_HSIZE; idx++)
+       {
+               read_lock(&mfw_lock);
+               for(mfw = ip_masq_mfw_table[idx]; mfw ; mfw = mfw->next)
+               {
+                       read_lock_bh(&mfw->lock);
+                       l=&mfw->hosts;
+
+                       for(e=l->next;l!=e;e=e->next) {
+                               h = list_entry(e, struct ip_masq_mfw_host, list);
+                               pos += 64;
+                               if (pos <= offset) {
+                                       len = 0;
+                                       continue;
+                               }
+
+                               sprintf(temp,"0x%x > %08lX %5u %5d %5d",
+                                               h->fwmark,
+                                               ntohl(h->addr), ntohs(h->port),
+                                               atomic_read(&h->pref_cnt), h->pref);
+                               len += sprintf(buffer+len, "%-63s\n", temp);
+
+                               if(len >= length) {
+                                       read_unlock_bh(&mfw->lock);
+                                       read_unlock(&mfw_lock);
+                                       goto done;
+                               }
+                       }
+                       read_unlock_bh(&mfw->lock);
+               }
+               read_unlock(&mfw_lock);
+       }
+
+done:
+
+       if (len) {
+               begin = len - (pos - offset);
+               *start = buffer + begin;
+               len -= begin;
+       }
+       if(len>length)
+               len = length;
+       MOD_DEC_USE_COUNT;
+       return len;
+}
+static struct proc_dir_entry mfw_proc_entry = {
+/*             0, 0, NULL", */
+               0, 3, "mfw",
+               S_IFREG | S_IRUGO, 1, 0, 0,
+               0, &proc_net_inode_operations,
+               mfw_procinfo
+};
+
+#define proc_ent &mfw_proc_entry
+#else /* !CONFIG_PROC_FS */
+
+#define proc_ent NULL
+#endif
+
+
+static void mfw_flush(void)
+{
+       struct ip_masq_mfw *mfw, *local_table[IP_MASQ_MFW_HSIZE];
+       struct ip_masq_mfw_host *h;
+       struct ip_masq_mfw *mfw_next;
+       int idx;
+       struct list_head *l,*e;
+
+       write_lock_bh(&mfw_lock);
+       memcpy(local_table, ip_masq_mfw_table, sizeof ip_masq_mfw_table);
+       memset(ip_masq_mfw_table, 0, sizeof ip_masq_mfw_table);
+       write_unlock_bh(&mfw_lock);
+
+       /*
+        *      For every hash table row ...
+        */
+       for(idx=0;idx<IP_MASQ_MFW_HSIZE;idx++) {
+
+               /*
+                *      For every m-entry in row ...
+                */
+               for(mfw=local_table[idx];mfw;mfw=mfw_next) {
+                       /*
+                        *      For every m.host in m-entry ...
+                        */
+                       l=&mfw->hosts;
+                       while((e=l->next) != l) {
+                               h = list_entry(e, struct ip_masq_mfw_host, list);
+                               atomic_dec(&mfw->nhosts);
+                               list_del(&h->list);
+                               kfree_s(h, sizeof(*h));
+                               MOD_DEC_USE_COUNT;
+                       }
+
+                       if (atomic_read(&mfw->nhosts)) {
+                               IP_MASQ_ERR("mfw_flush(): after flushing row nhosts=%d\n",
+                                               atomic_read(&mfw->nhosts));
+                       }
+                       mfw_next = mfw->next;
+                       kfree_s(mfw, sizeof(*mfw));     
+                       MOD_DEC_USE_COUNT;
+                       ip_masq_mod_dec_nent(mmod_self);
+               }
+       }
+}
+
+/*
+ *     User space control entry point
+ */
+static int mfw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
+{
+        struct ip_mfw_user *mu =  &mctl->u.mfw_user;
+       struct ip_masq_mfw *mfw;
+       int ret = EINVAL;
+       int arglen = optlen - IP_MASQ_CTL_BSIZE;
+       int cmd;
+
+
+       IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n",
+               arglen,
+               sizeof (*mu),
+               optlen,
+               sizeof (*mctl));
+
+       /*
+        *      checks ...
+        */
+       if (arglen != sizeof(*mu) && optlen != sizeof(*mctl)) 
+               return -EINVAL;
+       /* 
+        *      Don't trust the lusers - plenty of error checking! 
+        */
+       cmd = mctl->m_cmd;
+       IP_MASQ_DEBUG(1-debug, "ip_masq_mfw_ctl(cmd=%d, fwmark=%d)\n",
+                       cmd, mu->fwmark);
+
+
+       switch(cmd) {
+               case IP_MASQ_CMD_NONE:
+                       return 0;
+               case IP_MASQ_CMD_FLUSH:
+                       break;
+               case IP_MASQ_CMD_ADD:
+               case IP_MASQ_CMD_INSERT:
+               case IP_MASQ_CMD_SET:
+                       if (mu->fwmark == 0) {
+                               IP_MASQ_DEBUG(1-debug, "invalid fwmark==0\n");
+                               return -EINVAL;
+                       }
+                       if (mu->pref < 0) {
+                               IP_MASQ_DEBUG(1-debug, "invalid pref==%d\n",
+                                       mu->pref);
+                               return -EINVAL;
+                       }
+                       break;
+       }
+
+
+       ret = -EINVAL;
+
+       switch(cmd) {
+       case IP_MASQ_CMD_ADD:
+       case IP_MASQ_CMD_INSERT:
+               if (!mu->raddr) {
+                       IP_MASQ_DEBUG(0-debug, "ip_masq_mfw_ctl(ADD): invalid redirect 0x%x:%d\n",
+                                       mu->raddr, mu->rport);
+                       goto out;
+               }
+
+               /*
+                *      Cannot just use mfw_lock because below
+                *      are allocations that can sleep; so
+                *      to assure "new entry" atomic creation
+                *      I use a semaphore.
+                *
+                */
+               down(&mfw_sema);
+
+               read_lock(&mfw_lock);
+               mfw = __mfw_get(mu->fwmark);
+               read_unlock(&mfw_lock);
+               
+               /*
+                *      If first host, create m-entry
+                */
+               if (mfw == NULL) {
+                       mfw = mfw_new(mu->fwmark);
+                       if (mfw == NULL) 
+                               ret = -ENOMEM;
+               } 
+
+               if (mfw) {
+                       /*
+                        *      Put m.host in m-entry.
+                        */
+                       ret = mfw_addhost(mfw, mu, cmd == IP_MASQ_CMD_ADD);
+
+                       /*
+                        *      If first host, link m-entry to hash table.
+                        *      Already protected by global lock.
+                        */
+                       if (ret == 0 && atomic_read(&mfw->nhosts) == 1)  {
+                               write_lock_bh(&mfw_lock);
+                               __mfw_add(mfw);
+                               write_unlock_bh(&mfw_lock);
+                       } 
+                       if (atomic_read(&mfw->nhosts) == 0) {
+                               mfw_destroy(mfw);
+                       }
+               }
+
+               up(&mfw_sema);
+
+               break;
+
+       case IP_MASQ_CMD_DEL:
+               down(&mfw_sema);
+
+               read_lock(&mfw_lock);
+               mfw = __mfw_get(mu->fwmark);
+               read_unlock(&mfw_lock);
+
+               if (mfw) {
+                       ret = mfw_delhost(mfw, mu);
+
+                       /*
+                        *      Last lease will free
+                        *      XXX check logic XXX
+                        */
+                       if (atomic_read(&mfw->nhosts) == 0) {
+                               write_lock_bh(&mfw_lock);
+                               __mfw_del(mfw);
+                               write_unlock_bh(&mfw_lock);
+                               mfw_destroy(mfw);
+                       }
+               } else 
+                       ret = -ESRCH;
+
+               up(&mfw_sema);
+               break;
+       case IP_MASQ_CMD_FLUSH:
+
+               down(&mfw_sema);
+               mfw_flush();
+               up(&mfw_sema);
+               ret = 0;
+               break;
+       case IP_MASQ_CMD_SET:
+               /*
+                *      No need to semaphorize here, main list is not 
+                *      modified.
+                */
+               read_lock(&mfw_lock);
+               
+               mfw = __mfw_get(mu->fwmark);
+               if (mfw) {
+                       write_lock_bh(&mfw->lock);
+                       
+                       if (mu->flags & IP_MASQ_MFW_SCHED) {
+                               struct ip_masq_mfw_host *h;
+                               if ((h=__mfw_sched(mfw, 1))) {
+                                       mfw_host_to_user(h, mu);
+                                       ret = 0;
+                               } 
+                       } else {
+                               ret = __mfw_edithost(mfw, mu);
+                       }
+                               
+                       write_unlock_bh(&mfw->lock);
+               }
+
+               read_unlock(&mfw_lock);
+               break;
+       }
+out:
+       
+       return ret;
+}
+
+/*
+ *     Module stubs called from ip_masq core module
+ */
+/*
+ *     Input rule stub, called very early for each incoming packet, 
+ *     to see if this module has "interest" in packet.
+ */
+static int mfw_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
+{
+       int val;
+       read_lock(&mfw_lock);
+       val = ( __mfw_get(skb->fwmark) != 0);
+       read_unlock(&mfw_lock);
+       return val;
+}
+
+/*
+ *     Input-create stub, called to allow "custom" masq creation
+ */
+static struct ip_masq * mfw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
+{
+       union ip_masq_tphdr tph;
+       struct ip_masq *ms = NULL;
+       struct ip_masq_mfw_host *h = NULL;
+
+       tph.raw = (char*) iph + iph->ihl * 4;
+
+       switch (iph->protocol) {
+               case IPPROTO_TCP:
+                       /*      
+                        *      Only open TCP tunnel if SYN+!ACK packet
+                        */
+                       if (!tph.th->syn && tph.th->ack)
+                               return NULL;
+               case IPPROTO_UDP:
+                       break;
+               default:
+                       return NULL;
+       }
+
+       /* 
+        *      If no entry exists in the masquerading table
+        *      and the port is involved
+        *      in port forwarding, create a new masq entry 
+        */
+
+       if ((h=mfw_lookup(skb->fwmark))) {
+               ms = ip_masq_new(iph->protocol,
+                               iph->daddr, tph.portp[1],       
+                               /* if no redir-port, use packet dest port */
+                               h->addr, h->port? h->port : tph.portp[1],
+                               iph->saddr, tph.portp[0],
+                               0);
+
+               if (ms != NULL)
+                       ip_masq_listen(ms);
+       }
+       return ms;
+}
+
+
+#define mfw_in_update  NULL
+#define mfw_out_rule   NULL
+#define mfw_out_create NULL
+#define mfw_out_update NULL
+
+static struct ip_masq_mod mfw_mod = {
+       NULL,                   /* next */
+       NULL,                   /* next_reg */
+       "mfw",          /* name */
+       ATOMIC_INIT(0),         /* nent */
+       ATOMIC_INIT(0),         /* refcnt */
+       proc_ent,
+       mfw_ctl,
+       NULL,                   /* masq_mod_init */
+       NULL,                   /* masq_mod_done */
+       mfw_in_rule,
+       mfw_in_update,
+       mfw_in_create,
+       mfw_out_rule,
+       mfw_out_update,
+       mfw_out_create,
+};
+
+
+__initfunc(int ip_mfw_init(void))
+{
+       sema_init(&mfw_sema, 1);
+       return register_ip_masq_mod ((mmod_self=&mfw_mod));
+}
+
+int ip_mfw_done(void)
+{
+       return unregister_ip_masq_mod(&mfw_mod);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+       if (ip_mfw_init() != 0)
+               return -EIO;
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       if (ip_mfw_done() != 0)
+               printk(KERN_INFO "can't remove module");
+}
+
+#endif /* MODULE */
index 4384d9cf6bcf37426e49663984afed9bac79f890..ad26674013d897e445913d2ab78740a40ec2f382 100644 (file)
@@ -2,7 +2,7 @@
  *             IP_MASQ_PORTFW masquerading module
  *
  *
- *     $Id: ip_masq_portfw.c,v 1.2 1998/08/29 23:51:11 davem Exp $
+ *     $Id: ip_masq_portfw.c,v 1.3 1998/12/08 05:42:12 davem Exp $
  *
  * Author:     Steven Clarke <steven.clarke@monmouth.demon.co.uk>
  *
@@ -269,15 +269,18 @@ static __inline__ int portfw_ctl(int optname, struct ip_masq_ctl *mctl, int optl
        IP_MASQ_DEBUG(1-debug, "ip_masq_portfw_ctl(cmd=%d)\n", cmd);
 
 
-        if (cmd != IP_MASQ_CMD_FLUSH) {
-               if (htons(mm->lport) < IP_PORTFW_PORT_MIN 
-                               || htons(mm->lport) > IP_PORTFW_PORT_MAX)
-                       return EINVAL;
-
-                if (mm->protocol!=IPPROTO_TCP && mm->protocol!=IPPROTO_UDP)
-                        return EINVAL;
-        }
+       switch (cmd) {
+               case IP_MASQ_CMD_NONE:
+                       return 0;
+               case IP_MASQ_CMD_FLUSH:
+                       break;
+               default:
+                       if (htons(mm->lport) < IP_PORTFW_PORT_MIN || htons(mm->lport) > IP_PORTFW_PORT_MAX)
+                               return EINVAL;
 
+                       if (mm->protocol!=IPPROTO_TCP && mm->protocol!=IPPROTO_UDP)
+                               return EINVAL;
+       }
 
        switch(cmd) {
        case IP_MASQ_CMD_ADD:
index 5edfbef938d13aab7c386ee8643958765b794bf9..8e486a9b1c4af4ff3b79eb503542f84aeeca4af4 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The Internet Protocol (IP) output module.
  *
- * Version:    $Id: ip_output.c,v 1.63 1998/10/03 09:37:30 davem Exp $
+ * Version:    $Id: ip_output.c,v 1.64 1999/01/04 20:05:33 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -461,7 +461,7 @@ int ip_build_xmit_slow(struct sock *sk,
        id = htons(ip_id_count++);
 
        /*
-        *      Being outputting the bytes.
+        *      Begin outputting the bytes.
         */
         
        do {
index 4a3f2a747d82aeffe57d445e1548f7e0aac18f66..b3d62b5689c132775e4cab969ba721179e7b4844 100644 (file)
@@ -1,13 +1,17 @@
 /*
- *  $Id: ipconfig.c,v 1.16 1998/10/21 22:27:26 davem Exp $
+ *  $Id: ipconfig.c,v 1.18 1999/01/04 20:14:10 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
  *
- *  Copyright (C) 1996, 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *  Copyright (C) 1996--1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  *
  *  Derived from network configuration code in fs/nfs/nfsroot.c,
  *  originally Copyright (C) 1995, 1996 Gero Kuhlmann and me.
+ *
+ *  BOOTP rewritten to construct and analyse packets itself instead
+ *  of misusing the IP layer. num_bugs_causing_wrong_arp_replies--;
+ *                                          -- MJ, December 1998
  */
 
 #include <linux/config.h>
 #include <linux/in.h>
 #include <linux/if.h>
 #include <linux/inet.h>
-#include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
 #include <linux/socket.h>
-#include <linux/inetdevice.h>
 #include <linux/route.h>
-#include <net/route.h>
-#include <net/sock.h>
+#include <linux/udp.h>
 #include <net/arp.h>
-#include <net/ip_fib.h>
+#include <net/ip.h>
 #include <net/ipconfig.h>
 
 #include <asm/segment.h>
 #include <asm/uaccess.h>
+#include <asm/checksum.h>
 
 /* Define this to allow debugging output */
 #undef IPCONFIG_DEBUG
@@ -60,8 +62,6 @@ u32 ic_myaddr __initdata = INADDR_NONE;               /* My IP address */
 u32 ic_servaddr __initdata = INADDR_NONE;      /* Server IP address */
 u32 ic_gateway __initdata = INADDR_NONE;       /* Gateway IP address */
 u32 ic_netmask __initdata = INADDR_NONE;       /* Netmask for local subnet */
-int ic_bootp_flag __initdata = 1;              /* Use BOOTP */
-int ic_rarp_flag __initdata = 1;               /* Use RARP */
 int ic_enable __initdata = 1;                  /* Automatic IP configuration enabled */
 int ic_host_name_set __initdata = 0;           /* Host name configured manually */
 int ic_set_manually __initdata = 0;            /* IPconfig parameters set manually */
@@ -73,13 +73,17 @@ u8 root_server_path[256] __initdata = { 0, };               /* Path to mount as root */
 
 #define CONFIG_IP_PNP_DYNAMIC
 
-static int ic_got_reply __initdata = 0;
+static int ic_proto_enabled __initdata = IC_BOOTP | IC_RARP;   /* Protocols enabled */
+static int ic_got_reply __initdata = 0;                                /* Protocol(s) we got reply from */
+
+#else
 
-#define IC_GOT_BOOTP 1
-#define IC_GOT_RARP 2
+static int ic_proto_enabled __initdata = 0;
 
 #endif
 
+static int ic_proto_have_if __initdata = 0;
+
 /*
  *     Network devices
  */
@@ -88,14 +92,13 @@ struct ic_device {
        struct ic_device *next;
        struct device *dev;
        unsigned short flags;
+       int able;
 };
 
 static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
 static struct device *ic_dev __initdata = NULL;                /* Selected device */
-static int bootp_dev_count __initdata = 0;             /* BOOTP capable devices */
-static int rarp_dev_count __initdata = 0;              /* RARP capable devices */
 
-__initfunc(int ic_open_devs(void))
+static int __init ic_open_devs(void)
 {
        struct ic_device *d, **last;
        struct device *dev;
@@ -103,10 +106,20 @@ __initfunc(int ic_open_devs(void))
 
        last = &ic_first_dev;
        for (dev = dev_base; dev; dev = dev->next)
-               if (dev->type < ARPHRD_SLIP &&
-                   !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) &&
-                   strncmp(dev->name, "dummy", 5) &&
-                   (!user_dev_name[0] || !strcmp(dev->name, user_dev_name))) {
+               if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
+                   (!(dev->flags & IFF_LOOPBACK) &&
+                    (dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) &&
+                    strncmp(dev->name, "dummy", 5))) {
+                       int able = 0;
+                       if (dev->mtu >= 364)
+                               able |= IC_BOOTP;
+                       else
+                               printk(KERN_WARNING "BOOTP: Ignoring device %s, MTU %d too small", dev->name, dev->mtu);
+                       if (!(dev->flags & IFF_NOARP))
+                               able |= IC_RARP;
+                       able &= ic_proto_enabled;
+                       if (ic_proto_enabled && !able)
+                               continue;
                        oflags = dev->flags;
                        if (dev_change_flags(dev, oflags | IFF_UP) < 0) {
                                printk(KERN_ERR "IP-Config: Failed to open %s\n", dev->name);
@@ -118,14 +131,13 @@ __initfunc(int ic_open_devs(void))
                        *last = d;
                        last = &d->next;
                        d->flags = oflags;
-                       bootp_dev_count++;
-                       if (!(dev->flags & IFF_NOARP))
-                               rarp_dev_count++;
-                       DBG(("IP-Config: Opened %s\n", dev->name));
+                       d->able = able;
+                       ic_proto_have_if |= able;
+                       DBG(("IP-Config: Opened %s (able=%d)\n", dev->name, able));
                }
        *last = NULL;
 
-       if (!bootp_dev_count) {
+       if (!ic_first_dev) {
                if (user_dev_name[0])
                        printk(KERN_ERR "IP-Config: Device `%s' not found.\n", user_dev_name);
                else
@@ -135,7 +147,7 @@ __initfunc(int ic_open_devs(void))
        return 0;
 }
 
-__initfunc(void ic_close_devs(void))
+static void __init ic_close_devs(void)
 {
        struct ic_device *d, *next;
        struct device *dev;
@@ -164,7 +176,7 @@ set_sockaddr(struct sockaddr_in *sin, u32 addr, u16 port)
        sin->sin_port = port;
 }
 
-__initfunc(static int ic_dev_ioctl(unsigned int cmd, struct ifreq *arg))
+static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg)
 {
        int res;
 
@@ -175,7 +187,7 @@ __initfunc(static int ic_dev_ioctl(unsigned int cmd, struct ifreq *arg))
        return res;
 }
 
-__initfunc(static int ic_route_ioctl(unsigned int cmd, struct rtentry *arg))
+static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg)
 {
        int res;
 
@@ -190,7 +202,7 @@ __initfunc(static int ic_route_ioctl(unsigned int cmd, struct rtentry *arg))
  *     Set up interface addresses and routes.
  */
 
-__initfunc(static int ic_setup_if(void))
+static int __init ic_setup_if(void)
 {
        struct ifreq ir;
        struct sockaddr_in *sin = (void *) &ir.ifr_ifru.ifru_addr;
@@ -216,7 +228,7 @@ __initfunc(static int ic_setup_if(void))
        return 0;
 }
 
-__initfunc(int ic_setup_routes(void))
+static int __init ic_setup_routes(void)
 {
        /* No need to setup device routes, only the default route... */
 
@@ -246,7 +258,7 @@ __initfunc(int ic_setup_routes(void))
  *     Fill in default values for all missing parameters.
  */
 
-__initfunc(int ic_defaults(void))
+static int __init ic_defaults(void)
 {
        /*
         *      At this point we have no userspace running so need not
@@ -270,6 +282,7 @@ __initfunc(int ic_defaults(void))
                        printk(KERN_ERR "IP-Config: Unable to guess netmask for address %08x\n", ic_myaddr);
                        return -1;
                }
+               printk("IP-Config: Guessing netmask %s\n", in_ntoa(ic_netmask));
        }
 
        return 0;
@@ -281,25 +294,22 @@ __initfunc(int ic_defaults(void))
 
 #ifdef CONFIG_IP_PNP_RARP
 
-static int ic_rarp_recv(struct sk_buff *skb, struct device *dev,
-                       struct packet_type *pt);
+static int ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt);
 
 static struct packet_type rarp_packet_type __initdata = {
-       0,                      /* Should be: __constant_htons(ETH_P_RARP)
-                                * - but this _doesn't_ come out constant! */
+       __constant_htons(ETH_P_RARP),
        NULL,                   /* Listen to all devices */
        ic_rarp_recv,
        NULL,
        NULL
 };
 
-__initfunc(static void ic_rarp_init(void))
+static inline void ic_rarp_init(void)
 {
-       rarp_packet_type.type = htons(ETH_P_RARP);
        dev_add_pack(&rarp_packet_type);
 }
 
-__initfunc(static void ic_rarp_cleanup(void))
+static inline void ic_rarp_cleanup(void)
 {
        dev_remove_pack(&rarp_packet_type);
 }
@@ -307,14 +317,18 @@ __initfunc(static void ic_rarp_cleanup(void))
 /*
  *  Process received RARP packet.
  */
-__initfunc(static int
-ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt))
+static int __init
+ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 {
        struct arphdr *rarp = (struct arphdr *)skb->h.raw;
        unsigned char *rarp_ptr = (unsigned char *) (rarp + 1);
        unsigned long sip, tip;
        unsigned char *sha, *tha;               /* s for "source", t for "target" */
 
+       /* If we already have a reply, just drop the packet */
+       if (ic_got_reply)
+               goto drop;
+
        /* If this test doesn't pass, it's not IP, or we should ignore it anyway */
        if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd))
                goto drop;
@@ -346,7 +360,7 @@ ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt))
 
        /* Victory! The packet is what we were looking for! */
        if (!ic_got_reply) {
-               ic_got_reply = IC_GOT_RARP;
+               ic_got_reply = IC_RARP;
                ic_dev = dev;
                if (ic_myaddr == INADDR_NONE)
                        ic_myaddr = tip;
@@ -363,16 +377,16 @@ drop:
 /*
  *  Send RARP request packet over all devices which allow RARP.
  */
-__initfunc(static void ic_rarp_send(void))
+static void __init ic_rarp_send(void)
 {
        struct ic_device *d;
 
-       for (d=ic_first_dev; d; d=d->next) {
-               struct device *dev = d->dev;
-               if (!(dev->flags & IFF_NOARP))
+       for (d=ic_first_dev; d; d=d->next)
+               if (d->able & IC_RARP) {
+                       struct device *dev = d->dev;
                        arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
                                 dev->dev_addr, dev->dev_addr);
-       }
+               }
 }
 
 #endif
@@ -383,10 +397,9 @@ __initfunc(static void ic_rarp_send(void))
 
 #ifdef CONFIG_IP_PNP_BOOTP
 
-static struct socket *ic_bootp_xmit_sock __initdata = NULL; /* BOOTP send socket */
-static struct socket *ic_bootp_recv_sock __initdata = NULL; /* BOOTP receive socket */
-
 struct bootp_pkt {             /* BOOTP packet format */
+       struct iphdr iph;       /* IP header */
+       struct udphdr udph;     /* UDP header */
        u8 op;                  /* 1=request, 2=reply */
        u8 htype;               /* HW address type */
        u8 hlen;                /* HW address length */
@@ -407,150 +420,23 @@ struct bootp_pkt {               /* BOOTP packet format */
 #define BOOTP_REQUEST 1
 #define BOOTP_REPLY 2
 
-static struct bootp_pkt *ic_xmit_bootp __initdata = NULL; /* Packet being transmitted */
-static struct bootp_pkt *ic_recv_bootp __initdata = NULL; /* Packet being received */
-
-/*
- *  Allocation and freeing of BOOTP packet buffers.
- */
-__initfunc(static int ic_bootp_alloc(void))
-{
-       if (!(ic_xmit_bootp = kmalloc(sizeof(struct bootp_pkt), GFP_KERNEL)) ||
-           !(ic_recv_bootp = kmalloc(sizeof(struct bootp_pkt), GFP_KERNEL))) {
-               printk(KERN_ERR "BOOTP: Out of memory!\n");
-               return -1;
-       }
-       return 0;
-}
-
-__initfunc(static void ic_bootp_free(void))
-{
-       if (ic_xmit_bootp) {
-               kfree_s(ic_xmit_bootp, sizeof(struct bootp_pkt));
-               ic_xmit_bootp = NULL;
-       }
-       if (ic_recv_bootp) {
-               kfree_s(ic_recv_bootp, sizeof(struct bootp_pkt));
-               ic_recv_bootp = NULL;
-       }
-}
-
-
-/*
- *  Add / Remove fake interface addresses for BOOTP packet sending.
- */
-__initfunc(static int ic_bootp_addrs_add(void))
-{
-       struct ic_device *d;
-       int err;
-
-       for(d=ic_first_dev; d; d=d->next)
-               if ((err = inet_add_bootp_addr(d->dev)) < 0) {
-                       printk(KERN_ERR "BOOTP: Unable to set interface address\n");
-                       return -1;
-               }
-       return 0;
-}
-
-__initfunc(static void ic_bootp_addrs_del(void))
-{
-       struct ic_device *d;
-
-       for(d=ic_first_dev; d; d=d->next)
-               inet_del_bootp_addr(d->dev);
-}
-
-/*
- *  UDP socket operations.
- */
-__initfunc(static int ic_udp_open(struct socket **sock))
-{
-       int err;
-
-       if ((err = sock_create(PF_INET, SOCK_DGRAM, IPPROTO_UDP, sock)) < 0)
-               printk(KERN_ERR "BOOTP: Cannot open UDP socket!\n");
-       return err;
-}
-
-static inline void ic_udp_close(struct socket *sock)
-{
-       if (sock)
-               sock_release(sock);
-}
-
-__initfunc(static int ic_udp_connect(struct socket *sock, u32 addr, u16 port))
-{
-       struct sockaddr_in sa;
-       int err;
-
-       set_sockaddr(&sa, htonl(addr), htons(port));
-       err = sock->ops->connect(sock, (struct sockaddr *) &sa, sizeof(sa), 0);
-       if (err < 0) {
-               printk(KERN_ERR "BOOTP: connect() failed (%d)\n", err);
-               return -1;
-       }
-       return 0;
-}
-
-__initfunc(static int ic_udp_bind(struct socket *sock, u32 addr, u16 port))
-{
-       struct sockaddr_in sa;
-       int err;
-
-       set_sockaddr(&sa, htonl(addr), htons(port));
-       err = sock->ops->bind(sock, (struct sockaddr *) &sa, sizeof(sa));
-       if (err < 0) {
-               printk(KERN_ERR "BOOTP: bind() failed (%d)\n", err);
-               return -1;
-       }
-       return 0;
-}
-
-__initfunc(static int ic_udp_send(struct socket *sock, void *buf, int size))
-{
-       mm_segment_t oldfs;
-       int result;
-       struct msghdr msg;
-       struct iovec iov;
-
-       oldfs = get_fs();
-       set_fs(get_ds());
-       iov.iov_base = buf;
-       iov.iov_len = size;
-       memset(&msg, 0, sizeof(msg));
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-       result = sock_sendmsg(sock, &msg, size);
-       set_fs(oldfs);
-
-       return (result != size);
-}
+static u32 ic_bootp_xid;
 
-__initfunc(static int ic_udp_recv(struct socket *sock, void *buf, int size))
-{
-       mm_segment_t oldfs;
-       int result;
-       struct msghdr msg;
-       struct iovec iov;
+static int ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt);
 
-       oldfs = get_fs();
-       set_fs(get_ds());
-       iov.iov_base = buf;
-       iov.iov_len = size;
-       memset(&msg, 0, sizeof(msg));
-       msg.msg_flags = MSG_DONTWAIT;
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-       result = sock_recvmsg(sock, &msg, size, MSG_DONTWAIT);
-       set_fs(oldfs);
-       return result;
-}
+static struct packet_type bootp_packet_type __initdata = {
+       __constant_htons(ETH_P_IP),
+       NULL,                   /* Listen to all devices */
+       ic_bootp_recv,
+       NULL,
+       NULL
+};
 
 
 /*
  *  Initialize BOOTP extension fields in the request.
  */
-__initfunc(static void ic_bootp_init_ext(u8 *e))
+static void __init ic_bootp_init_ext(u8 *e)
 {
        *e++ = 99;              /* RFC1048 Magic Cookie */
        *e++ = 130;
@@ -578,92 +464,96 @@ __initfunc(static void ic_bootp_init_ext(u8 *e))
 /*
  *  Initialize the BOOTP mechanism.
  */
-__initfunc(static int ic_bootp_init(void))
+static inline void ic_bootp_init(void)
 {
-       /* Allocate memory for BOOTP packets */
-       if (ic_bootp_alloc() < 0)
-               return -1;
-
-       /* Add fake zero addresses to all interfaces */
-       if (ic_bootp_addrs_add() < 0)
-               return -1;
-       
-       /* Setting the addresses automatically creates appropriate
-          routes. */   
-
-       /* Initialize common portion of BOOTP request */
-       memset(ic_xmit_bootp, 0, sizeof(struct bootp_pkt));
-       ic_xmit_bootp->op = BOOTP_REQUEST;
-       get_random_bytes(&ic_xmit_bootp->xid, sizeof(ic_xmit_bootp->xid));
-       ic_bootp_init_ext(ic_xmit_bootp->vendor_area);
-
-       DBG(("BOOTP: XID=%08x\n", ic_xmit_bootp->xid));
-
-       /* Open the sockets */
-       if (ic_udp_open(&ic_bootp_xmit_sock) ||
-           ic_udp_open(&ic_bootp_recv_sock))
-               return -1;
-
-       /* Bind/connect the sockets */
-       ic_bootp_xmit_sock->sk->broadcast = 1;
-       ic_bootp_xmit_sock->sk->reuse = 1;
-       ic_bootp_recv_sock->sk->reuse = 1;
-       if (ic_udp_bind(ic_bootp_recv_sock, INADDR_ANY, 68) ||
-           ic_udp_bind(ic_bootp_xmit_sock, INADDR_ANY, 68) ||
-           ic_udp_connect(ic_bootp_xmit_sock, INADDR_BROADCAST, 67))
-               return -1;
-
-       return 0;
+       get_random_bytes(&ic_bootp_xid, sizeof(u32));
+       DBG(("BOOTP: XID=%08x\n", ic_bootp_xid));
+       dev_add_pack(&bootp_packet_type);
 }
 
 
 /*
  *  BOOTP cleanup.
  */
-__initfunc(static void ic_bootp_cleanup(void))
+static inline void ic_bootp_cleanup(void)
 {
-       ic_udp_close(ic_bootp_xmit_sock);
-       ic_udp_close(ic_bootp_recv_sock);
-       ic_bootp_addrs_del();
-       ic_bootp_free();
+       dev_remove_pack(&bootp_packet_type);
 }
 
 
 /*
  *  Send BOOTP request to single interface.
  */
-__initfunc(static int ic_bootp_send_if(struct ic_device *d, u32 jiffies))
+static void __init ic_bootp_send_if(struct ic_device *d, u32 jiffies)
 {
        struct device *dev = d->dev;
-       struct bootp_pkt *b = ic_xmit_bootp;
-
+       struct sk_buff *skb;
+       struct bootp_pkt *b;
+       int hh_len = (dev->hard_header_len + 15) & ~15;
+       struct iphdr *h;
+
+       /* Allocate packet */
+       skb = alloc_skb(sizeof(struct bootp_pkt) + hh_len + 15, GFP_KERNEL);
+       if (!skb)
+               return;
+       skb_reserve(skb, hh_len);
+       b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt));
+       memset(b, 0, sizeof(struct bootp_pkt));
+
+       /* Construct IP header */
+       skb->nh.iph = h = &b->iph;
+       h->version = 4;
+       h->ihl = 5;
+       h->tot_len = htons(sizeof(struct bootp_pkt));
+       h->frag_off = htons(IP_DF);
+       h->ttl = 1;
+       h->protocol = IPPROTO_UDP;
+       h->daddr = INADDR_BROADCAST;
+       h->check = 0;
+       h->check = ip_fast_csum((unsigned char *) h, h->ihl);
+
+       /* Construct UDP header */
+       b->udph.source = htons(68);
+       b->udph.dest = htons(67);
+       b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr));
+       /* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */
+
+       /* Construct BOOTP header */
+       b->op = BOOTP_REQUEST;
        b->htype = dev->type;
        b->hlen = dev->addr_len;
-       memset(b->hw_addr, 0, sizeof(b->hw_addr));
        memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
        b->secs = htons(jiffies / HZ);
-       return ic_udp_send(ic_bootp_xmit_sock, b, sizeof(struct bootp_pkt));
+       b->xid = ic_bootp_xid;
+       ic_bootp_init_ext(b->vendor_area);
+
+       /* Chain packet down the line... */
+       skb->dev = dev;
+       skb->protocol = __constant_htons(ETH_P_IP);
+       if ((dev->hard_header &&
+            dev->hard_header(skb, dev, ntohs(skb->protocol), dev->broadcast, dev->dev_addr, skb->len) < 0) ||
+           dev_queue_xmit(skb) < 0)
+               printk("E");
 }
 
 
 /*
  *  Send BOOTP requests to all interfaces.
  */
-__initfunc(static int ic_bootp_send(u32 jiffies))
+static void __init ic_bootp_send(u32 jiffies)
 {
        struct ic_device *d;
 
        for(d=ic_first_dev; d; d=d->next)
-               if (ic_bootp_send_if(d, jiffies) < 0)
-                       return -1;
-       return 0;
+               if (d->able & IC_BOOTP)
+                       ic_bootp_send_if(d, jiffies);
 }
 
 
 /*
  *  Copy BOOTP-supplied string if not already set.
  */
-__initfunc(static int ic_bootp_string(char *dest, char *src, int len, int max))
+static int __init ic_bootp_string(char *dest, char *src, int len, int max)
 {
        if (!len)
                return 0;
@@ -678,7 +568,7 @@ __initfunc(static int ic_bootp_string(char *dest, char *src, int len, int max))
 /*
  *  Process BOOTP extension.
  */
-__initfunc(static void ic_do_bootp_ext(u8 *ext))
+static void __init ic_do_bootp_ext(u8 *ext)
 {
 #ifdef IPCONFIG_DEBUG
        u8 *c;
@@ -714,65 +604,64 @@ __initfunc(static void ic_do_bootp_ext(u8 *ext))
 
 
 /*
- *  Receive BOOTP request.
+ *  Receive BOOTP reply.
  */
-__initfunc(static void ic_bootp_recv(void))
+static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 {
+       struct bootp_pkt *b = (struct bootp_pkt *) skb->nh.iph;
+       struct iphdr *h = &b->iph;
        int len;
-       u8 *ext, *end, *opt;
-       struct ic_device *d;
-       struct bootp_pkt *b = ic_recv_bootp;
 
-       if ((len = ic_udp_recv(ic_bootp_recv_sock, b, sizeof(struct bootp_pkt))) < 0)
-               return;
+       /* If we already have a reply, just drop the packet */
+       if (ic_got_reply)
+               goto drop;
 
-       /* Check consistency of incoming packet */
-       if (len < 300 ||                        /* See RFC 1542:2.1 */
-           b->op != BOOTP_REPLY ||
-           b->xid != ic_xmit_bootp->xid) {
-               printk("?");
-               return;
-               }
+       /* Check whether it's a BOOTP packet */
+       if (skb->pkt_type == PACKET_OTHERHOST ||
+           skb->len < sizeof(struct udphdr) + sizeof(struct iphdr) ||
+           h->ihl != 5 ||
+           h->version != 4 ||
+           ip_fast_csum((char *) h, h->ihl) != 0 ||
+           skb->len < ntohs(h->tot_len) ||
+           h->protocol != IPPROTO_UDP ||
+           b->udph.source != htons(67) ||
+           b->udph.dest != htons(68) ||
+           ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr))
+               goto drop;
 
-       /* Find interface this arrived from */
-       for(d=ic_first_dev; d; d=d->next) {
-               struct device *dev = d->dev;
-               if (b->htype == dev->type ||
-                   b->hlen == dev->addr_len ||
-                   !memcmp(b->hw_addr, dev->dev_addr, dev->addr_len))
-                       break;
-       }
-       if (!d) {       /* Unknown device */
-               printk("!");
-               return;
+       /* Fragments are not supported */
+       if (h->frag_off & htons(IP_OFFSET|IP_MF)) {
+               printk(KERN_ERR "BOOTP: Ignoring fragmented reply.\n");
+               goto drop;
        }
 
-       /* Record BOOTP packet arrival */
-       cli();
-       if (ic_got_reply) {
-               sti();
-               return;
+       /* Is it a reply to our BOOTP request? */
+       len = ntohs(b->udph.len) - sizeof(struct udphdr);
+       if (len < 300 ||                                    /* See RFC 951:2.1 */
+           b->op != BOOTP_REPLY ||
+           b->xid != ic_bootp_xid) {
+               printk("?");
+               goto drop;
        }
-       ic_got_reply = IC_GOT_BOOTP;
-       sti();
-       ic_dev = d->dev;
 
        /* Extract basic fields */
        ic_myaddr = b->your_ip;
        ic_servaddr = b->server_ip;
+       ic_got_reply = IC_BOOTP;
+       ic_dev = dev;
 
        /* Parse extensions */
        if (b->vendor_area[0] == 99 &&  /* Check magic cookie */
            b->vendor_area[1] == 130 &&
            b->vendor_area[2] == 83 &&
            b->vendor_area[3] == 99) {
-               ext = &b->vendor_area[4];
-               end = (u8 *) b + len;
+               u8 *ext = &b->vendor_area[4];
+               u8 *end = (u8 *) b + len;
                while (ext < end && *ext != 0xff) {
                        if (*ext == 0)          /* Padding */
                                ext++;
                        else {
-                               opt = ext;
+                               u8 *opt = ext;
                                ext += ext[1] + 2;
                                if (ext <= end)
                                        ic_do_bootp_ext(opt);
@@ -782,7 +671,12 @@ __initfunc(static void ic_bootp_recv(void))
 
        if (ic_gateway == INADDR_NONE && b->relay_ip)
                ic_gateway = b->relay_ip;
-}
+
+drop:
+       kfree_skb(skb);
+       return 0;
+}      
+
 
 #endif
 
@@ -793,11 +687,13 @@ __initfunc(static void ic_bootp_recv(void))
 
 #ifdef CONFIG_IP_PNP_DYNAMIC
 
-__initfunc(int ic_dynamic(void))
+static int __init ic_dynamic(void)
 {
        int retries;
        unsigned long timeout, jiff;
        unsigned long start_jiffies;
+       int do_rarp = ic_proto_have_if & IC_RARP;
+       int do_bootp = ic_proto_have_if & IC_BOOTP;
 
        /*
         * If neither BOOTP nor RARP was selected, return with an error. This
@@ -805,30 +701,22 @@ __initfunc(int ic_dynamic(void))
         * sing, and without BOOTP and RARP we are not able to get that in-
         * formation.
         */
-       if (!ic_bootp_flag && !ic_rarp_flag) {
+       if (!ic_proto_enabled) {
                printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n");
                return -1;
        }
 
 #ifdef CONFIG_IP_PNP_BOOTP
-       if (ic_bootp_flag && !bootp_dev_count) {
+       if ((ic_proto_enabled ^ ic_proto_have_if) & IC_BOOTP)
                printk(KERN_ERR "BOOTP: No suitable device found.\n");
-               ic_bootp_flag = 0;
-       }
-#else
-       ic_bootp_flag = 0;
 #endif
 
 #ifdef CONFIG_IP_PNP_RARP
-       if (ic_rarp_flag && !rarp_dev_count) {
+       if ((ic_proto_enabled ^ ic_proto_have_if) & IC_RARP)
                printk(KERN_ERR "RARP: No suitable device found.\n");
-               ic_rarp_flag = 0;
-       }
-#else
-       ic_rarp_flag = 0;
 #endif
 
-       if (!ic_bootp_flag && !ic_rarp_flag)
+       if (!ic_proto_have_if)
                /* Error message already printed */
                return -1;
 
@@ -836,14 +724,12 @@ __initfunc(int ic_dynamic(void))
         * Setup RARP and BOOTP protocols
         */
 #ifdef CONFIG_IP_PNP_RARP
-       if (ic_rarp_flag)
+       if (do_rarp)
                ic_rarp_init();
 #endif
 #ifdef CONFIG_IP_PNP_BOOTP
-       if (ic_bootp_flag && ic_bootp_init() < 0) {
-               ic_bootp_cleanup();
-               return -1;
-       }
+       if (do_bootp)
+               ic_bootp_init();
 #endif
 
        /*
@@ -855,36 +741,26 @@ __initfunc(int ic_dynamic(void))
         *  applies.. - AC]
         */
        printk(KERN_NOTICE "Sending %s%s%s requests...",
-               ic_bootp_flag ? "BOOTP" : "",
-               ic_bootp_flag && ic_rarp_flag ? " and " : "",
-               ic_rarp_flag ? "RARP" : "");
+               do_bootp ? "BOOTP" : "",
+               do_bootp && do_rarp ? " and " : "",
+               do_rarp ? "RARP" : "");
        start_jiffies = jiffies;
        retries = CONF_RETRIES;
        get_random_bytes(&timeout, sizeof(timeout));
        timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM);
        for(;;) {
 #ifdef CONFIG_IP_PNP_BOOTP
-               if (ic_bootp_flag && ic_bootp_send(jiffies - start_jiffies) < 0) {
-                       printk(" BOOTP failed!\n");
-                       ic_bootp_cleanup();
-                       ic_bootp_flag = 0;
-                       if (!ic_rarp_flag)
-                               break;
-               }
+               if (do_bootp)
+                       ic_bootp_send(jiffies - start_jiffies);
 #endif
 #ifdef CONFIG_IP_PNP_RARP
-               if (ic_rarp_flag)
+               if (do_rarp)
                        ic_rarp_send();
 #endif
                printk(".");
                jiff = jiffies + timeout;
                while (jiffies < jiff && !ic_got_reply)
-#ifdef CONFIG_IP_PNP_BOOTP
-                       if (ic_bootp_flag)
-                               ic_bootp_recv();
-#else
                        ;
-#endif
                if (ic_got_reply) {
                        printk(" OK\n");
                        break;
@@ -899,11 +775,11 @@ __initfunc(int ic_dynamic(void))
        }
 
 #ifdef CONFIG_IP_PNP_RARP
-       if (ic_rarp_flag)
+       if (do_rarp)
                ic_rarp_cleanup();
 #endif
 #ifdef CONFIG_IP_PNP_BOOTP
-       if (ic_bootp_flag)
+       if (do_bootp)
                ic_bootp_cleanup();
 #endif
 
@@ -911,7 +787,7 @@ __initfunc(int ic_dynamic(void))
                return -1;
 
        printk("IP-Config: Got %s answer from %s, ",
-               (ic_got_reply == IC_GOT_BOOTP) ? "BOOTP" : "RARP",
+               (ic_got_reply & IC_BOOTP) ? "BOOTP" : "RARP",
                in_ntoa(ic_servaddr));
        printk("my address is %s\n", in_ntoa(ic_myaddr));
 
@@ -924,7 +800,7 @@ __initfunc(int ic_dynamic(void))
  *     IP Autoconfig dispatcher.
  */
 
-__initfunc(int ip_auto_config(void))
+int __init ip_auto_config(void)
 {
        if (!ic_enable)
                return 0;
@@ -1000,25 +876,44 @@ __initfunc(int ip_auto_config(void))
  *     <device>        - use all available devices
  *     <bootp|rarp|both|off> - use both protocols to determine my own address
  */
-__initfunc(void ip_auto_config_setup(char *addrs, int *ints))
+static int __init ic_proto_name(char *name)
+{
+       if (!strcmp(name, "off")) {
+               ic_proto_enabled = 0;
+               return 1;
+       }
+#ifdef CONFIG_IP_PNP_BOOTP
+       else if (!strcmp(name, "bootp")) {
+               ic_proto_enabled &= ~IC_RARP;
+               return 1;
+       }
+#endif
+#ifdef CONFIG_IP_PNP_RARP
+       else if (!strcmp(name, "rarp")) {
+               ic_proto_enabled &= ~IC_BOOTP;
+               return 1;
+       }
+#endif
+#ifdef CONFIG_IP_PNP_DYNAMIC
+       else if (!strcmp(name, "both")) {
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+void __init ip_auto_config_setup(char *addrs, int *ints)
 {
        char *cp, *ip, *dp;
        int num = 0;
 
        ic_set_manually = 1;
-
-       if (!strcmp(addrs, "bootp")) {
-               ic_rarp_flag = 0;
-               return;
-       } else if (!strcmp(addrs, "rarp")) {
-               ic_bootp_flag = 0;
-               return;
-       } else if (!strcmp(addrs, "both")) {
-               return;
-       } else if (!strcmp(addrs, "off")) {
+       if (!strcmp(addrs, "off")) {
                ic_enable = 0;
                return;
        }
+       if (ic_proto_name(addrs))
+               return;
 
        /* Parse the whole string */
        ip = addrs;
@@ -1059,12 +954,7 @@ __initfunc(void ip_auto_config_setup(char *addrs, int *ints))
                                user_dev_name[IFNAMSIZ-1] = '\0';
                                break;
                        case 6:
-                               if (!strcmp(ip, "rarp"))
-                                       ic_bootp_flag = 0;
-                               else if (!strcmp(ip, "bootp"))
-                                       ic_rarp_flag = 0;
-                               else if (strcmp(ip, "both"))
-                                       ic_bootp_flag = ic_rarp_flag = 0;
+                               ic_proto_name(ip);
                                break;
                        }
                }
index 710a6077a169c97676062d127496a77d77ebd90c..1cf62e91ae2f47d715da594e8b71d46c0e48a4a2 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             ROUTE - implementation of the IP router.
  *
- * Version:    $Id: route.c,v 1.58 1998/10/03 09:37:50 davem Exp $
+ * Version:    $Id: route.c,v 1.60 1999/01/04 20:14:52 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -950,10 +950,6 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
        if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr))
                goto martian_destination;
 
-       /* Accept anything arriving at 0.0.0.0 */
-       if (in_dev->ifa_list && in_dev->ifa_list->ifa_local == 0)
-               goto local_input;
-
        /*
         *      Now we are ready to route packet.
         */
index ba0639714b3ac6a14f88eaccb31987fd63ba248f..10f5e9324dce9d0ebdea2996152871f4a70b60a0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.36 1998/10/21 05:26:59 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.38 1999/01/02 16:51:48 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -67,6 +67,9 @@ extern int sysctl_icmp_timeexceed_time;
 extern int sysctl_icmp_paramprob_time;
 extern int sysctl_icmp_echoreply_time;
 
+/* From igmp.c */
+extern int sysctl_igmp_max_memberships;
+
 int tcp_retr1_max = 255; 
 
 struct ipv4_config ipv4_config;
@@ -177,6 +180,10 @@ ctl_table ipv4_table[] = {
        {NET_IPV4_ICMP_ECHOREPLY_RATE, "icmp_echoreply_rate",
         &sysctl_icmp_echoreply_time, sizeof(int), 0644, NULL, &proc_dointvec},
        {NET_IPV4_ROUTE, "route", NULL, 0, 0555, ipv4_route_table},
+#ifdef CONFIG_IP_MULTICAST
+       {NET_IPV4_IGMP_MAX_MEMBERSHIPS, "igmp_max_memberships",
+        &sysctl_igmp_max_memberships, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
        {0}
 };
 
index de0db125fda141bf396b63abd00d53e3d27d267f..53b35417428e043c2fcf7f28466d51bb3c54be16 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.143 1998/12/20 20:20:20 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.145 1999/01/04 20:49:11 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -301,7 +301,7 @@ static void tcp_sacktag_write_queue(struct sock *sk, struct tcp_sack_block *sp,
                        /* The retransmission queue is always in order, so
                         * we can short-circuit the walk early.
                         */
-                       if(after(TCP_SKB_CB(skb)->seq, start_seq))
+                       if(after(TCP_SKB_CB(skb)->seq, end_seq))
                                break;
 
                        /* We play conservative, we don't allow SACKS to partially
@@ -1170,7 +1170,7 @@ coalesce:
        /* Zap SWALK, by moving every further SACK up by one slot.
         * Decrease num_sacks.
         */
-       for(this_sack += 1; this_sack < num_sacks-1; this_sack++, swalk++) {
+       for(; this_sack < num_sacks-1; this_sack++, swalk++) {
                struct tcp_sack_block *next = (swalk + 1);
                swalk->start_seq = next->start_seq;
                swalk->end_seq = next->end_seq;
index 421ffce0b49f2b286ad5b0e595731d425ef887da..660e64c44ffdb1a968d57891172cae8f6a4fbf35 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.163 1998/11/30 15:24:22 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.164 1999/01/04 20:36:55 davem Exp $
  *
  *             IPv4 specific functions
  *
@@ -1642,14 +1642,15 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
                skb->csum = csum_partial((char *)th, len, 0);
        case CHECKSUM_HW:
                if (tcp_v4_check(th,len,skb->nh.iph->saddr,skb->nh.iph->daddr,skb->csum)) {
-                       printk(KERN_DEBUG "TCPv4 bad checksum from %d.%d.%d.%d:%04x to %d.%d.%d.%d:%04x, "
-                              "len=%d/%d/%d\n",
-                              NIPQUAD(skb->nh.iph->saddr),
-                              ntohs(th->source), 
-                              NIPQUAD(skb->nh.iph->daddr),
-                              ntohs(th->dest),
-                              len, skb->len,
-                              ntohs(skb->nh.iph->tot_len));
+                       NETDEBUG(printk(KERN_DEBUG "TCPv4 bad checksum "
+                                       "from %d.%d.%d.%d:%04x to %d.%d.%d.%d:%04x, "
+                                       "len=%d/%d/%d\n",
+                                       NIPQUAD(skb->nh.iph->saddr),
+                                       ntohs(th->source), 
+                                       NIPQUAD(skb->nh.iph->daddr),
+                                       ntohs(th->dest),
+                                       len, skb->len,
+                                       ntohs(skb->nh.iph->tot_len)));
        bad_packet:             
                        tcp_statistics.TcpInErrs++;
                        goto discard_it;
index 1ced6e3c04ed582023202789fb1124451a4254d1..ddbe86c965ee7e10b38e478f346bf7f6c4e7f905 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Adapted from linux/net/ipv4/af_inet.c
  *
- *     $Id: af_inet6.c,v 1.39 1998/10/03 09:38:23 davem Exp $
+ *     $Id: af_inet6.c,v 1.41 1999/01/02 16:51:50 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -502,7 +502,7 @@ __initfunc(void inet6_proto_init(struct net_proto *pro))
        __this_module.can_unload = &ipv6_unload;
 #endif
 
-       printk(KERN_INFO "IPv6 v0.2 for NET3.037\n");
+       printk(KERN_INFO "IPv6 v0.8 for NET4.0\n");
 
        if (sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb))
        {
index 02bcd39fbddf1904536b88111c93ab12f50cf1b8..d66992315d39ffc9a4085e17485c797c142dbda8 100644 (file)
@@ -2456,7 +2456,7 @@ void ipx_proto_init(struct net_proto *pro)
        proc_net_register(&ipx_rt_procinfo);
 #endif
 
-       printk(KERN_INFO "Swansea University Computer Society IPX 0.38 for NET3.037\n");
+       printk(KERN_INFO "NET4: Linux IPX 0.38 for NET4.0\n");
        printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
 }
 
index 6d304fc0f93a7efd4d1736f22785d27a3a218fe7..e1b73cdbe7ff2c17104d17273c384c0ad5168042 100644 (file)
@@ -886,7 +886,7 @@ void spx_proto_init(void)
 
        /* route socket(PF_IPX, SOCK_SEQPACKET) calls through spx_create() */
 
-       printk(KERN_INFO "Sequenced Packet eXchange (SPX) 0.02 for Linux NET3.037\n");
+       printk(KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n");
        return;
 }
 
index 77382683c667737c8c740030a31a3e28963cdbef..23a721567dbcf52f6cf4c8d6916e6a2604013356 100644 (file)
@@ -403,7 +403,7 @@ EXPORT_SYMBOL(lapb_data_received);
 
 __initfunc(void lapb_proto_init(struct net_proto *pro))
 {
-       printk(KERN_INFO "LAPB for Linux. Version 0.01 for Linux NET3.038 (Linux 2.1)\n");
+       printk(KERN_INFO "NET4: LAPB for Linux. Version 0.01 for NET4.0\n");
 }
 
 #ifdef MODULE
index e53d7425289287c677a33a2ed4063c809cbf81ca..93a899d4e9613896430376cfb3c5ee129edab802 100644 (file)
@@ -1466,7 +1466,8 @@ void __init sock_init(void)
 {
        int i;
 
-       printk(KERN_INFO "Swansea University Computer Society NET3.039 for Linux 2.1\n");
+       printk(KERN_INFO "Linux NET4.0 for Linux 2.2\n");
+       printk(KERN_INFO "Based upon Swansea University Computer Society NET3.039\n");
 
        /*
         *      Initialize all address (protocol) families. 
index bdd15f74411e2c6378c29e73dc4a92da575c6baa..2d347b729ca32ab82fd965844c5d2c3739ea5873 100644 (file)
@@ -8,7 +8,7 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * Version:    $Id: af_unix.c,v 1.71 1998/10/03 09:39:05 davem Exp $
+ * Version:    $Id: af_unix.c,v 1.72 1998/11/21 06:50:00 davem Exp $
  *
  * Fixes:
  *             Linus Torvalds  :       Assorted bug cures.
@@ -1536,7 +1536,7 @@ __initfunc(void unix_proto_init(struct net_proto *pro))
        struct sk_buff *dummy_skb;
        struct proc_dir_entry *ent;
        
-       printk(KERN_INFO "NET3: Unix domain sockets 0.16 for Linux NET3.038.\n");
+       printk(KERN_INFO "NET4: Unix domain sockets 1.0 for Linux NET4.0.\n");
        if (sizeof(struct unix_skb_parms) > sizeof(dummy_skb->cb))
        {
                printk(KERN_CRIT "unix_proto_init: panic\n");
diff --git a/scripts/ksymoops-0.6/Makefile b/scripts/ksymoops-0.6/Makefile
deleted file mode 100644 (file)
index fa167b5..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-# Description file for ksymoops
-
-#      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
-
-# 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
-
-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)
diff --git a/scripts/ksymoops-0.6/README b/scripts/ksymoops-0.6/README
deleted file mode 100644 (file)
index aef796b..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-  ksymoops.
-
-  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
-
-  The patches subdirectory contains some arch specific patches to
-  provide more info on their Oops reports.  At the moment (2.1.126),
-  some archs do not print traces or do not print code lines, makes it
-  impossible to report properly.
-
-  TODO:
-  Performance improvements.  Reading a large log is quite slow, probably
-         one of the Oops regular expressions is pathological.
-  Clean up these docs.
-  Add "guess", "same" options, distinguish between default and supplied
-  values on report (Andries, I get the message :).
-
-  Tue Nov  3 02:31:01 EST 1998
-  Version 0.6
-  Read lsmod (/proc/modules).
-
-  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, 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
-                 [-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
-                         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.
-
-
-  WARNING:  The user interface will change slightly in 0.7, users will
-            have to give some indication of the state of their
-            environment.  Otherwise it may be too easy to pick the
-            wrong input files.
-
-  Return codes:        0 - normal.
-                 1 - error(s) or warning(s) issued, results may not be
-                     reliable.
-                 2 - fatal error, no useful results.
-
-  Supported architectures
-
-         i386 tested.
-          m68k code derived from ksymoops.cc and reading traps.c, untested.
-         MIPS tested.
-         Sparc tested.
-         Alpha 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.
-
-  * 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.
-
-    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.
diff --git a/scripts/ksymoops-0.6/io.c b/scripts/ksymoops-0.6/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-0.6/ksymoops.c b/scripts/ksymoops-0.6/ksymoops.c
deleted file mode 100644 (file)
index 78be43b..0000000
+++ /dev/null
@@ -1,569 +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.6"
-
-/*
-
-       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 <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<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\tOops report is read from stdin\n"
-               "\n"
-              );
-}
-
-/* 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;
-}
-
-/* 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 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 c, i;
-       char *p;
-
-       while ((c = getopt(argc, argv, "v:Vo:Ok:Kl:Lm:Ms:dh")) != 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 '?':
-                       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");
-       if (*objects) {
-               for (i = 0; i < *objects; ++i)
-                       printf(" -o %s", (*object)[i]);
-       }
-       else
-               printf(" -O");
-       if (*ksyms)
-               printf(" -k %s", *ksyms);
-       else
-               printf(" -K");
-       if (*lsmod)
-               printf(" -l %s", *lsmod);
-       else
-               printf(" -L");
-       if (*system_map)
-               printf(" -m %s", *system_map);
-       else
-               printf(" -M");
-       printf("\n\n");
-}
-
-/* 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 i;
-
-       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
-            );
-
-       if (spec_h && filecount == 0)
-               return(0);      /* just the help text */
-
-       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 */
-       Oops_read(filecount, filename);
-
-       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");
-               return(1);
-       }
-
-       return(0);
-}
diff --git a/scripts/ksymoops-0.6/ksymoops.h b/scripts/ksymoops-0.6/ksymoops.h
deleted file mode 100644 (file)
index 88aa0a7..0000000
+++ /dev/null
@@ -1,145 +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 void Oops_read(int filecount, char * const *filename);
-
-/* 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-0.6/ksyms.c b/scripts/ksymoops-0.6/ksyms.c
deleted file mode 100644 (file)
index 54b84b3..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
-       ksyms.c.
-
-       Process ksyms 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
-       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";
-
-       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-0.6/map.c b/scripts/ksymoops-0.6/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-0.6/misc.c b/scripts/ksymoops-0.6/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-0.6/object.c b/scripts/ksymoops-0.6/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-0.6/oops.c b/scripts/ksymoops-0.6/oops.c
deleted file mode 100644 (file)
index e0f05fd..0000000
+++ /dev/null
@@ -1,1061 +0,0 @@
-/*
-       oops.c.
-
-       Oops processing for ksymoop.
-
-       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
-       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>
-
-/* 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+strlen(options)+strlen(file)+1);
-       if (!cmd)
-               malloc_error(procname);
-       strcpy(cmd, path_objdump);
-       strcat(cmd, " ");
-       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;
-       elf_addr_t address, eip_relative;
-       char *line2, *map, **string = NULL;
-       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 */
-                       ".* +<_EIP\\+0?x?([0-9a-fA-F]+)>[ \t]*$"        /* 4 */
-                       ")?"
-                       ".*"
-                       ,
-               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[4]) {
-               /* EIP relative data to be adjusted */
-               errno = 0;
-               eip_relative = strtoul(string[4], NULL, 16);
-               if (errno) {
-                       fprintf(stderr,
-                               "%s Invalid hex value in objdump line, "
-                               "treated as zero - '%s'\n"
-                               "  objdump line '%s'\n",
-                               procname, string[4], 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 */
-               i = strlen(line)+1+2*sizeof(eip_relative)+1+strlen(map)+1;
-               line2 = malloc(i);
-               if (!line2)
-                       malloc_error(procname);
-               snprintf(line2, i, "%s %s %s",
-                       line, format_address(eip_relative), map);
-               add_symbol_n(ss, address, 'C', 1, line2);
-               free(line2);
-       }
-       else
-               add_symbol_n(ss, address, 'C', 1, line);        /* as is */
-       re_strings_free(&re_Oops_objdump, &string);
-}
-
-/* Maximum number of code bytes to process */
-#define CODE_SIZE 36   /* sparc and alpha dump 36 bytes */
-
-/******************************************************************************/
-/*                     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 byte = 0, 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 '>'.
-        * 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.
-                * 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;
-       }
-       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_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);
-
-       re_string_check(re_Oops_eip_sparc.re_nsub+1, string_max, procname);
-       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_strings(&re_Oops_eip_sparc, line, re_Oops_eip_sparc_pmatch,
-                       string);
-               return((*string)[re_Oops_eip_sparc.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);
-
-       re_string_check(re_Oops_eip_ppc.re_nsub+1, string_max, procname);
-       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_strings(&re_Oops_eip_ppc, line, re_Oops_eip_ppc_pmatch,
-                       string);
-               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);
-
-       re_string_check(re_Oops_eip_mips.re_nsub+1, string_max, procname);
-       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_strings(&re_Oops_eip_mips, line, re_Oops_eip_mips_pmatch,
-                       string);
-               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]*)"
-                       ")"
-                       BRACKETED_ADDRESS
-                       ,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_eip_other_pmatch);
-
-       re_string_check(re_Oops_eip_other.re_nsub+1, string_max, procname);
-       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_strings(&re_Oops_eip_other, line, re_Oops_eip_other_pmatch,
-                       string);
-               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";
-       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;
-       }
-       add_symbol_n(ss, *eip, 'E', 1, ">>EIP:");
-}
-
-/* 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);
-
-       re_string_check(re_Oops_ra.re_nsub+1, string_max, procname);
-       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_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 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 */
-
-       /* Oops 'Trace' lines */
-       re_compile(&re_Oops_trace,
-                       "^(Call Trace: )"                       /*  1 */
-       /* alpha */     "|^(Trace: )"                           /*  2 */
-       /* various */   "|(" BRACKETED_ADDRESS ")"              /* 3,4*/
-       /* ppc */       "|^(Call backtrace:)"                   /*  5 */
-       /* ppc */       "|^(" UNBRACKETED_ADDRESS ")"           /* 6,7*/
-                       ,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_trace_pmatch);
-
-       re_string_check(re_Oops_trace.re_nsub+1, string_max, procname);
-       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) {
-               re_strings(&re_Oops_trace, line, re_Oops_trace_pmatch,
-                       string);
-               if ((*string)[1] || (*string)[2]) {
-                       trace_line = 1;
-                       start = line + re_Oops_trace_pmatch[0].rm_eo;
-               }
-               else if ((*string)[5]) {
-                       trace_line = 2;         /* ppc */
-                       start = line + re_Oops_trace_pmatch[0].rm_eo;
-               }
-               else if (trace_line == 1 && (*string)[3])
-                       start = line + re_Oops_trace_pmatch[3].rm_so;
-               else if (trace_line == 2 && (*string)[6])       /* ppc */
-                       start = line + re_Oops_trace_pmatch[6].rm_so;
-               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 (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;
-       }
-
-       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.
- */
-static int Oops_print(const char *line, const char **text, char ***string,
-                     int string_max)
-{
-       int i, print;
-       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;
-       static regmatch_t *re_Oops_print_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);
-
-       re_string_check(re_Oops_prefix.re_nsub+1, string_max, procname);
-       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.
-        *
-        * 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,
-       /* 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 */   "|(Unable to handle kernel)"
-       /* various */   "|^(Process .*stackpage=)"
-       /* various */   "|^(Call Trace:[ \t])"
-       /* various */   "|^(Code *:[ \t])"
-       /* various */   "|^(Kernel panic)"
-       /* various */   "|^(In swapper task)"
-       /* various */   "|(Aiee)"      /* anywhere in text is a bad sign (TM) */
-       /* various */   "|(die_if_kernel)"      /* ditto */
-
-       /* 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 */      "|^(PC: )"
-       /* m68k */      "|^(d[04]: )"
-       /* m68k */      "|^(Frame format=)"
-       /* m68k */      "|^(wb [0-9] stat)"
-       /* m68k */      "|^(push data: )"
-       /* m68k */      "|^(baddr=)"
-       /* any other m68K lines to print? */
-
-       /* sparc */     "|(\\([0-9]\\): Oops )"
-       /* sparc */     "|(: memory violation)"
-       /* sparc */     "|(: Exception at)"
-       /* sparc */     "|(: Arithmetic fault)"
-       /* sparc */     "|(: Instruction fault)"
-       /* sparc */     "|(: arithmetic trap)"
-       /* sparc */     "|^(Bad unaligned kernel)"
-       /* sparc */     "|^(Forwarding unaligned exception)"
-       /* sparc */     "|^(: unhandled unaligned exception)"
-       /* sparc */     "|(: unaligned trap)"
-       /* sparc */     "|^(<sc)"
-       /* sparc */     "|^(pc *=)"
-       /* sparc */     "|^(r[0-9]+ *=)"
-       /* sparc */     "|^(gp *=)"
-       /* any other sparc lines to print? */
-
-       /* alpha */     "|^(tsk->)"
-       /* alpha   die_if_kernel has no fixed text, identify by (pid): text. */
-       /* alpha */     "|^(.*\\([0-9]+\\): "
-                          /* Somebody has been playful with the texts.  */
-                          "((Whee)|(Oops)|(Kernel)|(.*Penguin)|(BOGUS))"
-                         ")"
-       /* alpha */     "|^(PSR: )"
-       /* alpha */     "|^(g0: )"
-       /* alpha */     "|^(o0: )"
-       /* alpha */     "|^(l0: )"
-       /* alpha */     "|^(i0: )"
-       /* alpha */     "|^(Instruction DUMP: )"
-       /* any other alpha lines to print? */
-
-       /* ppc */       "|^(MSR: )"
-       /* ppc */       "|^(TASK = )"
-       /* ppc */       "|^(last math )"
-       /* ppc */       "|^(GPR[0-9]+: )"
-       /* ppc */       "|(kernel pc )"
-       /* ppc */       "|(trap at PC: )"
-       /* ppc */       "|(bad area pc )"
-       /* ppc */       "|(NIP: )"
-       /* any other ppc lines to print? */
-
-       /* MIPS */      "|^(\\$[0-9 ]+:)"
-       /* MIPS */      "|^(epc )"
-       /* MIPS */      "|^(Status:)"
-       /* MIPS */      "|^(Cause :)"
-       /* MIPS */      "|( ra *=)"
-       /* any other MIPS lines to print? */
-
-                       ")",
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_print_pmatch);
-
-       re_string_check(re_Oops_print.re_nsub+1, string_max, procname);
-       i = regexec(&re_Oops_print, *text, re_Oops_print.re_nsub+1,
-               re_Oops_print_pmatch, 0);
-       if (debug > 3)
-               fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
-       print = 0;
-       if (i == 0) {
-               re_strings(&re_Oops_print, *text, re_Oops_print_pmatch,
-                       string);
-               print = 1;
-               /* Handle multiline messages, messy */
-               if (!(*string)[2] && !(*string)[3] && !(*string)[4])
-                       stack_line = 0;
-               else if ((*string)[2] || (*string)[3])
-                       stack_line = 1;
-               else if (stack_line && !(*string)[4]) {
-                       print = 0;
-                       stack_line = 0;
-               }
-               if (!(*string)[5] && !(*string)[6] && !(*string)[9])
-                       trace_line = 0;
-               else if ((*string)[5] || (*string)[9] || (*string)[10])
-                       trace_line = 1;
-               else if (stack_line && !(*string)[6]) {
-                       print = 0;
-                       trace_line = 0;
-               }
-               if ((*string)[8])
-                       add_Version((*string)[8]+8, "Oops");
-       }
-       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 '>'.
-        */
-       re_compile(&re_Oops_code,
-                       "^("                                            /*  1 */
-       /* sparc */       "(Instruction DUMP)"                          /*  2 */
-       /* various */     "|(Code *)"                                   /*  3 */
-                       ")"
-                       ":[ \t]+"
-                       "("                                             /*  4 */
-                         "(general protection.*)"
-                         "|(<[0-9]+>)"
-                         "|((<?[0-9a-fA-F]+>?[ \t]*)+)"
-                       ")"
-                       "(.*)$"                         /* trailing garbage */
-                       ,
-               REG_NEWLINE|REG_EXTENDED|REG_ICASE,
-               &re_Oops_code_pmatch);
-
-       re_string_check(re_Oops_code.re_nsub+1, string_max, procname);
-       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_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)
-{
-       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))
-               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 */
-void Oops_read(int filecount, char * const *filename)
-{
-       char *line = NULL, **string = NULL;
-       const char *start, *text;
-       int i, size = 0, lineno = 0, lastprint = 0;
-       elf_addr_t eip = 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;
-                       if (Oops_print(line, &text, &string, MAX_STRINGS)) {
-                               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_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);
-                               Oops_format(&ss_format);
-                               ss_free(&ss_format);
-                       }
-                       /* 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 (ss_format.used) {
-                       fprintf(stderr,
-                               "Warning, Code line not seen, dumping "
-                               "what data is available\n");
-                       ++warnings;
-                       Oops_format(&ss_format);
-                       ss_free(&ss_format);
-               }
-       } while (filecount != 0);
-
-       for (i = 0; i < sizeof(string); ++i) {
-               free(string[i]);
-               string[i] = NULL;
-       }
-       free(line);
-}
diff --git a/scripts/ksymoops-0.6/patches/README b/scripts/ksymoops-0.6/patches/README
deleted file mode 100644 (file)
index 7727d8e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-An ad-hoc collection of patches to the Linux kernel and related
-utilities, to make the best use of ksymoops.
-
-Most of the kernel patches are to extend the information logged on an
-Oops, some architectures currently (2.1.126) do not provide full
-diagnostics.  Hopefully these patches will be integrated into the
-kernel tree in future.  ksymoops will still run without these patches
-but will provide degraded output.
-
-mips    - Kernel patch by Ulf Carlsson <ulfc@bun.falkenberg.se> to
-          provide full diagnostics on a mips Oops.
-
-ppc     - Kernel patch by "Ryan Nielsen" <ran@krazynet.com> to provide
-          full diagnostics on a ppc Oops.
-
diff --git a/scripts/ksymoops-0.6/patches/mips b/scripts/ksymoops-0.6/patches/mips
deleted file mode 100644 (file)
index ec0b0b6..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
---- linux/arch/mips/kernel/traps.c-orig        Thu Oct 29 17:23:19 1998
-+++ linux/arch/mips/kernel/traps.c     Fri Oct 30 13:25:21 1998
-@@ -6,6 +6,7 @@
-  *
-  * Copyright 1994, 1995, 1996, 1997, 1998 by Ralf Baechle
-  * Modified for R3000 by Paul M. Antoine, 1995, 1996
-+ * Complete output from die() by Ulf Carlsson, 1998
-  */
- #include <linux/config.h>
- #include <linux/init.h>
-@@ -80,50 +81,61 @@
-  * This routine abuses get_user()/put_user() to reference pointers
-  * with at least a bit of error checking ...
-  */
--void show_registers(char * str, struct pt_regs * regs, long err)
-+void show_stack(unsigned int *sp)
- {
--      int     i;
--      int     *stack;
--      u32     *sp, *pc, addr, module_start, module_end;
--      extern  char start_kernel, _etext;
-+      int i;
-+      unsigned int *stack;
--      sp = (u32 *)regs->regs[29];
--      pc = (u32 *)regs->cp0_epc;
-+      stack = sp;
-+      i = 0;
--      show_regs(regs);
-+      printk("Stack:");
-+      while ((unsigned long) stack & (PAGE_SIZE - 1)) {
-+              unsigned long stackdata;
--      /*
--       * Dump the stack
--       */
--      printk("Process %s (pid: %ld, stackpage=%08lx)\nStack: ",
--              current->comm, current->pid, (unsigned long)current);
--      for(i=0;i<5;i++)
--              printk("%08x ", *sp++);
--      stack = (int *) sp;
-+              if (__get_user(stackdata, stack++)) {
-+                      printk(" (Bad stack address)");
-+                      break;
-+              }
--      for(i=0; i < kstack_depth_to_print; i++) {
--              unsigned int stackdata;
-+              printk(" %08lx", stackdata);
--              if (((u32) stack & (PAGE_SIZE -1)) == 0)
--                      break;
--              if (i && ((i % 8) == 0))
--                      printk("\n       ");
--              if (get_user(stackdata, stack++) < 0) {
--                      printk("(Bad stack address)");
-+              if (++i > 40) {
-+                      printk(" ...");
-                       break;
-               }
--              printk("%08x ", stackdata);
-+
-+              if (i % 8 == 0)
-+                      printk("\n      ");
-       }
--      printk("\nCall Trace: ");
--      stack = (int *)sp;
--      i = 1;
-+}
-+
-+void show_trace(unsigned int *sp)
-+{
-+      int i;
-+      unsigned int *stack;
-+      unsigned long kernel_start, kernel_end;
-+      unsigned long module_start, module_end;
-+      extern char _stext, _etext;
-+
-+      stack = sp;
-+      i = 0;
-+
-+      kernel_start = (unsigned long) &_stext;
-+      kernel_end = (unsigned long) &_etext;
-       module_start = VMALLOC_START;
-       module_end = module_start + MODULE_RANGE;
--      while (((unsigned long)stack & (PAGE_SIZE -1)) != 0) {
--              if (get_user(addr, stack++) < 0) {
--                      printk("(Bad address)\n");
-+
-+      printk("\nCall Trace:");
-+
-+      while ((unsigned long) stack & (PAGE_SIZE -1)) {
-+              unsigned long addr;
-+
-+              if (__get_user(addr, stack++)) {
-+                      printk(" (Bad stack address)\n");
-                       break;
-               }
-+
-               /*
-                * If the address is either in the text segment of the
-                * kernel, or in the region which contains vmalloc'ed
-@@ -132,26 +144,33 @@
-                * down the cause of the crash will be able to figure
-                * out the call path that was taken.
-                */
--              if (((addr >= (u32) &start_kernel) &&
--                   (addr <= (u32) &_etext)) ||
--                  ((addr >= module_start) && (addr <= module_end))) {
--                      if (i && ((i % 8) == 0))
--                              printk("\n       ");
--                      printk("%08x ", addr);
--                      i++;
-+
-+              if ((addr >= kernel_start && addr < kernel_end) ||
-+                  (addr >= module_start && addr < module_end)) { 
-+
-+                      printk(" [<%08lx>]", addr);
-+                      if (++i > 40) {
-+                              printk(" ...");
-+                              break;
-+                      }
-               }
-       }
-+}
--      printk("\nCode : ");
--      if ((KSEGX(pc) == KSEG0 || KSEGX(pc) == KSEG1) &&
--          (((unsigned long) pc & 3) == 0))
--      {
--              for(i=0;i<5;i++)
--                      printk("%08x ", *pc++);
--              printk("\n");
-+void show_code(unsigned int *pc)
-+{
-+      long i;
-+
-+      printk("\nCode:");
-+
-+      for(i = -3 ; i < 6 ; i++) {
-+              unsigned long insn;
-+              if (__get_user(insn, pc + i)) {
-+                      printk(" (Bad address in epc)\n");
-+                      break;
-+              }
-+              printk("%c%08lx%c",(i?' ':'<'),insn,(i?' ':'>'));
-       }
--      else
--              printk("(Bad address in epc)\n");
- }
- void die(const char * str, struct pt_regs * regs, unsigned long err)
-@@ -162,6 +181,12 @@
-       console_verbose();
-       printk("%s: %04lx\n", str, err & 0xffff);
-       show_regs(regs);
-+      printk("Process %s (pid: %ld, stackpage=%08lx)\n",
-+              current->comm, current->pid, (unsigned long) current);
-+      show_stack((unsigned int *) regs->regs[29]);
-+      show_trace((unsigned int *) regs->regs[29]);
-+      show_code((unsigned int *) regs->cp0_epc);
-+      printk("\n");
-       do_exit(SIGSEGV);
- }
-
diff --git a/scripts/ksymoops-0.6/patches/ppc b/scripts/ksymoops-0.6/patches/ppc
deleted file mode 100644 (file)
index 5edecf4..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
---- linux/arch/ppc/kernel/process.c    1998/10/11 17:47:23     1.67
-+++ linux/arch/ppc/kernel/process.c    1998/11/02 03:11:28
-@@ -196,6 +198,19 @@
-       _enable_interrupts(s);
- }
-+void instruction_dump (unsigned long *pc)
-+{
-+      int i;
-+
-+      if((((unsigned long) pc) & 3))
-+                return;
-+
-+      printk("Instruction DUMP:");
-+      for(i = -3; i < 6; i++)
-+              printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
-+      printk("\n");
-+}
-+
- void show_regs(struct pt_regs * regs)
- {
-       int i;
---- linux/arch/ppc/kernel/traps.c      1998/05/05 19:18:53     1.21
-+++ linux/arch/ppc/kernel/traps.c      1998/11/02 03:11:36
-@@ -79,6 +79,7 @@
-               debugger(regs);
- #endif
-               print_backtrace((unsigned long *)regs->gpr[1]);
-+              instruction_dump((unsigned long *)regs->nip);
-               panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
-       }
-       force_sig(signr, current);
-@@ -126,6 +127,7 @@
-               debugger(regs);
- #endif
-               print_backtrace((unsigned long *)regs->gpr[1]);
-+              instruction_dump((unsigned long *)regs->nip);
-               panic("machine check");
-       }
-       _exception(SIGSEGV, regs);      
-@@ -219,6 +221,7 @@
- #endif
-       show_regs(regs);
-       print_backtrace((unsigned long *)regs->gpr[1]);
-+      instruction_dump((unsigned long *)regs->nip);
-       panic("kernel stack overflow");
- }
---- linux/arch/ppc/mm/fault.c  1998/10/06 03:13:19     1.28
-+++ linux/arch/ppc/mm/fault.c  1998/11/02 03:11:36
-@@ -89,6 +89,7 @@
-                       printk("page fault in interrupt handler, addr=%lx\n",
-                              address);
-                       show_regs(regs);
-+                      instruction_dump((unsigned long *)regs->nip);
- #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
-                       if (debugger_kernel_faults)
-                               debugger(regs);
-@@ -174,6 +175,7 @@
-       /* kernel has accessed a bad area */
-       show_regs(regs);
-       print_backtrace( (unsigned long *)regs->gpr[1] );
-+      instruction_dump((unsigned long *)regs->nip);
- #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
-       if (debugger_kernel_faults)
-               debugger(regs);
-
diff --git a/scripts/ksymoops-0.6/re.c b/scripts/ksymoops-0.6/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-0.6/symbol.c b/scripts/ksymoops-0.6/symbol.c
deleted file mode 100644 (file)
index 00c6f4e..0000000
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
-       symbol.c.
-
-       Symbol handling 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
-       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",
-               (Version >> 16) & 0xff,
-               (Version >> 8) & 0xff,
-               (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;
-}
diff --git a/scripts/ksymoops/Makefile b/scripts/ksymoops/Makefile
new file mode 100644 (file)
index 0000000..81e80c1
--- /dev/null
@@ -0,0 +1,79 @@
+# 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)
diff --git a/scripts/ksymoops/README b/scripts/ksymoops/README
new file mode 100644 (file)
index 0000000..134ef02
--- /dev/null
@@ -0,0 +1,395 @@
+  ksymoops.
+
+  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, 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.
+         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.
+
+  * 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.
diff --git a/scripts/ksymoops/io.c b/scripts/ksymoops/io.c
new file mode 100644 (file)
index 0000000..b54e8ad
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+       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
new file mode 100644 (file)
index 0000000..0cd6579
--- /dev/null
@@ -0,0 +1,678 @@
+/*
+       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
new file mode 100644 (file)
index 0000000..fb3e99d
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+       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
new file mode 100644 (file)
index 0000000..608254a
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+       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
new file mode 100644 (file)
index 0000000..6f91e9d
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+       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
new file mode 100644 (file)
index 0000000..7876f7e
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+       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
new file mode 100644 (file)
index 0000000..7a44e4c
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+       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
new file mode 100644 (file)
index 0000000..1df01f4
--- /dev/null
@@ -0,0 +1,1200 @@
+/*
+       oops.c.
+
+       Oops processing for ksymoop.
+
+       Copyright Keith Owens <kaos@ocs.com.au>.
+       Released under the GNU Public Licence, Version 2.
+
+       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>
+
+/* 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+strlen(options)+strlen(file)+1);
+       if (!cmd)
+               malloc_error(procname);
+       strcpy(cmd, path_objdump);
+       strcat(cmd, " ");
+       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;
+       elf_addr_t address, eip_relative;
+       char *line2, *map, **string = NULL;
+       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 */
+                       ".* +<_EIP\\+0?x?([0-9a-fA-F]+)>[ \t]*$"        /* 4 */
+                       ")?"
+                       ".*"
+                       ,
+               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[4]) {
+               /* EIP relative data to be adjusted */
+               errno = 0;
+               eip_relative = strtoul(string[4], NULL, 16);
+               if (errno) {
+                       fprintf(stderr,
+                               "%s Invalid hex value in objdump line, "
+                               "treated as zero - '%s'\n"
+                               "  objdump line '%s'\n",
+                               procname, string[4], 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 */
+               i = strlen(line)+1+2*sizeof(eip_relative)+1+strlen(map)+1;
+               line2 = malloc(i);
+               if (!line2)
+                       malloc_error(procname);
+               snprintf(line2, i, "%s %s %s",
+                       line, format_address(eip_relative), map);
+               add_symbol_n(ss, address, 'C', 1, line2);
+               free(line2);
+       }
+       else
+               add_symbol_n(ss, address, 'C', 1, line);        /* as is */
+       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_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);
+               return((*string)[re_Oops_eip_sparc.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);
+               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);
+               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);
+               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";
+       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;
+       }
+       add_symbol_n(ss, *eip, 'E', 1, ">>EIP:");
+}
+
+/* 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 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 */
+                       ")",
+               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
+                       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? */
+
+       /* sparc */     "|(Bad unaligned kernel)"
+       /* sparc */     "|(Forwarding unaligned exception)"
+       /* sparc */     "|(: unhandled unaligned exception)"
+       /* sparc */     "|(<sc)"
+       /* sparc */     "|(pc *=)"
+       /* sparc */     "|(r[0-9]+ *=)"
+       /* sparc */     "|(gp *=)"
+       /* any other sparc lines to print? */
+
+       /* alpha */     "|(tsk->)"
+       /* alpha */     "|(PSR: )"
+       /* alpha */     "|([goli]0: )"
+       /* alpha */     "|(Instruction DUMP: )"
+       /* any other alpha 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 */
+
+       /* sparc */     "|(\\([0-9]\\): Oops )"
+       /* sparc */     "|(: memory violation)"
+       /* sparc */     "|(: Exception at)"
+       /* sparc */     "|(: Arithmetic fault)"
+       /* sparc */     "|(: Instruction fault)"
+       /* sparc */     "|(: arithmetic trap)"
+       /* sparc */     "|(: 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]*)+)"
+                       ")"
+                       "(.*)$"                         /* 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;
+       elf_addr_t eip = 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;
+                       if (Oops_print(line, &text, &string, MAX_STRINGS)) {
+                               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_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) {
+                       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
new file mode 100644 (file)
index 0000000..9c65832
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+       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
new file mode 100644 (file)
index 0000000..5c66cc9
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+       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;
+}
index 040c1fe80f9e8c7e05bd698f996a2ffb799878d0..3aa67da05e3540faf09ef991261b7955beabea33 100644 (file)
@@ -307,10 +307,10 @@ void generate_if(struct kconfig * item,
     case tok_hex:
     case tok_string:
       printf("} then { ");
-      printf(".menu%d.config.f.x%d.x configure -state normal -fore [ cget .ref -foreground ]; ", menu_num, line_num);
+      printf(".menu%d.config.f.x%d.x configure -state normal -foreground [ cget .ref -foreground ]; ", menu_num, line_num);
       printf(".menu%d.config.f.x%d.l configure -state normal; ", menu_num, line_num);
       printf("} else { ");
-      printf(".menu%d.config.f.x%d.x configure -state disabled -fore [ cget .ref -disabledforeground ];", menu_num, line_num );
+      printf(".menu%d.config.f.x%d.x configure -state disabled -foreground [ cget .ref -disabledforeground ];", menu_num, line_num );
       printf(".menu%d.config.f.x%d.l configure -state disabled;", menu_num, line_num );
       printf("}\n");
       break;