Pull fix-offsets-h into release branch
authorTony Luck <tony.luck@intel.com>
Wed, 14 Sep 2005 21:14:45 +0000 (14:14 -0700)
committerTony Luck <tony.luck@intel.com>
Wed, 14 Sep 2005 21:14:45 +0000 (14:14 -0700)
375 files changed:
Documentation/cciss.txt
Documentation/dontdiff
Documentation/feature-removal-schedule.txt
Documentation/kdump/kdump.txt
Documentation/oops-tracing.txt
Documentation/pm.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
MAINTAINERS
arch/arm/kernel/calls.S
arch/arm/kernel/entry-common.S
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/corgi_lcd.c
arch/arm/mach-pxa/corgi_ssp.c
arch/arm/mach-pxa/sharpsl.h [new file with mode: 0644]
arch/arm/mach-pxa/spitz.c [new file with mode: 0644]
arch/i386/kernel/reboot.c
arch/i386/kernel/setup.c
arch/i386/kernel/smpboot.c
arch/i386/kernel/traps.c
arch/ia64/ia32/binfmt_elf32.c
arch/mips/kernel/sysirix.c
arch/ppc/kernel/temp.c
arch/ppc/kernel/time.c
arch/ppc/kernel/vmlinux.lds.S
arch/ppc/platforms/chrp_time.c
arch/ppc/syslib/prep_nvram.c
arch/ppc64/kernel/asm-offsets.c
arch/ppc64/kernel/entry.S
arch/ppc64/kernel/pSeries_setup.c
arch/ppc64/kernel/vdso.c
arch/x86_64/ia32/ia32_binfmt.c
arch/x86_64/ia32/syscall32.c
arch/x86_64/kernel/e820.c
arch/x86_64/kernel/mce.c
arch/x86_64/kernel/nmi.c
drivers/base/attribute_container.c
drivers/base/class.c
drivers/base/firmware_class.c
drivers/base/map.c
drivers/base/platform.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_cmd.h
drivers/block/cciss_scsi.c
drivers/block/pktcdvd.c
drivers/bluetooth/hci_usb.c
drivers/bluetooth/hci_usb.h
drivers/char/amiserial.c
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Makefile
drivers/char/watchdog/i6300esb.c [new file with mode: 0644]
drivers/char/watchdog/ibmasr.c [new file with mode: 0644]
drivers/char/watchdog/mv64x60_wdt.c [new file with mode: 0644]
drivers/char/watchdog/pcwd_pci.c
drivers/char/watchdog/s3c2410_wdt.c
drivers/char/watchdog/sbc8360.c [new file with mode: 0644]
drivers/char/watchdog/w83977f_wdt.c [new file with mode: 0644]
drivers/i2c/busses/i2c-keywest.c
drivers/ide/ide-iops.c
drivers/ide/pci/cmd64x.c
drivers/ide/pci/hpt34x.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/spitzkbd.c [new file with mode: 0644]
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/corgi_ts.c
drivers/isdn/sc/init.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-zoltrix.c
drivers/media/video/cx88/cx88-dvb.c
drivers/net/Kconfig
drivers/net/arcnet/com90io.c
drivers/net/e100.c
drivers/net/e1000/e1000_main.c
drivers/net/ixgb/ixgb_main.c
drivers/net/s2io.c
drivers/net/sk98lin/skge.c
drivers/net/skge.c
drivers/net/skge.h
drivers/net/tulip/xircom_cb.c
drivers/net/wireless/airo.c
drivers/net/wireless/orinoco_cs.c
drivers/pci/pci.c
drivers/pcmcia/pcmcia_ioctl.c
drivers/pcmcia/yenta_socket.c
drivers/s390/net/ctcmain.c
drivers/sbus/char/display7seg.c
drivers/scsi/sata_sis.c
drivers/tc/zs.c
drivers/video/Kconfig
drivers/video/backlight/corgi_bl.c
drivers/video/console/fbcon.c
drivers/video/console/fbcon.h
drivers/video/console/font_10x18.c
drivers/video/console/font_6x11.c
drivers/video/console/font_7x14.c
drivers/video/console/font_8x16.c
drivers/video/console/font_8x8.c
drivers/video/console/font_acorn_8x8.c
drivers/video/console/font_mini_4x6.c
drivers/video/console/font_pearl_8x8.c
drivers/video/console/font_sun12x22.c
drivers/video/console/font_sun8x16.c
drivers/video/console/fonts.c
drivers/video/matrox/matroxfb_base.c
drivers/video/pm3fb.c
fs/exec.c
fs/file.c
fs/namei.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/open.c
fs/reiserfs/file.c
fs/reiserfs/inode.c
include/asm-alpha/pgtable.h
include/asm-arm/arch-pxa/akita.h [new file with mode: 0644]
include/asm-arm/arch-pxa/corgi.h
include/asm-arm/arch-pxa/sharpsl.h [new file with mode: 0644]
include/asm-arm/arch-pxa/spitz.h [new file with mode: 0644]
include/asm-arm/pgtable.h
include/asm-arm26/pgtable.h
include/asm-frv/pgtable.h
include/asm-h8300/pgtable.h
include/asm-i386/pgtable.h
include/asm-ia64/pgtable.h
include/asm-m32r/pgtable.h
include/asm-m68k/pgtable.h
include/asm-m68knommu/pgtable.h
include/asm-mips/pgtable.h
include/asm-parisc/pgtable.h
include/asm-ppc/mv64x60.h
include/asm-ppc/pgtable.h
include/asm-ppc/segment.h [deleted file]
include/asm-sh/pgtable.h
include/asm-sh64/pgtable.h
include/asm-x86_64/pgtable.h
include/asm-xtensa/pgtable.h
include/linux/audit.h
include/linux/fb.h
include/linux/font.h
include/linux/kernel.h
include/linux/nfsd/xdr4.h
include/linux/pci_ids.h
include/linux/pktcdvd.h
include/linux/sched.h
include/linux/security.h
include/linux/videodev2.h
include/net/bluetooth/hci.h
include/sound/core.h
include/sound/cs46xx.h
include/sound/emu10k1.h
include/sound/pcm.h
include/sound/pcm_oss.h
include/sound/trident.h
include/sound/version.h
include/sound/ymfpci.h
include/video/pm3fb.h
include/video/w100fb.h
init/initramfs.c
kernel/audit.c
kernel/auditsc.c
kernel/module.c
kernel/sched.c
kernel/timer.c
mm/mempolicy.c
mm/mmap.c
mm/page_alloc.c
mm/slab.c
mm/vmscan.c
net/bluetooth/hci_event.c
net/bluetooth/rfcomm/sock.c
net/dccp/input.c
net/ipv4/netfilter/ip_conntrack_ftp.c
net/ipv4/netfilter/ip_conntrack_irc.c
net/ipv4/netfilter/ip_conntrack_netbios_ns.c
net/ipv4/netfilter/ip_conntrack_tftp.c
net/ipv4/netfilter/ipt_MASQUERADE.c
net/ipv4/netfilter/ipt_REDIRECT.c
net/sunrpc/svcsock.c
security/Kconfig
security/Makefile
security/inode.c [new file with mode: 0644]
security/seclvl.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/ss/services.c
sound/arm/Kconfig
sound/arm/aaci.c
sound/arm/sa11xx-uda1341.c
sound/core/Kconfig
sound/core/control.c
sound/core/control_compat.c
sound/core/device.c
sound/core/hwdep.c
sound/core/info.c
sound/core/init.c
sound/core/memalloc.c
sound/core/memory.c
sound/core/oss/mixer_oss.c
sound/core/oss/pcm_oss.c
sound/core/oss/pcm_plugin.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/seq/instr/ainstr_gf1.c
sound/core/seq/instr/ainstr_iw.c
sound/core/seq/oss/seq_oss_init.c
sound/core/seq/oss/seq_oss_midi.c
sound/core/seq/oss/seq_oss_readq.c
sound/core/seq/oss/seq_oss_synth.c
sound/core/seq/oss/seq_oss_timer.c
sound/core/seq/oss/seq_oss_writeq.c
sound/core/seq/seq.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_device.c
sound/core/seq/seq_dummy.c
sound/core/seq/seq_fifo.c
sound/core/seq/seq_instr.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_midi.c
sound/core/seq/seq_midi_event.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_prioq.c
sound/core/seq/seq_queue.c
sound/core/seq/seq_system.c
sound/core/seq/seq_timer.c
sound/core/seq/seq_virmidi.c
sound/core/sound.c
sound/core/timer.c
sound/drivers/Kconfig
sound/drivers/dummy.c
sound/drivers/mpu401/mpu401.c
sound/drivers/mpu401/mpu401_uart.c
sound/drivers/mtpav.c
sound/drivers/opl3/opl3_lib.c
sound/drivers/opl3/opl3_oss.c
sound/drivers/opl4/opl4_lib.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/drivers/vx/vx_core.c
sound/drivers/vx/vx_pcm.c
sound/i2c/cs8427.c
sound/i2c/i2c.c
sound/i2c/l3/uda1341.c
sound/i2c/other/ak4114.c
sound/i2c/other/ak4117.c
sound/i2c/tea6330t.c
sound/isa/Kconfig
sound/isa/ad1816a/ad1816a_lib.c
sound/isa/ad1848/ad1848.c
sound/isa/ad1848/ad1848_lib.c
sound/isa/cmi8330.c
sound/isa/cs423x/cs4231.c
sound/isa/cs423x/cs4231_lib.c
sound/isa/cs423x/cs4236.c
sound/isa/es1688/es1688.c
sound/isa/es1688/es1688_lib.c
sound/isa/es18xx.c
sound/isa/gus/gus_main.c
sound/isa/gus/gus_mem_proc.c
sound/isa/gus/gus_pcm.c
sound/isa/gus/gusclassic.c
sound/isa/gus/gusextreme.c
sound/isa/gus/gusmax.c
sound/isa/gus/interwave.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/emu8000.c
sound/isa/sb/emu8000_pcm.c
sound/isa/sb/sb16.c
sound/isa/sb/sb16_csp.c
sound/isa/sb/sb8.c
sound/isa/sb/sb_common.c
sound/isa/sgalaxy.c
sound/isa/sscape.c
sound/isa/wavefront/wavefront.c
sound/mips/Kconfig
sound/mips/au1x00.c
sound/parisc/harmony.c
sound/pci/Kconfig
sound/pci/Makefile
sound/pci/ac97/ac97_codec.c
sound/pci/ac97/ac97_id.h
sound/pci/ac97/ac97_patch.c
sound/pci/ac97/ak4531_codec.c
sound/pci/ad1889.c [new file with mode: 0644]
sound/pci/ad1889.h [new file with mode: 0644]
sound/pci/ali5451/ali5451.c
sound/pci/als4000.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emupcm.c
sound/pci/emu10k1/p16v.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_si3054.c
sound/pci/hda/patch_sigmatel.c
sound/pci/ice1712/aureon.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/juli.c
sound/pci/ice1712/phase.c
sound/pci/ice1712/pontis.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/nm256/nm256.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sonicvibes.c
sound/pci/trident/trident.c
sound/pci/trident/trident_main.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci_main.c
sound/pcmcia/pdaudiocf/pdaudiocf_core.c
sound/ppc/Kconfig
sound/ppc/pmac.c
sound/ppc/powermac.c
sound/ppc/tumbler.c
sound/sparc/Kconfig
sound/sparc/amd7930.c
sound/sparc/cs4231.c
sound/sparc/dbri.c
sound/synth/emux/emux.c
sound/synth/emux/emux_seq.c
sound/synth/emux/soundfont.c
sound/synth/util_mem.c
sound/usb/usbaudio.c
sound/usb/usbmidi.c
sound/usb/usbmixer.c
sound/usb/usx2y/usbusx2yaudio.c

index c8f9a73111da8371d5ff4b49b68116ffb3353e48..68a711fb82cf8d9d612363ff04bb71719ef6729f 100644 (file)
@@ -17,7 +17,9 @@ This driver is known to work with the following cards:
        * SA P600
        * SA P800
        * SA E400
-       * SA E300
+       * SA P400i
+       * SA E200
+       * SA E200i
 
 If nodes are not already created in the /dev/cciss directory, run as root:
 
index 96bea278bbf61eb9ae6d6cb5657f8092b543a87e..24adfe9af3ca92a169b9f7a7fc368e9098dac487 100644 (file)
@@ -55,6 +55,7 @@ aic7*seq.h*
 aicasm
 aicdb.h*
 asm
+asm-offsets.*
 asm_offsets.*
 autoconf.h*
 bbootsect
index 784e08c1c80a308b9916a4a1f360380482761603..b67189a8d8d471789629ae23e4c1b6e9e2b713da 100644 (file)
@@ -17,15 +17,6 @@ Who: Greg Kroah-Hartman <greg@kroah.com>
 
 ---------------------------
 
-What:  io_remap_page_range() (macro or function)
-When:  September 2005
-Why:   Replaced by io_remap_pfn_range() which allows more memory space
-       addressabilty (by using a pfn) and supports sparc & sparc64
-       iospace as part of the pfn.
-Who:   Randy Dunlap <rddunlap@osdl.org>
-
----------------------------
-
 What:  RAW driver (CONFIG_RAW_DRIVER)
 When:  December 2005
 Why:   declared obsolete since kernel 2.6.3
index 1f5f7d28c9e6bf54e2b95d97f9399aed324b177f..5f08f9ce60464bdb03e7dd6c82398c79c0bd2eba 100644 (file)
@@ -66,11 +66,11 @@ SETUP
    c) Enable "/proc/vmcore support" (Optional, in Pseudo filesystems).
        CONFIG_PROC_VMCORE=y
    d) Disable SMP support and build a UP kernel (Until it is fixed).
-       CONFIG_SMP=n
+       CONFIG_SMP=n
    e) Enable "Local APIC support on uniprocessors".
-       CONFIG_X86_UP_APIC=y
+       CONFIG_X86_UP_APIC=y
    f) Enable "IO-APIC support on uniprocessors"
-       CONFIG_X86_UP_IOAPIC=y
+       CONFIG_X86_UP_IOAPIC=y
 
   Note:   i) Options a) and b) depend upon "Configure standard kernel features
             (for small systems)" (under General setup).
@@ -95,6 +95,11 @@ SETUP
            hence have memory less than 4GB.
        iii) Specify "irqpoll" as command line parameter. This reduces driver
             initialization failures in second kernel due to shared interrupts.
+        iv) <root-dev> needs to be specified in a format corresponding to
+            the root device name in the output of mount command.
+         v) If you have built the drivers required to mount root file
+            system as modules in <second-kernel>, then, specify
+            --initrd=<initrd-for-second-kernel>.
 
 5) System reboots into the second kernel when a panic occurs. A module can be
    written to force the panic or "ALT-SysRq-c" can be used initiate a crash
index da711028e5f712cde905b4129e6addfc96b7ac92..66eaaab7773d551691181070daead961fca33df2 100644 (file)
@@ -205,8 +205,8 @@ Phone: 701-234-7556
 Tainted kernels:
 
 Some oops reports contain the string 'Tainted: ' after the program
-counter, this indicates that the kernel has been tainted by some
-mechanism.  The string is followed by a series of position sensitive
+counter. This indicates that the kernel has been tainted by some
+mechanism.  The string is followed by a series of position-sensitive
 characters, each representing a particular tainted value.
 
   1: 'G' if all modules loaded have a GPL or compatible license, 'P' if
@@ -214,16 +214,25 @@ characters, each representing a particular tainted value.
      MODULE_LICENSE or with a MODULE_LICENSE that is not recognised by
      insmod as GPL compatible are assumed to be proprietary.
 
-  2: 'F' if any module was force loaded by insmod -f, ' ' if all
+  2: 'F' if any module was force loaded by "insmod -f", ' ' if all
      modules were loaded normally.
 
   3: 'S' if the oops occurred on an SMP kernel running on hardware that
-      hasn't been certified as safe to run multiprocessor.
-         Currently this occurs only on various Athlons that are not
-         SMP capable.
+     hasn't been certified as safe to run multiprocessor.
+     Currently this occurs only on various Athlons that are not
+     SMP capable.
+
+  4: 'R' if a module was force unloaded by "rmmod -f", ' ' if all
+     modules were unloaded normally.
+
+  5: 'M' if any processor has reported a Machine Check Exception,
+     ' ' if no Machine Check Exceptions have occurred.
+
+  6: 'B' if a page-release function has found a bad page reference or
+     some unexpected page flags.
 
 The primary reason for the 'Tainted: ' string is to tell kernel
 debuggers if this is a clean kernel or if anything unusual has
-occurred.  Tainting is permanent, even if an offending module is
-unloading the tainted value remains to indicate that the kernel is not
+occurred.  Tainting is permanent: even if an offending module is
+unloaded, the tainted value remains to indicate that the kernel is not
 trustworthy.
index cc63ae18d147e031f69866c4aca8ebcdacfa5c5c..2ea1149bf6b044b7a77f5c70f7abe48863b60540 100644 (file)
@@ -38,6 +38,12 @@ system the associated daemon will exit gracefully.
 
 Driver Interface -- OBSOLETE, DO NOT USE!
 ----------------*************************
+
+Note: pm_register(), pm_access(), pm_dev_idle() and friends are
+obsolete. Please do not use them. Instead you should properly hook
+your driver into the driver model, and use its suspend()/resume()
+callbacks to do this kind of stuff.
+
 If you are writing a new driver or maintaining an old driver, it
 should include power management support.  Without power management
 support, a single driver may prevent a system with power management
index ebfcdf28485f28aa47ee6af8fd5f4f639aadda59..13cba955cb5af313a2c2cc0866666766ef56a40a 100644 (file)
@@ -75,7 +75,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     adsp_map   - PCM device number maps assigned to the 2st OSS device.
                - Default: 1
     nonblock_open
-               - Don't block opening busy PCM devices.
+               - Don't block opening busy PCM devices.  Default: 1
 
     For example, when dsp_map=2, /dev/dsp will be mapped to PCM #2 of
     the card #0.  Similarly, when adsp_map=0, /dev/adsp will be mapped
@@ -148,6 +148,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Module supports up to 8 cards. This module does not support autoprobe
     thus main port must be specified!!! Other ports are optional.
     
+  Module snd-ad1889
+  -----------------
+
+    Module for Analog Devices AD1889 chips.
+
+    ac97_quirk  - AC'97 workaround for strange hardware
+                  See the description of intel8x0 module for details.
+
+    This module supports up to 8 cards.
+
   Module snd-ali5451
   ------------------
 
@@ -189,15 +199,20 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   Module snd-atiixp
   -----------------
 
-    Module for ATI IXP 150/200/250 AC97 controllers.
+    Module for ATI IXP 150/200/250/400 AC97 controllers.
 
-    ac97_clock         - AC'97 clock (defalut = 48000)
+    ac97_clock         - AC'97 clock (default = 48000)
     ac97_quirk         - AC'97 workaround for strange hardware
-                         See the description of intel8x0 module for details.
+                         See "AC97 Quirk Option" section below.
     spdif_aclink       - S/PDIF transfer over AC-link (default = 1)
 
     This module supports up to 8 cards and autoprobe.
 
+    ATI IXP has two different methods to control SPDIF output.  One is
+    over AC-link and another is over the "direct" SPDIF output.  The
+    implementation depends on the motherboard, and you'll need to
+    choose the correct one via spdif_aclink module option.
+
   Module snd-atiixp-modem
   -----------------------
 
@@ -230,7 +245,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     The hardware EQ hardware and SPDIF is only present in the Vortex2 and 
     Advantage.
 
-    Note: Some ALSA mixer applicactions don't handle the SPDIF samplerate 
+    Note: Some ALSA mixer applications don't handle the SPDIF sample rate 
            control correctly. If you have problems regarding this, try
            another ALSA compliant mixer (alsamixer works).
 
@@ -302,7 +317,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     mpu_port   - 0x300,0x310,0x320,0x330, 0 = disable (default)
     fm_port     - 0x388 (default), 0 = disable (default)
-    soft_ac3    - Sofware-conversion of raw SPDIF packets (model 033 only)
+    soft_ac3    - Software-conversion of raw SPDIF packets (model 033 only)
                   (default = 1)
     joystick_port - Joystick port address (0 = disable, 1 = auto-detect)
 
@@ -384,7 +399,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Module for PCI sound cards based on CS4610/CS4612/CS4614/CS4615/CS4622/
                                       CS4624/CS4630/CS4280 PCI chips.
 
-    external_amp     - Force to enable external amplifer.
+    external_amp     - Force to enable external amplifier.
     thinkpad         - Force to enable Thinkpad's CLKRUN control.
     mmap_valid       - Support OSS mmap mode (default = 0).
 
@@ -620,7 +635,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
               VIA VT8251/VT8237A
 
     model      - force the model name
-    position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF)
+    position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
 
     Module supports up to 8 cards.
 
@@ -656,6 +671,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          allout        5-jack in back, 2-jack in front, SPDIF out
          auto          auto-config reading BIOS (default)
 
+    If the default configuration doesn't work and one of the above
+    matches with your device, report it together with the PCI
+    subsystem ID (output of "lspci -nv") to ALSA BTS or alsa-devel
+    ML (see the section "Links and Addresses").
+
     Note 2: If you get click noises on output, try the module option
            position_fix=1 or 2.  position_fix=1 will use the SD_LPIB
            register value without FIFO size correction as the current
@@ -783,20 +803,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     ac97_clock   - AC'97 codec clock base (0 = auto-detect)
     ac97_quirk    - AC'97 workaround for strange hardware
-                    The following strings are accepted:
-                      default = don't override the default setting
-                      disable = disable the quirk
-                      hp_only = use headphone control as master
-                      swap_hp = swap headphone and master controls
-                      swap_surround = swap master and surround controls
-                      ad_sharing = for AD1985, turn on OMS bit and use headphone
-                      alc_jack = for ALC65x, turn on the jack sense mode
-                      inv_eapd = inverted EAPD implementation
-                      mute_led = bind EAPD bit for turning on/off mute LED
-                    For backward compatibility, the corresponding integer
-                    value -1, 0, ... are accepted, too.
+                   See "AC97 Quirk Option" section below.
     buggy_irq     - Enable workaround for buggy interrupts on some
-                    motherboards (default off)
+                    motherboards (default yes on nForce chips,
+                   otherwise off)
+    buggy_semaphore - Enable workaround for hardwares with buggy
+                   semaphores (e.g. on some ASUS laptops)
+                   (default off)
 
     Module supports autoprobe and multiple bus-master chips (max 8).
 
@@ -808,13 +821,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     motherboard has these devices, use the ns558 or snd-mpu401
     modules, respectively.
 
-    The ac97_quirk option is used to enable/override the workaround
-    for specific devices.  Some hardware have swapped output pins
-    between Master and Headphone, or Surround.  The driver provides
-    the auto-detection of known problematic devices, but some might
-    be unknown or wrongly detected.  In such a case, pass the proper
-    value with this option.
-
     The power-management is supported.
     
   Module snd-intel8x0m
@@ -966,7 +972,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     with machines with other (most likely CS423x or OPL3SAx) chips,
     even though the device is detected in lspci.  In such a case, try
     other drivers, e.g. snd-cs4232 or snd-opl3sa2.  Some has ISA-PnP
-    but some doesn't have ISA PnP.  You'll need to speicfy isapnp=0
+    but some doesn't have ISA PnP.  You'll need to specify isapnp=0
     and proper hardware parameters in the case without ISA PnP.
 
     Note: some laptops need a workaround for AC97 RESET.  For the
@@ -1302,7 +1308,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
                  channels
                  [VIA8233/C, 8235, 8237 only]
     ac97_quirk  - AC'97 workaround for strange hardware
-                  See the description of intel8x0 module for details.
+                 See "AC97 Quirk Option" section below.
 
     Module supports autoprobe and multiple bus-master chips (max 8).
 
@@ -1327,16 +1333,17 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          "lspci -nv").
          If dxs_support=5 does not work, try dxs_support=4; if it
          doesn't work too, try dxs_support=1.  (dxs_support=1 is
-         usually for old motherboards.  The correct implementated
+         usually for old motherboards.  The correct implemented
          board should work with 4 or 5.)  If it still doesn't
          work and the default setting is ok, dxs_support=3 is the
          right choice.  If the default setting doesn't work at all,
          try dxs_support=2 to disable the DXS channels.
          In any cases, please let us know the result and the
-         subsystem vendor/device ids.
+         subsystem vendor/device ids.  See "Links and Addresses"
+         below.
 
     Note: for the MPU401 on VIA823x, use snd-mpu401 driver
-         additonally.  The mpu_port option is for VIA686 chips only.
+         additionally.  The mpu_port option is for VIA686 chips only.
 
   Module snd-via82xx-modem
   ------------------------
@@ -1398,8 +1405,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Module supports up to 8 cards.  The module is compiled only when
     PCMCIA is supported on kernel.
 
-    To activate the driver via the card manager, you'll need to set
-    up /etc/pcmcia/vxpocket.conf.  See the sound/pcmcia/vx/vxpocket.c.
+    With the older 2.6.x kernel, to activate the driver via the card
+    manager, you'll need to set up /etc/pcmcia/vxpocket.conf.  See the
+    sound/pcmcia/vx/vxpocket.c.  2.6.13 or later kernel requires no
+    longer require a config file.
 
     When the driver is compiled as a module and the hotplug firmware
     is supported, the firmware data is loaded via hotplug automatically.
@@ -1411,6 +1420,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     Note: the driver is build only when CONFIG_ISA is set.
     
+    Note2: snd-vxp440 driver is merged to snd-vxpocket driver since
+           ALSA 1.0.10.
+
   Module snd-ymfpci
   -----------------
 
@@ -1436,6 +1448,37 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     Note: the driver is build only when CONFIG_ISA is set.
 
 
+AC97 Quirk Option
+=================
+
+The ac97_quirk option is used to enable/override the workaround for
+specific devices on drivers for on-board AC'97 controllers like
+snd-intel8x0.  Some hardware have swapped output pins between Master
+and Headphone, or Surround (thanks to confusion of AC'97
+specifications from version to version :-)
+
+The driver provides the auto-detection of known problematic devices,
+but some might be unknown or wrongly detected.  In such a case, pass
+the proper value with this option.
+
+The following strings are accepted:
+    - default  Don't override the default setting
+    - disable  Disable the quirk
+    - hp_only  Bind Master and Headphone controls as a single control
+    - swap_hp  Swap headphone and master controls
+    - swap_surround  Swap master and surround controls
+    - ad_sharing  For AD1985, turn on OMS bit and use headphone
+    - alc_jack For ALC65x, turn on the jack sense mode
+    - inv_eapd Inverted EAPD implementation
+    - mute_led Bind EAPD bit for turning on/off mute LED
+
+For backward compatibility, the corresponding integer value -1, 0,
+... are  accepted, too.
+
+For example, if "Master" volume control has no effect on your device
+but only "Headphone" does, pass ac97_quirk=hp_only module option.
+
+
 Configuring Non-ISAPNP Cards
 ============================
 
@@ -1553,6 +1596,8 @@ Proc interfaces (/proc/asound)
          - whole-frag  write only whole fragments (optimization affecting
                        playback only)
          - no-silence  do not fill silence ahead to avoid clicks
+         - buggy-ptr   Returns the whitespace blocks in GETOPTR ioctl
+                       instead of filled blocks
 
   Example: echo "x11amp 128 16384" > /proc/asound/card0/pcm0p/oss
            echo "squake 0 0 disable" > /proc/asound/card0/pcm0c/oss
@@ -1589,9 +1634,14 @@ commands to the snd-page-alloc driver:
     use.
 
 
-Links
-=====
+Links and Addresses
+===================
 
   ALSA project homepage
        http://www.alsa-project.org
 
+  ALSA Bug Tracking System
+       https://bugtrack.alsa-project.org/bugs/
+
+  ALSA Developers ML
+       mailto:alsa-devel@lists.sourceforge.net
index 0475478c2484c90c3b14b6c74a4a8efe8fa4941b..24e85520890b902a799def758cef191f78a30490 100644 (file)
           ....
 
           /* allocate a chip-specific data with zero filled */
-          chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+          chip = kzalloc(sizeof(*chip), GFP_KERNEL);
           if (chip == NULL)
                   return -ENOMEM;
 
           After allocating a card instance via
           <function>snd_card_new()</function> (with
           <constant>NULL</constant> on the 4th arg), call
-          <function>kcalloc()</function>. 
+          <function>kzalloc()</function>. 
 
           <informalexample>
             <programlisting>
   mychip_t *chip;
   card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL);
   .....
-  chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+  chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 ]]>
             </programlisting>
           </informalexample>
                   return -ENXIO;
           }
 
-          chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+          chip = kzalloc(sizeof(*chip), GFP_KERNEL);
           if (chip == NULL) {
                   pci_disable_device(pci);
                   return -ENOMEM;
       need to initialize this number as -1 before actual allocation,
       since irq 0 is valid. The port address and its resource pointer
       can be initialized as null by
-      <function>kcalloc()</function> automatically, so you
+      <function>kzalloc()</function> automatically, so you
       don't have to take care of resetting them. 
       </para>
 
index a67bf7d315d7ee14923789fc66eb08649178f4ce..d1e0eb46d201fb8574625f587159fe991ff6e609 100644 (file)
@@ -370,7 +370,10 @@ W: http://atmelwlandriver.sourceforge.net/
 S:     Maintained
 
 AUDIT SUBSYSTEM
-L:     linux-audit@redhat.com (subscribers-only)
+P:     David Woodhouse
+M:     dwmw2@infradead.org
+L:     linux-audit@redhat.com
+W:     http://people.redhat.com/sgrubb/audit/
 S:     Maintained
 
 AX.25 NETWORK LAYER
index 949ec4427f2165efdd2a7c04a66d391a76c7da6e..2ad4aa2a1536c1ca22e1843352cdd9d2ac9cfbb7 100644 (file)
@@ -131,7 +131,7 @@ __syscall_start:
                .long   sys_wait4
 /* 115 */      .long   sys_swapoff
                .long   sys_sysinfo
-               .long   sys_ipc
+               .long   sys_ipc_wrapper
                .long   sys_fsync
                .long   sys_sigreturn_wrapper
 /* 120 */      .long   sys_clone_wrapper
index db302c6e53439ddd553d42992109deccc3105741..81d450ac3fab2e1351b15860d9e6bda727261198 100644 (file)
@@ -273,6 +273,10 @@ sys_mbind_wrapper:
                str     r5, [sp, #4]
                b       sys_mbind
 
+sys_ipc_wrapper:
+               str     r5, [sp, #4]            @ push sixth arg
+               b       sys_ipc
+
 /*
  * Note: off_4k (r5) is always units of 4K.  If we can't do the requested
  * offset, we return EINVAL.
index 405a55f2287cc8b0b459f431effca8bc25d4ebdb..3e5f69bb5ac40764427b4d0d09ee1bedb040c1e9 100644 (file)
@@ -20,40 +20,66 @@ config ARCH_PXA_IDP
        select PXA25x
 
 config PXA_SHARPSL
-       bool "SHARP SL-5600 and SL-C7xx Models"
-       select PXA25x
+       bool "SHARP Zaurus SL-5600, SL-C7xx and SL-Cxx00 Models"
        select SHARP_SCOOP
        select SHARP_PARAM
        help
          Say Y here if you intend to run this kernel on a
-         Sharp SL-5600 (Poodle), Sharp SL-C700 (Corgi),
-         SL-C750 (Shepherd) or a Sharp SL-C760 (Husky)
-         handheld computer.
+         Sharp Zaurus SL-5600 (Poodle), SL-C700 (Corgi),
+         SL-C750 (Shepherd), SL-C760 (Husky), SL-C1000 (Akita),
+         SL-C3000 (Spitz) or SL-C3100 (Borzoi) handheld computer.
 
 endchoice
 
+if PXA_SHARPSL
+
+choice
+       prompt "Select target Sharp Zaurus device range"
+
+config PXA_SHARPSL_25x
+       bool "Sharp PXA25x models (SL-5600 and SL-C7xx)"
+       select PXA25x
+
+config PXA_SHARPSL_27x
+       bool "Sharp PXA270 models (SL-Cxx00)"
+       select PXA27x
+
+endchoice
+
+endif
+
 endmenu
 
 config MACH_POODLE
        bool "Enable Sharp SL-5600 (Poodle) Support"
-       depends PXA_SHARPSL
+       depends PXA_SHARPSL_25x
        select SHARP_LOCOMO
 
 config MACH_CORGI
        bool "Enable Sharp SL-C700 (Corgi) Support"
-       depends PXA_SHARPSL
+       depends PXA_SHARPSL_25x
        select PXA_SHARP_C7xx
 
 config MACH_SHEPHERD
        bool "Enable Sharp SL-C750 (Shepherd) Support"
-       depends PXA_SHARPSL
+       depends PXA_SHARPSL_25x
        select PXA_SHARP_C7xx
 
 config MACH_HUSKY
        bool "Enable Sharp SL-C760 (Husky) Support"
-       depends PXA_SHARPSL
+       depends PXA_SHARPSL_25x
        select PXA_SHARP_C7xx
 
+config MACH_SPITZ
+       bool "Enable Sharp Zaurus SL-3000 (Spitz) Support"
+       depends PXA_SHARPSL_27x
+       select PXA_SHARP_Cxx00
+
+config MACH_BORZOI
+       bool "Enable Sharp Zaurus SL-3100 (Borzoi) Support"
+       depends PXA_SHARPSL_27x
+       select PXA_SHARP_Cxx00
+
 config PXA25x
        bool
        help
@@ -74,4 +100,9 @@ config PXA_SHARP_C7xx
        help
          Enable support for all Sharp C7xx models
 
+config PXA_SHARP_Cxx00
+       bool
+       help
+         Enable common support for Sharp Cxx00 models
+
 endif
index 33dae99ec2d843290105013226519a47e3a50daf..f609a0f232cb6424918bda6f494e633b24f45382 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
 obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
 obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
 obj-$(CONFIG_PXA_SHARP_C7xx)   += corgi.o corgi_ssp.o corgi_lcd.o ssp.o
+obj-$(CONFIG_PXA_SHARP_Cxx00)  += spitz.o corgi_ssp.o corgi_lcd.o ssp.o
 obj-$(CONFIG_MACH_POODLE)      += poodle.o
 
 # Support for blinky lights
index 07b5dd453565402d9ec8c69b691681bae063be5a..426c2bc517eb7ca8fd42a06fa2e6b0d971b24324 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/hardware/scoop.h>
 
 #include "generic.h"
+#include "sharpsl.h"
 
 
 /*
@@ -94,14 +95,30 @@ struct platform_device corgissp_device = {
        .id             = -1,
 };
 
+struct corgissp_machinfo corgi_ssp_machinfo = {
+       .port           = 1,
+       .cs_lcdcon      = CORGI_GPIO_LCDCON_CS,
+       .cs_ads7846     = CORGI_GPIO_ADS7846_CS,
+       .cs_max1111     = CORGI_GPIO_MAX1111_CS,
+       .clk_lcdcon     = 76,
+       .clk_ads7846    = 2,
+       .clk_max1111    = 8,
+};
+
 
 /*
  * Corgi Backlight Device
  */
+static struct corgibl_machinfo corgi_bl_machinfo = {
+       .max_intensity = 0x2f,
+       .set_bl_intensity = corgi_bl_set_intensity,
+};
+
 static struct platform_device corgibl_device = {
        .name           = "corgi-bl",
        .dev            = {
                .parent = &corgifb_device.dev,
+               .platform_data  = &corgi_bl_machinfo,
        },
        .id             = -1,
 };
@@ -119,12 +136,29 @@ static struct platform_device corgikbd_device = {
 /*
  * Corgi Touch Screen Device
  */
+static struct resource corgits_resources[] = {
+       [0] = {
+               .start          = CORGI_IRQ_GPIO_TP_INT,
+               .end            = CORGI_IRQ_GPIO_TP_INT,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct corgits_machinfo  corgi_ts_machinfo = {
+       .get_hsync_len   = corgi_get_hsync_len,
+       .put_hsync       = corgi_put_hsync,
+       .wait_hsync      = corgi_wait_hsync,
+};
+
 static struct platform_device corgits_device = {
        .name           = "corgi-ts",
        .dev            = {
                .parent = &corgissp_device.dev,
+               .platform_data  = &corgi_ts_machinfo,
        },
        .id             = -1,
+       .num_resources  = ARRAY_SIZE(corgits_resources),
+       .resource       = corgits_resources,
 };
 
 
@@ -225,7 +259,10 @@ static struct platform_device *devices[] __initdata = {
 
 static void __init corgi_init(void)
 {
+       corgi_ssp_set_machinfo(&corgi_ssp_machinfo);
+
        pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
+       pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
        pxa_set_udc_info(&udc_info);
        pxa_set_mci_info(&corgi_mci_platform_data);
 
index deac29c0029019136f87df697ac9d2e1f46334bb..c5efcd04fcbc8011c01961ca334a080dcf62005a 100644 (file)
@@ -1,10 +1,14 @@
 /*
  * linux/drivers/video/w100fb.c
  *
- * Corgi LCD Specific Code for ATI Imageon w100 (Wallaby)
+ * Corgi/Spitz LCD Specific Code
  *
  * Copyright (C) 2005 Richard Purdie
  *
+ * Connectivity:
+ *   Corgi - LCD to ATI Imageon w100 (Wallaby)
+ *   Spitz - LCD to PXA Framebuffer
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
+#include <linux/module.h>
+#include <asm/mach-types.h>
+#include <asm/arch/akita.h>
 #include <asm/arch/corgi.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/sharpsl.h>
+#include <asm/arch/spitz.h>
+#include <asm/hardware/scoop.h>
 #include <asm/mach/sharpsl_param.h>
-#include <video/w100fb.h>
+#include "generic.h"
 
 /* Register Addresses */
 #define RESCTL_ADRS     0x00
@@ -134,10 +146,10 @@ static void lcdtg_set_common_voltage(u8 base_data, u8 data)
 }
 
 /* Set Phase Adjuct */
-static void lcdtg_set_phadadj(struct w100fb_par *par)
+static void lcdtg_set_phadadj(int mode)
 {
        int adj;
-       switch(par->xres) {
+       switch(mode) {
                case 480:
                case 640:
                        /* Setting for VGA */
@@ -161,7 +173,7 @@ static void lcdtg_set_phadadj(struct w100fb_par *par)
 
 static int lcd_inited;
 
-static void lcdtg_hw_init(struct w100fb_par *par)
+static void lcdtg_hw_init(int mode)
 {
        if (!lcd_inited) {
                int comadj;
@@ -215,7 +227,7 @@ static void lcdtg_hw_init(struct w100fb_par *par)
                corgi_ssp_lcdtg_send(PICTRL_ADRS, 0);
 
                /* Set Phase Adjuct */
-               lcdtg_set_phadadj(par);
+               lcdtg_set_phadadj(mode);
 
                /* Initialize for Input Signals from ATI */
                corgi_ssp_lcdtg_send(POLCTRL_ADRS, POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE
@@ -224,10 +236,10 @@ static void lcdtg_hw_init(struct w100fb_par *par)
 
                lcd_inited=1;
        } else {
-               lcdtg_set_phadadj(par);
+               lcdtg_set_phadadj(mode);
        }
 
-       switch(par->xres) {
+       switch(mode) {
                case 480:
                case 640:
                        /* Set Lcd Resolution (VGA) */
@@ -242,7 +254,7 @@ static void lcdtg_hw_init(struct w100fb_par *par)
        }
 }
 
-static void lcdtg_suspend(struct w100fb_par *par)
+static void lcdtg_suspend(void)
 {
        /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
        mdelay(34);
@@ -276,15 +288,30 @@ static void lcdtg_suspend(struct w100fb_par *par)
        lcd_inited = 0;
 }
 
-static struct w100_tg_info corgi_lcdtg_info = {
-       .change=lcdtg_hw_init,
-       .suspend=lcdtg_suspend,
-       .resume=lcdtg_hw_init,
-};
 
 /*
  * Corgi w100 Frame Buffer Device
  */
+#ifdef CONFIG_PXA_SHARP_C7xx
+
+#include <video/w100fb.h>
+
+static void w100_lcdtg_suspend(struct w100fb_par *par)
+{
+       lcdtg_suspend();
+}
+
+static void w100_lcdtg_init(struct w100fb_par *par)
+{
+       lcdtg_hw_init(par->xres);
+}
+
+
+static struct w100_tg_info corgi_lcdtg_info = {
+       .change  = w100_lcdtg_init,
+       .suspend = w100_lcdtg_suspend,
+       .resume  = w100_lcdtg_init,
+};
 
 static struct w100_mem_info corgi_fb_mem = {
        .ext_cntl          = 0x00040003,
@@ -394,3 +421,145 @@ struct platform_device corgifb_device = {
        },
 
 };
+#endif
+
+
+/*
+ * Spitz PXA Frame Buffer Device
+ */
+#ifdef CONFIG_PXA_SHARP_Cxx00
+
+#include <asm/arch/pxafb.h>
+
+void spitz_lcd_power(int on)
+{
+       if (on)
+               lcdtg_hw_init(480);
+       else
+               lcdtg_suspend();
+}
+
+#endif
+
+
+/*
+ * Corgi/Spitz Touchscreen to LCD interface
+ */
+static unsigned long (*get_hsync_time)(struct device *dev);
+
+static void inline sharpsl_wait_sync(int gpio)
+{
+       while((GPLR(gpio) & GPIO_bit(gpio)) == 0);
+       while((GPLR(gpio) & GPIO_bit(gpio)) != 0);
+}
+
+#ifdef CONFIG_PXA_SHARP_C7xx
+unsigned long corgi_get_hsync_len(void)
+{
+       if (!get_hsync_time)
+               get_hsync_time = symbol_get(w100fb_get_hsynclen);
+       if (!get_hsync_time)
+               return 0;
+
+       return get_hsync_time(&corgifb_device.dev);
+}
+
+void corgi_put_hsync(void)
+{
+       if (get_hsync_time)
+               symbol_put(w100fb_get_hsynclen);
+}
+
+void corgi_wait_hsync(void)
+{
+       sharpsl_wait_sync(CORGI_GPIO_HSYNC);
+}
+#endif
+
+#ifdef CONFIG_PXA_SHARP_Cxx00
+unsigned long spitz_get_hsync_len(void)
+{
+       if (!get_hsync_time)
+               get_hsync_time = symbol_get(pxafb_get_hsync_time);
+       if (!get_hsync_time)
+               return 0;
+
+       return pxafb_get_hsync_time(&pxafb_device.dev);
+}
+
+void spitz_put_hsync(void)
+{
+       if (get_hsync_time)
+               symbol_put(pxafb_get_hsync_time);
+}
+
+void spitz_wait_hsync(void)
+{
+       sharpsl_wait_sync(SPITZ_GPIO_HSYNC);
+}
+#endif
+
+/*
+ * Corgi/Spitz Backlight Power
+ */
+#ifdef CONFIG_PXA_SHARP_C7xx
+void corgi_bl_set_intensity(int intensity)
+{
+       if (intensity > 0x10)
+               intensity += 0x10;
+
+       /* Bits 0-4 are accessed via the SSP interface */
+       corgi_ssp_blduty_set(intensity & 0x1f);
+
+       /* Bit 5 is via SCOOP */
+       if (intensity & 0x0020)
+               set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
+       else
+               reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT);
+}
+#endif
+
+
+#if defined(CONFIG_MACH_SPITZ) || defined(CONFIG_MACH_BORZOI)
+void spitz_bl_set_intensity(int intensity)
+{
+       if (intensity > 0x10)
+               intensity += 0x10;
+
+       /* Bits 0-4 are accessed via the SSP interface */
+       corgi_ssp_blduty_set(intensity & 0x1f);
+
+       /* Bit 5 is via SCOOP */
+       if (intensity & 0x0020)
+               reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT);
+       else
+               set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT);
+
+       if (intensity)
+               set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON);
+       else
+               reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON);
+}
+#endif
+
+#ifdef CONFIG_MACH_AKITA
+void akita_bl_set_intensity(int intensity)
+{
+       if (intensity > 0x10)
+               intensity += 0x10;
+
+       /* Bits 0-4 are accessed via the SSP interface */
+       corgi_ssp_blduty_set(intensity & 0x1f);
+
+       /* Bit 5 is via IO-Expander */
+       if (intensity & 0x0020)
+               akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT);
+       else
+               akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT);
+
+       if (intensity)
+               akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON);
+       else
+               akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON);
+}
+#endif
index 366a9bde3d8be08880231795926d834839d35ddc..0ef42828705526b5fc06823144791e3a93351fbb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  SSP control code for Sharp Corgi devices
  *
- *  Copyright (c) 2004 Richard Purdie
+ *  Copyright (c) 2004-2005 Richard Purdie
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 
 #include <asm/arch/ssp.h>
-#include <asm/arch/corgi.h>
 #include <asm/arch/pxa-regs.h>
+#include "sharpsl.h"
 
 static DEFINE_SPINLOCK(corgi_ssp_lock);
 static struct ssp_dev corgi_ssp_dev;
 static struct ssp_state corgi_ssp_state;
+static struct corgissp_machinfo *ssp_machinfo;
 
 /*
  * There are three devices connected to the SSP interface:
@@ -48,12 +50,12 @@ unsigned long corgi_ssp_ads7846_putget(ulong data)
        unsigned long ret,flag;
 
        spin_lock_irqsave(&corgi_ssp_lock, flag);
-       GPCR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+       GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
 
        ssp_write_word(&corgi_ssp_dev,data);
        ret = ssp_read_word(&corgi_ssp_dev);
 
-       GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+       GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
        spin_unlock_irqrestore(&corgi_ssp_lock, flag);
 
        return ret;
@@ -66,12 +68,12 @@ unsigned long corgi_ssp_ads7846_putget(ulong data)
 void corgi_ssp_ads7846_lock(void)
 {
        spin_lock(&corgi_ssp_lock);
-       GPCR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+       GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
 }
 
 void corgi_ssp_ads7846_unlock(void)
 {
-       GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);
+       GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
        spin_unlock(&corgi_ssp_lock);
 }
 
@@ -97,23 +99,27 @@ EXPORT_SYMBOL(corgi_ssp_ads7846_get);
  */
 unsigned long corgi_ssp_dac_put(ulong data)
 {
-       unsigned long flag;
+       unsigned long flag, sscr1 = SSCR1_SPH;
 
        spin_lock_irqsave(&corgi_ssp_lock, flag);
-       GPCR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS);
+
+       if (machine_is_spitz() || machine_is_akita() || machine_is_borzoi())
+               sscr1 = 0;
 
        ssp_disable(&corgi_ssp_dev);
-       ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), SSCR1_SPH, 0, SSCR0_SerClkDiv(76));
+       ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), sscr1, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_lcdcon));
        ssp_enable(&corgi_ssp_dev);
 
+       GPCR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
        ssp_write_word(&corgi_ssp_dev,data);
        /* Read null data back from device to prevent SSP overflow */
        ssp_read_word(&corgi_ssp_dev);
+       GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
 
        ssp_disable(&corgi_ssp_dev);
-       ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2));
+       ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
        ssp_enable(&corgi_ssp_dev);
-       GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS);
+
        spin_unlock_irqrestore(&corgi_ssp_lock, flag);
 
        return 0;
@@ -141,9 +147,9 @@ int corgi_ssp_max1111_get(ulong data)
        int voltage,voltage1,voltage2;
 
        spin_lock_irqsave(&corgi_ssp_lock, flag);
-       GPCR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS);
+       GPCR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
        ssp_disable(&corgi_ssp_dev);
-       ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(8));
+       ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_max1111));
        ssp_enable(&corgi_ssp_dev);
 
        udelay(1);
@@ -161,9 +167,9 @@ int corgi_ssp_max1111_get(ulong data)
        voltage2=ssp_read_word(&corgi_ssp_dev);
 
        ssp_disable(&corgi_ssp_dev);
-       ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2));
+       ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
        ssp_enable(&corgi_ssp_dev);
-       GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS);
+       GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
        spin_unlock_irqrestore(&corgi_ssp_lock, flag);
 
        if (voltage1 & 0xc0 || voltage2 & 0x3f)
@@ -179,25 +185,31 @@ EXPORT_SYMBOL(corgi_ssp_max1111_get);
 /*
  *  Support Routines
  */
-int __init corgi_ssp_probe(struct device *dev)
+
+void __init corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo)
+{
+       ssp_machinfo = machinfo;
+}
+
+static int __init corgi_ssp_probe(struct device *dev)
 {
        int ret;
 
        /* Chip Select - Disable All */
-       GPDR0 |= GPIO_bit(CORGI_GPIO_LCDCON_CS); /* output */
-       GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS);  /* High - Disable LCD Control/Timing Gen */
-       GPDR0 |= GPIO_bit(CORGI_GPIO_MAX1111_CS); /* output */
-       GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS);  /* High - Disable MAX1111*/
-       GPDR0 |= GPIO_bit(CORGI_GPIO_ADS7846_CS);  /* output */
-       GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS);   /* High - Disable ADS7846*/
+       GPDR(ssp_machinfo->cs_lcdcon) |= GPIO_bit(ssp_machinfo->cs_lcdcon); /* output */
+       GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);  /* High - Disable LCD Control/Timing Gen */
+       GPDR(ssp_machinfo->cs_max1111) |= GPIO_bit(ssp_machinfo->cs_max1111); /* output */
+       GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);  /* High - Disable MAX1111*/
+       GPDR(ssp_machinfo->cs_ads7846) |= GPIO_bit(ssp_machinfo->cs_ads7846);  /* output */
+       GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);   /* High - Disable ADS7846*/
 
-       ret=ssp_init(&corgi_ssp_dev,1);
+       ret = ssp_init(&corgi_ssp_dev,ssp_machinfo->port);
 
        if (ret)
                printk(KERN_ERR "Unable to register SSP handler!\n");
        else {
                ssp_disable(&corgi_ssp_dev);
-               ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2));
+               ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
                ssp_enable(&corgi_ssp_dev);
        }
 
@@ -222,9 +234,9 @@ static int corgi_ssp_suspend(struct device *dev, pm_message_t state, u32 level)
 static int corgi_ssp_resume(struct device *dev, u32 level)
 {
        if (level == RESUME_POWER_ON) {
-               GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS);  /* High - Disable LCD Control/Timing Gen */
-               GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); /* High - Disable MAX1111*/
-               GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); /* High - Disable ADS7846*/
+               GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);  /* High - Disable LCD Control/Timing Gen */
+               GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/
+               GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/
                ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state);
                ssp_enable(&corgi_ssp_dev);
        }
diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h
new file mode 100644 (file)
index 0000000..3977a77
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SharpSL SSP Driver
+ */
+
+struct corgissp_machinfo {
+       int port;
+       int cs_lcdcon;
+       int cs_ads7846;
+       int cs_max1111;
+       int clk_lcdcon;
+       int clk_ads7846;
+       int clk_max1111;
+};
+
+void corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo);
+
+/*
+ * SharpSL Backlight
+ */
+
+void corgi_bl_set_intensity(int intensity);
+void spitz_bl_set_intensity(int intensity);
+void akita_bl_set_intensity(int intensity);
+
+/*
+ * SharpSL Touchscreen Driver
+ */
+
+unsigned long corgi_get_hsync_len(void);
+unsigned long spitz_get_hsync_len(void);
+void corgi_put_hsync(void);
+void spitz_put_hsync(void);
+void corgi_wait_hsync(void);
+void spitz_wait_hsync(void);
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
new file mode 100644 (file)
index 0000000..568afe3
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Support for Sharp SL-Cxx00 Series of PDAs
+ * Models: SL-C3000 (Spitz), SL-C1000 (Akita) and SL-C3100 (Borzoi)
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * Based on Sharp's 2.4 kernel patches/lubbock.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/mmc/host.h>
+
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irq.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/udc.h>
+#include <asm/arch/ohci.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/akita.h>
+#include <asm/arch/spitz.h>
+#include <asm/arch/sharpsl.h>
+
+#include <asm/mach/sharpsl_param.h>
+#include <asm/hardware/scoop.h>
+
+#include "generic.h"
+#include "sharpsl.h"
+
+/*
+ * Spitz SCOOP Device #1
+ */
+static struct resource spitz_scoop_resources[] = {
+       [0] = {
+               .start          = 0x10800000,
+               .end            = 0x10800fff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct scoop_config spitz_scoop_setup = {
+       .io_dir         = SPITZ_SCP_IO_DIR,
+       .io_out         = SPITZ_SCP_IO_OUT,
+       .suspend_clr = SPITZ_SCP_SUS_CLR,
+       .suspend_set = SPITZ_SCP_SUS_SET,
+};
+
+struct platform_device spitzscoop_device = {
+       .name           = "sharp-scoop",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &spitz_scoop_setup,
+       },
+       .num_resources  = ARRAY_SIZE(spitz_scoop_resources),
+       .resource       = spitz_scoop_resources,
+};
+
+/*
+ * Spitz SCOOP Device #2
+ */
+static struct resource spitz_scoop2_resources[] = {
+       [0] = {
+               .start          = 0x08800040,
+               .end            = 0x08800fff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct scoop_config spitz_scoop2_setup = {
+       .io_dir         = SPITZ_SCP2_IO_DIR,
+       .io_out         = SPITZ_SCP2_IO_OUT,
+       .suspend_clr = SPITZ_SCP2_SUS_CLR,
+       .suspend_set = SPITZ_SCP2_SUS_SET,
+};
+
+struct platform_device spitzscoop2_device = {
+       .name           = "sharp-scoop",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &spitz_scoop2_setup,
+       },
+       .num_resources  = ARRAY_SIZE(spitz_scoop2_resources),
+       .resource       = spitz_scoop2_resources,
+};
+
+static struct scoop_pcmcia_dev spitz_pcmcia_scoop[] = {
+{
+       .dev        = &spitzscoop_device.dev,
+       .irq        = SPITZ_IRQ_GPIO_CF_IRQ,
+       .cd_irq     = SPITZ_IRQ_GPIO_CF_CD,
+       .cd_irq_str = "PCMCIA0 CD",
+},{
+       .dev        = &spitzscoop2_device.dev,
+       .irq        = SPITZ_IRQ_GPIO_CF2_IRQ,
+       .cd_irq     = -1,
+},
+};
+
+
+/*
+ * Spitz SSP Device
+ *
+ * Set the parent as the scoop device because a lot of SSP devices
+ * also use scoop functions and this makes the power up/down order
+ * work correctly.
+ */
+struct platform_device spitzssp_device = {
+       .name           = "corgi-ssp",
+       .dev            = {
+               .parent = &spitzscoop_device.dev,
+       },
+       .id             = -1,
+};
+
+struct corgissp_machinfo spitz_ssp_machinfo = {
+       .port           = 2,
+       .cs_lcdcon      = SPITZ_GPIO_LCDCON_CS,
+       .cs_ads7846     = SPITZ_GPIO_ADS7846_CS,
+       .cs_max1111     = SPITZ_GPIO_MAX1111_CS,
+       .clk_lcdcon     = 520,
+       .clk_ads7846    = 14,
+       .clk_max1111    = 56,
+};
+
+
+/*
+ * Spitz Backlight Device
+ */
+static struct corgibl_machinfo spitz_bl_machinfo = {
+       .max_intensity = 0x2f,
+};
+
+static struct platform_device spitzbl_device = {
+       .name           = "corgi-bl",
+       .dev            = {
+               .platform_data  = &spitz_bl_machinfo,
+       },
+       .id             = -1,
+};
+
+
+/*
+ * Spitz Keyboard Device
+ */
+static struct platform_device spitzkbd_device = {
+       .name           = "spitz-keyboard",
+       .id             = -1,
+};
+
+
+/*
+ * Spitz Touch Screen Device
+ */
+static struct resource spitzts_resources[] = {
+       [0] = {
+               .start          = SPITZ_IRQ_GPIO_TP_INT,
+               .end            = SPITZ_IRQ_GPIO_TP_INT,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct corgits_machinfo  spitz_ts_machinfo = {
+       .get_hsync_len   = spitz_get_hsync_len,
+       .put_hsync       = spitz_put_hsync,
+       .wait_hsync      = spitz_wait_hsync,
+};
+
+static struct platform_device spitzts_device = {
+       .name           = "corgi-ts",
+       .dev            = {
+               .parent = &spitzssp_device.dev,
+               .platform_data  = &spitz_ts_machinfo,
+       },
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(spitzts_resources),
+       .resource       = spitzts_resources,
+};
+
+
+/*
+ * MMC/SD Device
+ *
+ * The card detect interrupt isn't debounced so we delay it by 250ms
+ * to give the card a chance to fully insert/eject.
+ */
+
+static struct pxamci_platform_data spitz_mci_platform_data;
+
+static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(int, void *, struct pt_regs *), void *data)
+{
+       int err;
+
+       /* setup GPIO for PXA27x MMC controller */
+       pxa_gpio_mode(GPIO32_MMCCLK_MD);
+       pxa_gpio_mode(GPIO112_MMCCMD_MD);
+       pxa_gpio_mode(GPIO92_MMCDAT0_MD);
+       pxa_gpio_mode(GPIO109_MMCDAT1_MD);
+       pxa_gpio_mode(GPIO110_MMCDAT2_MD);
+       pxa_gpio_mode(GPIO111_MMCDAT3_MD);
+       pxa_gpio_mode(SPITZ_GPIO_nSD_DETECT | GPIO_IN);
+       pxa_gpio_mode(SPITZ_GPIO_nSD_WP | GPIO_IN);
+
+       spitz_mci_platform_data.detect_delay = msecs_to_jiffies(250);
+
+       err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int, SA_INTERRUPT,
+                            "MMC card detect", data);
+       if (err) {
+               printk(KERN_ERR "spitz_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
+               return -1;
+       }
+
+       set_irq_type(SPITZ_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE);
+
+       return 0;
+}
+
+/* Power control is shared with one of the CF slots so we have a mess */
+static void spitz_mci_setpower(struct device *dev, unsigned int vdd)
+{
+       struct pxamci_platform_data* p_d = dev->platform_data;
+
+       unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR);
+
+       if (( 1 << vdd) & p_d->ocr_mask) {
+               /* printk(KERN_DEBUG "%s: on\n", __FUNCTION__); */
+               set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+               mdelay(2);
+               write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | 0x04);
+       } else {
+               /* printk(KERN_DEBUG "%s: off\n", __FUNCTION__); */
+               write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr & ~0x04);
+
+               if (!(cpr | 0x02)) {
+                       mdelay(1);
+                       reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
+               }
+       }
+}
+
+static int spitz_mci_get_ro(struct device *dev)
+{
+       return GPLR(SPITZ_GPIO_nSD_WP) & GPIO_bit(SPITZ_GPIO_nSD_WP);
+}
+
+static void spitz_mci_exit(struct device *dev, void *data)
+{
+       free_irq(SPITZ_IRQ_GPIO_nSD_DETECT, data);
+}
+
+static struct pxamci_platform_data spitz_mci_platform_data = {
+       .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
+       .init           = spitz_mci_init,
+       .get_ro         = spitz_mci_get_ro,
+       .setpower       = spitz_mci_setpower,
+       .exit           = spitz_mci_exit,
+};
+
+
+/*
+ * Spitz PXA Framebuffer
+ */
+static struct pxafb_mach_info spitz_pxafb_info __initdata = {
+        .pixclock       = 19231,
+        .xres           = 480,
+        .yres           = 640,
+        .bpp            = 16,
+        .hsync_len      = 40,
+        .left_margin    = 46,
+        .right_margin   = 125,
+        .vsync_len      = 3,
+        .upper_margin   = 1,
+        .lower_margin   = 0,
+        .sync           = 0,
+        .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act | LCCR0_LDDALT | LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM,
+        .lccr3          = LCCR3_PixRsEdg | LCCR3_OutEnH,
+        .pxafb_lcd_power = spitz_lcd_power,
+};
+
+
+static struct platform_device *devices[] __initdata = {
+       &spitzscoop_device,
+       &spitzssp_device,
+       &spitzkbd_device,
+       &spitzts_device,
+       &spitzbl_device,
+       &spitzbattery_device,
+};
+
+static void __init common_init(void)
+{
+       PMCR = 0x00;
+
+       /* setup sleep mode values */
+       PWER  = 0x00000002;
+       PFER  = 0x00000000;
+       PRER  = 0x00000002;
+       PGSR0 = 0x0158C000;
+       PGSR1 = 0x00FF0080;
+       PGSR2 = 0x0001C004;
+
+       /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
+       PCFR |= PCFR_OPDE;
+
+       corgi_ssp_set_machinfo(&spitz_ssp_machinfo);
+
+       pxa_gpio_mode(SPITZ_GPIO_HSYNC | GPIO_IN);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+       pxa_set_mci_info(&spitz_mci_platform_data);
+       pxafb_device.dev.parent = &spitzssp_device.dev;
+       set_pxa_fb_info(&spitz_pxafb_info);
+}
+
+static void __init spitz_init(void)
+{
+       scoop_num = 2;
+       scoop_devs = &spitz_pcmcia_scoop[0];
+       spitz_bl_machinfo.set_bl_intensity = spitz_bl_set_intensity;
+
+       common_init();
+
+       platform_device_register(&spitzscoop2_device);
+}
+
+static void __init fixup_spitz(struct machine_desc *desc,
+               struct tag *tags, char **cmdline, struct meminfo *mi)
+{
+       sharpsl_save_param();
+       mi->nr_banks = 1;
+       mi->bank[0].start = 0xa0000000;
+       mi->bank[0].node = 0;
+       mi->bank[0].size = (64*1024*1024);
+}
+
+#ifdef CONFIG_MACH_SPITZ
+MACHINE_START(SPITZ, "SHARP Spitz")
+       .phys_ram       = 0xa0000000,
+       .phys_io        = 0x40000000,
+       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
+       .fixup          = fixup_spitz,
+       .map_io         = pxa_map_io,
+       .init_irq       = pxa_init_irq,
+       .init_machine   = spitz_init,
+       .timer          = &pxa_timer,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_BORZOI
+MACHINE_START(BORZOI, "SHARP Borzoi")
+       .phys_ram       = 0xa0000000,
+       .phys_io        = 0x40000000,
+       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
+       .fixup          = fixup_spitz,
+       .map_io         = pxa_map_io,
+       .init_irq       = pxa_init_irq,
+       .init_machine   = spitz_init,
+       .timer          = &pxa_timer,
+MACHINE_END
+#endif
index 1cbb9c0f47040d9eb430e738f81871ff18aeacee..350ea6680f63782dcfb237480f83c42b9229005a 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/efi.h>
 #include <linux/dmi.h>
+#include <linux/ctype.h>
 #include <asm/uaccess.h>
 #include <asm/apic.h>
 #include <asm/desc.h>
@@ -28,8 +29,6 @@ static int reboot_thru_bios;
 
 #ifdef CONFIG_SMP
 static int reboot_cpu = -1;
-/* shamelessly grabbed from lib/vsprintf.c for readability */
-#define is_digit(c)    ((c) >= '0' && (c) <= '9')
 #endif
 static int __init reboot_setup(char *str)
 {
@@ -49,9 +48,9 @@ static int __init reboot_setup(char *str)
                        break;
 #ifdef CONFIG_SMP
                case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
-                       if (is_digit(*(str+1))) {
+                       if (isdigit(*(str+1))) {
                                reboot_cpu = (int) (*(str+1) - '0');
-                               if (is_digit(*(str+2))) 
+                               if (isdigit(*(str+2)))
                                        reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
                        }
                                /* we will leave sorting out the final value 
index dc39ca6a7eca82f546c649cb6b2e1b3c6a20b4a2..9b8c8a19824de64c9a308177e11f55df3974099c 100644 (file)
@@ -848,9 +848,7 @@ static void __init parse_cmdline_early (char ** cmdline_p)
 #ifdef CONFIG_X86_IO_APIC
                else if (!memcmp(from, "acpi_skip_timer_override", 24))
                        acpi_skip_timer_override = 1;
-#endif
 
-#ifdef CONFIG_X86_LOCAL_APIC
                if (!memcmp(from, "disable_timer_pin_1", 19))
                        disable_timer_pin_1 = 1;
                if (!memcmp(from, "enable_timer_pin_1", 18))
@@ -859,7 +857,7 @@ static void __init parse_cmdline_early (char ** cmdline_p)
                /* disable IO-APIC */
                else if (!memcmp(from, "noapic", 6))
                        disable_ioapic_setup();
-#endif /* CONFIG_X86_LOCAL_APIC */
+#endif /* CONFIG_X86_IO_APIC */
 #endif /* CONFIG_ACPI */
 
 #ifdef CONFIG_X86_LOCAL_APIC
index c70cd2a083045ea7ff12069a1fce5e9444cd6257..5f0a95d76a4f16fa3c95ba57c131c6eb3c967046 100644 (file)
@@ -202,7 +202,7 @@ static void __devinit smp_store_cpu_info(int id)
                                goto valid_k7;
 
                /* If we get here, it's not a certified SMP capable AMD system. */
-               tainted |= TAINT_UNSAFE_SMP;
+               add_taint(TAINT_UNSAFE_SMP);
        }
 
 valid_k7:
index 09a58cb6daa7050e018496a127458241f2fa0e30..431a551e46ea5f191498eaa6fbe7a6fc7d7273fa 100644 (file)
@@ -807,8 +807,9 @@ void math_error(void __user *eip)
        cwd = get_fpu_cwd(task);
        swd = get_fpu_swd(task);
        switch (swd & ~cwd & 0x3f) {
-               case 0x000:
-               default:
+               case 0x000: /* No unmasked exception */
+                       return;
+               default:    /* Multiple exceptions */
                        break;
                case 0x001: /* Invalid Op */
                        /*
index 31de70b7c67f63f95ba5c685b707f428d0fb1583..a7280d9f6c1634d80cdd7b1b48a90d6eb3a138f4 100644 (file)
@@ -216,12 +216,6 @@ ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack)
        if (!mpnt)
                return -ENOMEM;
 
-       if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))
-                                     >> PAGE_SHIFT)) {
-               kmem_cache_free(vm_area_cachep, mpnt);
-               return -ENOMEM;
-       }
-
        memset(mpnt, 0, sizeof(*mpnt));
 
        down_write(&current->mm->mmap_sem);
index 4de155699c4fa2d748267365c923b6a1eaf2a58a..7ae4af476974cc0583a10086679ae233e4736c47 100644 (file)
@@ -581,18 +581,13 @@ asmlinkage int irix_brk(unsigned long brk)
        }
 
        /*
-        * Check if we have enough memory..
+        * Ok, looks good - let it rip.
         */
-       if (security_vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) {
+       if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) {
                ret = -ENOMEM;
                goto out;
        }
-
-       /*
-        * Ok, looks good - let it rip.
-        */
        mm->brk = brk;
-       do_brk(oldbrk, newbrk-oldbrk);
        ret = 0;
 
 out:
index fe8bb634ead0a1e404edfff77c50260c887442a7..26bd8ea35a4e915e10264202cc12a6937f8c4cbf 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/reg.h>
 #include <asm/nvram.h>
index a3c5281a5d2d8c05e328a6fc5c83f10b9981193c..22d7fd1e0aea7e4e86851db796699ffa3c8f9bee 100644 (file)
@@ -58,7 +58,6 @@
 #include <linux/init.h>
 #include <linux/profile.h>
 
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/nvram.h>
 #include <asm/cache.h>
index 9353584fb7103c77cc866b417eecb12fa729c968..17d2db7e537df7eef854d6500bfc7b13ee84ed45 100644 (file)
@@ -96,6 +96,9 @@ SECTIONS
        *(.init.text)
        _einittext = .;
   }
+  /* .exit.text is discarded at runtime, not link time,
+     to deal with references from __bug_table */
+  .exit.text : { *(.exit.text) }
   .init.data : {
     *(.init.data);
     __vtop_table_begin = .;
@@ -190,5 +193,6 @@ SECTIONS
   /* Sections to be discarded. */
   /DISCARD/ : {
     *(.exitcall.exit)
+    *(.exit.data)
   }
 }
index 4864a7de3daa9ac1373f9a2cf1fe4c288dcbac4d..6037ce7796f5e2e1864749b40636b6e759746b75 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/init.h>
 #include <linux/bcd.h>
 
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/nvram.h>
 #include <asm/prom.h>
index 2bcf8a16d1c936180acae6965438678ef417a17d..8599850ca772f5d8a7cfef073a98875c5afae220 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/ioport.h>
 
 #include <asm/sections.h>
-#include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/machdep.h>
 #include <asm/prep_nvram.h>
index 17e35d0fed09ff87d7eeb0d49e30b02d8e9f139d..1ff4fa05a97329f1a7c5217a7e8737f6f49421e5 100644 (file)
@@ -68,6 +68,7 @@ int main(void)
        DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr));
 #endif /* CONFIG_ALTIVEC */
        DEFINE(MM, offsetof(struct task_struct, mm));
+       DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context));
 
        DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size));
        DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_dline_size));
index d133a49cdf8972270fcd1f668f1d43cbea1a6766..e8c0bbf4d000353c176b55d4da7c36b628b19b65 100644 (file)
@@ -276,12 +276,22 @@ _GLOBAL(ppc64_rt_sigsuspend)
 _GLOBAL(ppc32_rt_sigsuspend)
        bl      .save_nvgprs
        bl      .sys32_rt_sigsuspend
-       /* If sigsuspend() returns zero, we are going into a signal handler */
 70:    cmpdi   0,r3,0
-       beq     .ret_from_except
-       /* If it returned -EINTR, we need to return via syscall_exit to set
+       /* If it returned an error, we need to return via syscall_exit to set
           the SO bit in cr0 and potentially stop for ptrace. */
-       b       syscall_exit
+       bne     syscall_exit
+       /* If sigsuspend() returns zero, we are going into a signal handler. We
+          may need to call audit_syscall_exit() to mark the exit from sigsuspend() */
+#ifdef CONFIG_AUDIT
+       ld      r3,PACACURRENT(r13)
+       ld      r4,AUDITCONTEXT(r3)
+       cmpdi   0,r4,0
+       beq     .ret_from_except        /* No audit_context: Leave immediately. */
+       li      r4, 2                   /* AUDITSC_FAILURE */
+       li      r5,-4                   /* It's always -EINTR */
+       bl      .audit_syscall_exit
+#endif
+       b       .ret_from_except
 
 _GLOBAL(ppc_fork)
        bl      .save_nvgprs
index bfadccc7b8be78e4683fcb0bac7f1fd5189ab3ab..3009701eb90d89b7dfe708ee499e97a6f61ab85d 100644 (file)
@@ -238,8 +238,8 @@ static void __init pSeries_setup_arch(void)
 
        /* Find and initialize PCI host bridges */
        init_pci_config_tokens();
-       eeh_init();
        find_and_init_phbs();
+       eeh_init();
 
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
index 4777676365fe2a60917683cfa713b0f0b5728289..efa985f05aca2ebfe45be32ff4cd1e6b339ce1d8 100644 (file)
@@ -224,10 +224,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack)
        vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
        if (vma == NULL)
                return -ENOMEM;
-       if (security_vm_enough_memory(vdso_pages)) {
-               kmem_cache_free(vm_area_cachep, vma);
-               return -ENOMEM;
-       }
+
        memset(vma, 0, sizeof(*vma));
 
        /*
@@ -237,8 +234,10 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack)
         */
        vdso_base = get_unmapped_area(NULL, vdso_base,
                                      vdso_pages << PAGE_SHIFT, 0, 0);
-       if (vdso_base & ~PAGE_MASK)
+       if (vdso_base & ~PAGE_MASK) {
+               kmem_cache_free(vm_area_cachep, vma);
                return (int)vdso_base;
+       }
 
        current->thread.vdso_base = vdso_base;
 
@@ -266,7 +265,11 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack)
        vma->vm_ops = &vdso_vmops;
 
        down_write(&mm->mmap_sem);
-       insert_vm_struct(mm, vma);
+       if (insert_vm_struct(mm, vma)) {
+               up_write(&mm->mmap_sem);
+               kmem_cache_free(vm_area_cachep, vma);
+               return -ENOMEM;
+       }
        mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
        up_write(&mm->mmap_sem);
 
index c8131f342cfc6de02b41e447b66bdaaee5e83b5b..d9161e395978ca6d423d44b87845290781acb6c8 100644 (file)
@@ -353,11 +353,6 @@ int setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int exec
        mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
        if (!mpnt) 
                return -ENOMEM; 
-       
-       if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) {
-               kmem_cache_free(vm_area_cachep, mpnt);
-               return -ENOMEM;
-       }
 
        memset(mpnt, 0, sizeof(*mpnt));
 
index adbc5f8089e9a209707087ca86048c8358caa93e..3a01329473ab42642210804fc586122d433007f8 100644 (file)
@@ -52,17 +52,13 @@ int syscall32_setup_pages(struct linux_binprm *bprm, int exstack)
        vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
        if (!vma)
                return -ENOMEM;
-       if (security_vm_enough_memory(npages)) {
-               kmem_cache_free(vm_area_cachep, vma);
-               return -ENOMEM;
-       }
 
        memset(vma, 0, sizeof(struct vm_area_struct));
        /* Could randomize here */
        vma->vm_start = VSYSCALL32_BASE;
        vma->vm_end = VSYSCALL32_END;
        /* MAYWRITE to allow gdb to COW and set breakpoints */
-       vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYEXEC|VM_MAYWRITE;
+       vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
        vma->vm_flags |= mm->def_flags;
        vma->vm_page_prot = protection_map[vma->vm_flags & 7];
        vma->vm_ops = &syscall32_vm_ops;
index eb7929eea7b33c4743b533a0d39bf8c22c42707c..4e34b0f9d6138bc9141fc6410ed59d6dabd14001 100644 (file)
@@ -28,6 +28,7 @@ extern char _end[];
  * PFN of last memory page.
  */
 unsigned long end_pfn; 
+EXPORT_SYMBOL(end_pfn);
 
 /* 
  * end_pfn only includes RAM, while end_pfn_map includes all e820 entries.
index 969365c0771b242f5b64071e294bba4cd114fca9..08203b07f4bd6d6c5aa26ddc9cedda58a29fda7f 100644 (file)
@@ -217,7 +217,7 @@ void do_machine_check(struct pt_regs * regs, long error_code)
                        panicm_found = 1;
                }
 
-               tainted |= TAINT_MACHINE_CHECK;
+               add_taint(TAINT_MACHINE_CHECK);
        }
 
        /* Never do anything final in the polling timer */
index 4388b8a5bae761fd04a7ab70af00d5a0b8b04043..39d445e16f2254441b29dcfb6a5a37de5439ca8a 100644 (file)
@@ -366,7 +366,7 @@ static void setup_k7_watchdog(void)
                | K7_NMI_EVENT;
 
        wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
-       wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
+       wrmsrl(MSR_K7_PERFCTR0, -((u64)cpu_khz * 1000 / nmi_hz));
        apic_write(APIC_LVTPC, APIC_DM_NMI);
        evntsel |= K7_EVNTSEL_ENABLE;
        wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
@@ -407,8 +407,8 @@ static int setup_p4_watchdog(void)
 
        wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
        wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
-       Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000));
-       wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1);
+       Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz * 1000UL / nmi_hz));
+       wrmsrl(MSR_P4_IQ_COUNTER0, -((u64)cpu_khz * 1000 / nmi_hz));
        apic_write(APIC_LVTPC, APIC_DM_NMI);
        wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
        return 1;
@@ -506,7 +506,7 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
                        wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
                        apic_write(APIC_LVTPC, APIC_DM_NMI);
                }
-               wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
+               wrmsrl(nmi_perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
        }
 }
 
index 373e7b728fa70746bb13907e07114ee0293fd4f6..6b2eb6f39b4dea6ec809acb715cf1c2ab1fc0b45 100644 (file)
@@ -152,12 +152,13 @@ attribute_container_add_device(struct device *dev,
 
                if (!cont->match(cont, dev))
                        continue;
-               ic = kmalloc(sizeof(struct internal_container), GFP_KERNEL);
+
+               ic = kzalloc(sizeof(*ic), GFP_KERNEL);
                if (!ic) {
                        dev_printk(KERN_ERR, dev, "failed to allocate class container\n");
                        continue;
                }
-               memset(ic, 0, sizeof(struct internal_container));
+
                ic->cont = cont;
                class_device_initialize(&ic->classdev);
                ic->classdev.dev = get_device(dev);
index d164c32a97ad4e90426a4f1e8a244b8d5f7d93d3..3b112e3542f897e81bf881b762f3a317ecaefae4 100644 (file)
@@ -189,12 +189,11 @@ struct class *class_create(struct module *owner, char *name)
        struct class *cls;
        int retval;
 
-       cls = kmalloc(sizeof(struct class), GFP_KERNEL);
+       cls = kzalloc(sizeof(*cls), GFP_KERNEL);
        if (!cls) {
                retval = -ENOMEM;
                goto error;
        }
-       memset(cls, 0x00, sizeof(struct class));
 
        cls->name = name;
        cls->owner = owner;
@@ -500,13 +499,13 @@ int class_device_add(struct class_device *class_dev)
        /* add the needed attributes to this device */
        if (MAJOR(class_dev->devt)) {
                struct class_device_attribute *attr;
-               attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+               attr = kzalloc(sizeof(*attr), GFP_KERNEL);
                if (!attr) {
                        error = -ENOMEM;
                        kobject_del(&class_dev->kobj);
                        goto register_done;
                }
-               memset(attr, sizeof(*attr), 0x00);
+
                attr->attr.name = "dev";
                attr->attr.mode = S_IRUGO;
                attr->attr.owner = parent->owner;
@@ -577,12 +576,11 @@ struct class_device *class_device_create(struct class *cls, dev_t devt,
        if (cls == NULL || IS_ERR(cls))
                goto error;
 
-       class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL);
+       class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
        if (!class_dev) {
                retval = -ENOMEM;
                goto error;
        }
-       memset(class_dev, 0x00, sizeof(struct class_device));
 
        class_dev->devt = devt;
        class_dev->dev = device;
index 5bfa2e9a7c2678efade79213aa5bd203054613b8..4acb2c5733c3b46710d6321b886d16b8704f1d1c 100644 (file)
@@ -301,9 +301,9 @@ fw_register_class_device(struct class_device **class_dev_p,
                         const char *fw_name, struct device *device)
 {
        int retval;
-       struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
+       struct firmware_priv *fw_priv = kzalloc(sizeof(*fw_priv),
                                                GFP_KERNEL);
-       struct class_device *class_dev = kmalloc(sizeof (struct class_device),
+       struct class_device *class_dev = kzalloc(sizeof(*class_dev),
                                                 GFP_KERNEL);
 
        *class_dev_p = NULL;
@@ -313,8 +313,6 @@ fw_register_class_device(struct class_device **class_dev_p,
                retval = -ENOMEM;
                goto error_kfree;
        }
-       memset(fw_priv, 0, sizeof (*fw_priv));
-       memset(class_dev, 0, sizeof (*class_dev));
 
        init_completion(&fw_priv->completion);
        fw_priv->attr_data = firmware_attr_data_tmpl;
@@ -402,14 +400,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
        if (!firmware_p)
                return -EINVAL;
 
-       *firmware_p = firmware = kmalloc(sizeof (struct firmware), GFP_KERNEL);
+       *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
        if (!firmware) {
                printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
                       __FUNCTION__);
                retval = -ENOMEM;
                goto out;
        }
-       memset(firmware, 0, sizeof (*firmware));
 
        retval = fw_setup_class_device(firmware, &class_dev, name, device,
                hotplug);
index 2f455d86793c8bde34098fae2deb80a17e54238d..b449dae6f0d30fcb8385ce68c1f9bdfd34f6ff64 100644 (file)
@@ -135,7 +135,7 @@ retry:
 struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
 {
        struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
-       struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL);
+       struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
        int i;
 
        if ((p == NULL) || (base == NULL)) {
@@ -144,7 +144,6 @@ struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem)
                return NULL;
        }
 
-       memset(base, 0, sizeof(struct probe));
        base->dev = 1;
        base->range = ~0;
        base->get = base_probe;
index 3a5f4c991797a02eb0de0ecaac726076d88281f9..361e204209ebb3c8324599aecf0716766d1b20c1 100644 (file)
@@ -225,13 +225,12 @@ struct platform_device *platform_device_register_simple(char *name, unsigned int
        struct platform_object *pobj;
        int retval;
 
-       pobj = kmalloc(sizeof(struct platform_object) + sizeof(struct resource) * num, GFP_KERNEL);
+       pobj = kzalloc(sizeof(*pobj) + sizeof(struct resource) * num, GFP_KERNEL);
        if (!pobj) {
                retval = -ENOMEM;
                goto error;
        }
 
-       memset(pobj, 0, sizeof(*pobj));
        pobj->pdev.name = name;
        pobj->pdev.id = id;
        pobj->pdev.dev.release = platform_device_release_simple;
index 28f2c177a54167a0ce7d3bd9e3f1dbe7ac1d7995..c56f995aadadcee00d8a63982ccf0a16da20c97a 100644 (file)
 #include <linux/completion.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 2.6.6)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,6)
+#define DRIVER_NAME "HP CISS Driver (v 2.6.8)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,8)
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Hewlett-Packard Company");
-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
+MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.8");
 MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
-                       " SA6i P600 P800 E400 E300");
+                       " SA6i P600 P800 P400 P400i E200 E200i");
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -83,12 +83,22 @@ static const struct pci_device_id cciss_pci_device_id[] = {
                0x0E11, 0x4091, 0, 0, 0},
        { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA,
                0x103C, 0x3225, 0, 0, 0},
-       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
                0x103c, 0x3223, 0, 0, 0},
        { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
-               0x103c, 0x3231, 0, 0, 0},
+               0x103c, 0x3234, 0, 0, 0},
        { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
-               0x103c, 0x3233, 0, 0, 0},
+               0x103c, 0x3235, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+               0x103c, 0x3211, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+               0x103c, 0x3212, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+               0x103c, 0x3213, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+               0x103c, 0x3214, 0, 0, 0},
+       { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
+               0x103c, 0x3215, 0, 0, 0},
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -111,8 +121,13 @@ static struct board_type products[] = {
        { 0x40910E11, "Smart Array 6i", &SA5_access},
        { 0x3225103C, "Smart Array P600", &SA5_access},
        { 0x3223103C, "Smart Array P800", &SA5_access},
-       { 0x3231103C, "Smart Array E400", &SA5_access},
-       { 0x3233103C, "Smart Array E300", &SA5_access},
+       { 0x3234103C, "Smart Array P400", &SA5_access},
+       { 0x3235103C, "Smart Array P400i", &SA5_access},
+       { 0x3211103C, "Smart Array E200i", &SA5_access},
+       { 0x3212103C, "Smart Array E200", &SA5_access},
+       { 0x3213103C, "Smart Array E200i", &SA5_access},
+       { 0x3214103C, "Smart Array E200i", &SA5_access},
+       { 0x3215103C, "Smart Array E200i", &SA5_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
@@ -140,15 +155,26 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 
 static int revalidate_allvol(ctlr_info_t *host);
 static int cciss_revalidate(struct gendisk *disk);
-static int deregister_disk(struct gendisk *disk);
-static int register_new_disk(ctlr_info_t *h);
+static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk);
+static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all);
 
+static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
+       int withirq, unsigned int *total_size, unsigned int *block_size);
+static void cciss_geometry_inquiry(int ctlr, int logvol,
+                       int withirq, unsigned int total_size,
+                       unsigned int block_size, InquiryData_struct *inq_buff,
+                       drive_info_struct *drv);
 static void cciss_getgeometry(int cntl_num);
 
 static void start_io( ctlr_info_t *h);
 static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
        unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
        unsigned char *scsi3addr, int cmd_type);
+static int sendcmd_withirq(__u8        cmd, int ctlr, void *buff, size_t size,
+       unsigned int use_unit_num, unsigned int log_unit, __u8  page_code,
+       int cmd_type);
+
+static void fail_all_cmds(unsigned long ctlr);
 
 #ifdef CONFIG_PROC_FS
 static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
@@ -265,7 +291,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
        for(i=0; i<=h->highest_lun; i++) {
 
                 drv = &h->drv[i];
-               if (drv->block_size == 0)
+               if (drv->heads == 0)
                        continue;
 
                vol_sz = drv->nr_blocks;
@@ -363,6 +389,8 @@ static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
                        return NULL;
                memset(c, 0, sizeof(CommandList_struct));
 
+               c->cmdindex = -1;
+
                c->err_info = (ErrorInfo_struct *)pci_alloc_consistent(
                                        h->pdev, sizeof(ErrorInfo_struct), 
                                        &err_dma_handle);
@@ -393,6 +421,8 @@ static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
                err_dma_handle = h->errinfo_pool_dhandle 
                                        + i*sizeof(ErrorInfo_struct);
                 h->nr_allocs++;
+
+               c->cmdindex = i;
         }
 
        c->busaddr = (__u32) cmd_dma_handle;
@@ -453,6 +483,11 @@ static int cciss_open(struct inode *inode, struct file *filep)
        printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name);
 #endif /* CCISS_DEBUG */ 
 
+       if (host->busy_initializing)
+               return -EBUSY;
+
+       if (host->busy_initializing || drv->busy_configuring)
+               return -EBUSY;
        /*
         * Root is allowed to open raw volume zero even if it's not configured
         * so array config can still work. Root is also allowed to open any
@@ -796,10 +831,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
                return(0);
        }
        case CCISS_DEREGDISK:
-               return deregister_disk(disk);
+               return rebuild_lun_table(host, disk);
 
        case CCISS_REGNEWD:
-               return register_new_disk(host);
+               return rebuild_lun_table(host, NULL);
 
        case CCISS_PASSTHRU:
        {
@@ -1143,48 +1178,323 @@ static int revalidate_allvol(ctlr_info_t *host)
         return 0;
 }
 
-static int deregister_disk(struct gendisk *disk)
+/* This function will check the usage_count of the drive to be updated/added.
+ * If the usage_count is zero then the drive information will be updated and
+ * the disk will be re-registered with the kernel.  If not then it will be
+ * left alone for the next reboot.  The exception to this is disk 0 which
+ * will always be left registered with the kernel since it is also the
+ * controller node.  Any changes to disk 0 will show up on the next
+ * reboot.
+*/
+static void cciss_update_drive_info(int ctlr, int drv_index)
+  {
+       ctlr_info_t *h = hba[ctlr];
+       struct gendisk *disk;
+       ReadCapdata_struct *size_buff = NULL;
+       InquiryData_struct *inq_buff = NULL;
+       unsigned int block_size;
+       unsigned int total_size;
+       unsigned long flags = 0;
+       int ret = 0;
+
+       /* if the disk already exists then deregister it before proceeding*/
+       if (h->drv[drv_index].raid_level != -1){
+               spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+               h->drv[drv_index].busy_configuring = 1;
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               ret = deregister_disk(h->gendisk[drv_index],
+                       &h->drv[drv_index], 0);
+               h->drv[drv_index].busy_configuring = 0;
+       }
+
+       /* If the disk is in use return */
+       if (ret)
+               return;
+
+
+       /* Get information about the disk and modify the driver sturcture */
+       size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+        if (size_buff == NULL)
+               goto mem_msg;
+       inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+       if (inq_buff == NULL)
+               goto mem_msg;
+
+       cciss_read_capacity(ctlr, drv_index, size_buff, 1,
+               &total_size, &block_size);
+       cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
+               inq_buff, &h->drv[drv_index]);
+
+       ++h->num_luns;
+       disk = h->gendisk[drv_index];
+       set_capacity(disk, h->drv[drv_index].nr_blocks);
+
+
+       /* if it's the controller it's already added */
+       if (drv_index){
+               disk->queue = blk_init_queue(do_cciss_request, &h->lock);
+
+               /* Set up queue information */
+               disk->queue->backing_dev_info.ra_pages = READ_AHEAD;
+               blk_queue_bounce_limit(disk->queue, hba[ctlr]->pdev->dma_mask);
+
+               /* This is a hardware imposed limit. */
+               blk_queue_max_hw_segments(disk->queue, MAXSGENTRIES);
+
+               /* This is a limit in the driver and could be eliminated. */
+               blk_queue_max_phys_segments(disk->queue, MAXSGENTRIES);
+
+               blk_queue_max_sectors(disk->queue, 512);
+
+               disk->queue->queuedata = hba[ctlr];
+
+               blk_queue_hardsect_size(disk->queue,
+                       hba[ctlr]->drv[drv_index].block_size);
+
+               h->drv[drv_index].queue = disk->queue;
+               add_disk(disk);
+       }
+
+freeret:
+       kfree(size_buff);
+       kfree(inq_buff);
+       return;
+mem_msg:
+       printk(KERN_ERR "cciss: out of memory\n");
+       goto freeret;
+}
+
+/* This function will find the first index of the controllers drive array
+ * that has a -1 for the raid_level and will return that index.  This is
+ * where new drives will be added.  If the index to be returned is greater
+ * than the highest_lun index for the controller then highest_lun is set
+ * to this new index.  If there are no available indexes then -1 is returned.
+*/
+static int cciss_find_free_drive_index(int ctlr)
 {
+       int i;
+
+       for (i=0; i < CISS_MAX_LUN; i++){
+               if (hba[ctlr]->drv[i].raid_level == -1){
+                       if (i > hba[ctlr]->highest_lun)
+                               hba[ctlr]->highest_lun = i;
+                       return i;
+               }
+       }
+       return -1;
+}
+
+/* This function will add and remove logical drives from the Logical
+ * drive array of the controller and maintain persistancy of ordering
+ * so that mount points are preserved until the next reboot.  This allows
+ * for the removal of logical drives in the middle of the drive array
+ * without a re-ordering of those drives.
+ * INPUT
+ * h           = The controller to perform the operations on
+ * del_disk    = The disk to remove if specified.  If the value given
+ *               is NULL then no disk is removed.
+*/
+static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
+{
+       int ctlr = h->ctlr;
+       int num_luns;
+       ReportLunData_struct *ld_buff = NULL;
+       drive_info_struct *drv = NULL;
+       int return_code;
+       int listlength = 0;
+       int i;
+       int drv_found;
+       int drv_index = 0;
+       __u32 lunid = 0;
        unsigned long flags;
+
+       /* Set busy_configuring flag for this operation */
+       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       if (h->num_luns >= CISS_MAX_LUN){
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               return -EINVAL;
+       }
+
+       if (h->busy_configuring){
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               return -EBUSY;
+       }
+       h->busy_configuring = 1;
+
+       /* if del_disk is NULL then we are being called to add a new disk
+        * and update the logical drive table.  If it is not NULL then
+        * we will check if the disk is in use or not.
+        */
+       if (del_disk != NULL){
+               drv = get_drv(del_disk);
+               drv->busy_configuring = 1;
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               return_code = deregister_disk(del_disk, drv, 1);
+               drv->busy_configuring = 0;
+               h->busy_configuring = 0;
+               return return_code;
+       } else {
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               if (!capable(CAP_SYS_RAWIO))
+                       return -EPERM;
+
+               ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+               if (ld_buff == NULL)
+                       goto mem_msg;
+
+               return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
+                               sizeof(ReportLunData_struct), 0, 0, 0,
+                               TYPE_CMD);
+
+               if (return_code == IO_OK){
+                       listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+                       listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+                       listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
+                       listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+               } else{ /* reading number of logical volumes failed */
+                       printk(KERN_WARNING "cciss: report logical volume"
+                               " command failed\n");
+                       listlength = 0;
+                       goto freeret;
+               }
+
+               num_luns = listlength / 8;      /* 8 bytes per entry */
+               if (num_luns > CISS_MAX_LUN){
+                       num_luns = CISS_MAX_LUN;
+                       printk(KERN_WARNING "cciss: more luns configured"
+                               " on controller than can be handled by"
+                               " this driver.\n");
+               }
+
+               /* Compare controller drive array to drivers drive array.
+               * Check for updates in the drive information and any new drives
+               * on the controller.
+               */
+               for (i=0; i < num_luns; i++){
+                       int j;
+
+                       drv_found = 0;
+
+                       lunid = (0xff &
+                               (unsigned int)(ld_buff->LUN[i][3])) << 24;
+                       lunid |= (0xff &
+                               (unsigned int)(ld_buff->LUN[i][2])) << 16;
+                       lunid |= (0xff &
+                               (unsigned int)(ld_buff->LUN[i][1])) << 8;
+                       lunid |= 0xff &
+                               (unsigned int)(ld_buff->LUN[i][0]);
+
+                       /* Find if the LUN is already in the drive array
+                        * of the controller.  If so then update its info
+                        * if not is use.  If it does not exist then find
+                        * the first free index and add it.
+                       */
+                       for (j=0; j <= h->highest_lun; j++){
+                               if (h->drv[j].LunID == lunid){
+                                       drv_index = j;
+                                       drv_found = 1;
+                               }
+                       }
+
+                       /* check if the drive was found already in the array */
+                       if (!drv_found){
+                               drv_index = cciss_find_free_drive_index(ctlr);
+                               if (drv_index == -1)
+                                       goto freeret;
+
+                       }
+                       h->drv[drv_index].LunID = lunid;
+                       cciss_update_drive_info(ctlr, drv_index);
+               } /* end for */
+       } /* end else */
+
+freeret:
+       kfree(ld_buff);
+       h->busy_configuring = 0;
+       /* We return -1 here to tell the ACU that we have registered/updated
+        * all of the drives that we can and to keep it from calling us
+        * additional times.
+       */
+       return -1;
+mem_msg:
+       printk(KERN_ERR "cciss: out of memory\n");
+       goto freeret;
+}
+
+/* This function will deregister the disk and it's queue from the
+ * kernel.  It must be called with the controller lock held and the
+ * drv structures busy_configuring flag set.  It's parameters are:
+ *
+ * disk = This is the disk to be deregistered
+ * drv  = This is the drive_info_struct associated with the disk to be
+ *        deregistered.  It contains information about the disk used
+ *        by the driver.
+ * clear_all = This flag determines whether or not the disk information
+ *             is going to be completely cleared out and the highest_lun
+ *             reset.  Sometimes we want to clear out information about
+ *             the disk in preperation for re-adding it.  In this case
+ *             the highest_lun should be left unchanged and the LunID
+ *             should not be cleared.
+*/
+static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
+                          int clear_all)
+{
        ctlr_info_t *h = get_host(disk);
-       drive_info_struct *drv = get_drv(disk);
-       int ctlr = h->ctlr;
 
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
 
-       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
        /* make sure logical volume is NOT is use */
-       if( drv->usage_count > 1) {
-               spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+       if(clear_all || (h->gendisk[0] == disk)) {
+       if (drv->usage_count > 1)
                 return -EBUSY;
        }
-       drv->usage_count++;
-       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+        else
+               if( drv->usage_count > 0 )
+                       return -EBUSY;
 
-       /* invalidate the devices and deregister the disk */ 
-       if (disk->flags & GENHD_FL_UP)
+       /* invalidate the devices and deregister the disk.  If it is disk
+        * zero do not deregister it but just zero out it's values.  This
+        * allows us to delete disk zero but keep the controller registered.
+       */
+       if (h->gendisk[0] != disk){
+               if (disk->flags & GENHD_FL_UP){
+                       blk_cleanup_queue(disk->queue);
                del_gendisk(disk);
+                       drv->queue = NULL;
+               }
+       }
+
+       --h->num_luns;
+       /* zero out the disk size info */
+       drv->nr_blocks = 0;
+       drv->block_size = 0;
+       drv->heads = 0;
+       drv->sectors = 0;
+       drv->cylinders = 0;
+       drv->raid_level = -1;   /* This can be used as a flag variable to
+                                * indicate that this element of the drive
+                                * array is free.
+                               */
+
+       if (clear_all){
        /* check to see if it was the last disk */
        if (drv == h->drv + h->highest_lun) {
                /* if so, find the new hightest lun */
                int i, newhighest =-1;
                for(i=0; i<h->highest_lun; i++) {
                        /* if the disk has size > 0, it is available */
-                       if (h->drv[i].nr_blocks)
+                               if (h->drv[i].heads)
                                newhighest = i;
                }
                h->highest_lun = newhighest;
-                               
        }
-       --h->num_luns;
-       /* zero out the disk size info */ 
-       drv->nr_blocks = 0;
-       drv->block_size = 0;
-       drv->cylinders = 0;
+
        drv->LunID = 0;
+       }
        return(0);
 }
+
 static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
        size_t size,
        unsigned int use_unit_num, /* 0: address the controller,
@@ -1420,8 +1730,10 @@ case CMD_HARDWARE_ERR:
                }
        }       
        /* unlock the buffers from DMA */
+       buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
+       buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
        pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
-                       size, PCI_DMA_BIDIRECTIONAL);
+                       c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
        cmd_free(h, c, 0);
         return(return_status);
 
@@ -1495,164 +1807,6 @@ cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
        return;
 }
 
-static int register_new_disk(ctlr_info_t *h)
-{
-        struct gendisk *disk;
-       int ctlr = h->ctlr;
-        int i;
-       int num_luns;
-       int logvol;
-       int new_lun_found = 0;
-       int new_lun_index = 0;
-       int free_index_found = 0;
-       int free_index = 0;
-       ReportLunData_struct *ld_buff = NULL;
-       ReadCapdata_struct *size_buff = NULL;
-       InquiryData_struct *inq_buff = NULL;
-       int return_code;
-       int listlength = 0;
-       __u32 lunid = 0;
-       unsigned int block_size;
-       unsigned int total_size;
-
-        if (!capable(CAP_SYS_RAWIO))
-                return -EPERM;
-       /* if we have no space in our disk array left to add anything */
-       if(  h->num_luns >= CISS_MAX_LUN)
-               return -EINVAL;
-       
-       ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
-       if (ld_buff == NULL)
-               goto mem_msg;
-       memset(ld_buff, 0, sizeof(ReportLunData_struct));
-       size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
-               goto mem_msg;
-       inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
-        if (inq_buff == NULL)
-               goto mem_msg;
-       
-       return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, 
-                       sizeof(ReportLunData_struct), 0, 0, 0, TYPE_CMD);
-
-       if( return_code == IO_OK)
-       {
-               
-               // printk("LUN Data\n--------------------------\n");
-
-               listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
-               listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
-               listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;  
-               listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
-       } else /* reading number of logical volumes failed */
-       {
-               printk(KERN_WARNING "cciss: report logical volume"
-                       " command failed\n");
-               listlength = 0;
-               goto free_err;
-       }
-       num_luns = listlength / 8; // 8 bytes pre entry
-       if (num_luns > CISS_MAX_LUN)
-       {
-               num_luns = CISS_MAX_LUN;
-       }
-#ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
-               ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
-               ld_buff->LUNListLength[3],  num_luns);
-#endif 
-       for(i=0; i<  num_luns; i++)
-       {
-               int j;
-               int lunID_found = 0;
-
-               lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
-               lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
-               lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
-               lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
-               
-               /* check to see if this is a new lun */ 
-               for(j=0; j <= h->highest_lun; j++)
-               {
-#ifdef CCISS_DEBUG
-                       printk("Checking %d %x against %x\n", j,h->drv[j].LunID,
-                                               lunid);
-#endif /* CCISS_DEBUG */
-                       if (h->drv[j].LunID == lunid)
-                       {
-                               lunID_found = 1;
-                               break;
-                       }
-                       
-               }
-               if( lunID_found == 1)
-                       continue;
-               else
-               {       /* It is the new lun we have been looking for */
-#ifdef CCISS_DEBUG
-                       printk("new lun found at %d\n", i);
-#endif /* CCISS_DEBUG */
-                       new_lun_index = i;
-                       new_lun_found = 1;
-                       break;  
-               }
-        }
-        if (!new_lun_found)
-        {
-               printk(KERN_WARNING "cciss:  New Logical Volume not found\n");
-               goto free_err;
-        }
-        /* Now find the free index     */
-       for(i=0; i <CISS_MAX_LUN; i++)
-       {
-#ifdef CCISS_DEBUG
-               printk("Checking Index %d\n", i);
-#endif /* CCISS_DEBUG */
-               if(h->drv[i].LunID == 0)
-               {
-#ifdef CCISS_DEBUG
-                       printk("free index found at %d\n", i);
-#endif /* CCISS_DEBUG */
-                       free_index_found = 1;
-                       free_index = i;
-                       break;
-               }
-       }
-       if (!free_index_found)
-       {
-               printk(KERN_WARNING "cciss: unable to find free slot for disk\n");
-               goto free_err;
-         }
-
-       logvol = free_index;
-       h->drv[logvol].LunID = lunid;
-               /* there could be gaps in lun numbers, track hightest */
-       if(h->highest_lun < lunid)
-               h->highest_lun = logvol;
-       cciss_read_capacity(ctlr, logvol, size_buff, 1,
-               &total_size, &block_size);
-       cciss_geometry_inquiry(ctlr, logvol, 1, total_size, block_size,
-                       inq_buff, &h->drv[logvol]);
-       h->drv[logvol].usage_count = 0;
-       ++h->num_luns;
-       /* setup partitions per disk */
-        disk = h->gendisk[logvol];
-       set_capacity(disk, h->drv[logvol].nr_blocks);
-       /* if it's the controller it's already added */
-       if(logvol)
-               add_disk(disk);
-freeret:
-       kfree(ld_buff);
-       kfree(size_buff);
-       kfree(inq_buff);
-       return (logvol);
-mem_msg:
-       printk(KERN_ERR "cciss: out of memory\n");
-free_err:
-       logvol = -1;
-       goto freeret;
-}
-
 static int cciss_revalidate(struct gendisk *disk)
 {
        ctlr_info_t *h = get_host(disk);
@@ -1859,8 +2013,10 @@ resend_cmd1:
                
 cleanup1:      
        /* unlock the data buffer from DMA */
+       buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
+       buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
        pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
-                               size, PCI_DMA_BIDIRECTIONAL);
+                               c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
        cmd_free(info_p, c, 1);
        return (status);
 } 
@@ -2111,7 +2267,11 @@ queue:
        /* fill in the request */ 
        drv = creq->rq_disk->private_data;
        c->Header.ReplyQueue = 0;  // unused in simple mode
-       c->Header.Tag.lower = c->busaddr;  // use the physical address the cmd block for tag
+       /* got command from pool, so use the command block index instead */
+       /* for direct lookups. */
+       /* The first 2 bits are reserved for controller error reporting. */
+       c->Header.Tag.lower = (c->cmdindex << 3);
+       c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
        c->Header.LUN.LogDev.VolId= drv->LunID;
        c->Header.LUN.LogDev.Mode = 1;
        c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
@@ -2186,7 +2346,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
        ctlr_info_t *h = dev_id;
        CommandList_struct *c;
        unsigned long flags;
-       __u32 a, a1;
+       __u32 a, a1, a2;
        int j;
        int start_queue = h->next_to_run;
 
@@ -2204,10 +2364,21 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                while((a = h->access.command_completed(h)) != FIFO_EMPTY) 
                {
                        a1 = a;
+                       if ((a & 0x04)) {
+                               a2 = (a >> 3);
+                               if (a2 >= NR_CMDS) {
+                                       printk(KERN_WARNING "cciss: controller cciss%d failed, stopping.\n", h->ctlr);
+                                       fail_all_cmds(h->ctlr);
+                                       return IRQ_HANDLED;
+                               }
+
+                               c = h->cmd_pool + a2;
+                               a = c->busaddr;
+
+                       } else {
                        a &= ~3;
-                       if ((c = h->cmpQ) == NULL)
-                       {  
-                               printk(KERN_WARNING "cciss: Completion of %08lx ignored\n", (unsigned long)a1);
+                               if ((c = h->cmpQ) == NULL) {
+                                       printk(KERN_WARNING "cciss: Completion of %08x ignored\n", a1);
                                continue;       
                        } 
                        while(c->busaddr != a) {
@@ -2215,6 +2386,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                                if (c == h->cmpQ) 
                                        break;
                        }
+                       }
                        /*
                         * If we've found the command, take it off the
                         * completion Q and free it
@@ -2634,12 +2806,16 @@ static void cciss_getgeometry(int cntl_num)
 #endif /* CCISS_DEBUG */
 
        hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
-       for(i=0; i<  hba[cntl_num]->num_luns; i++)
+//     for(i=0; i<  hba[cntl_num]->num_luns; i++)
+       for(i=0; i < CISS_MAX_LUN; i++)
        {
-
-               lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
-               lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
-               lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
+               if (i < hba[cntl_num]->num_luns){
+                       lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
+                                << 24;
+                       lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
+                                << 16;
+                       lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
+                                << 8;
                lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
                
                hba[cntl_num]->drv[i].LunID = lunid;
@@ -2647,13 +2823,18 @@ static void cciss_getgeometry(int cntl_num)
 
 #ifdef CCISS_DEBUG
                printk(KERN_DEBUG "LUN[%d]:  %x %x %x %x = %x\n", i, 
-               ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], 
-               ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID);
+                       ld_buff->LUN[i][0], ld_buff->LUN[i][1],
+                       ld_buff->LUN[i][2], ld_buff->LUN[i][3],
+                       hba[cntl_num]->drv[i].LunID);
 #endif /* CCISS_DEBUG */
                cciss_read_capacity(cntl_num, i, size_buff, 0,
                        &total_size, &block_size);
-               cciss_geometry_inquiry(cntl_num, i, 0, total_size, block_size,
-                       inq_buff, &hba[cntl_num]->drv[i]);
+                       cciss_geometry_inquiry(cntl_num, i, 0, total_size,
+                               block_size, inq_buff, &hba[cntl_num]->drv[i]);
+               } else {
+                       /* initialize raid_level to indicate a free space */
+                       hba[cntl_num]->drv[i].raid_level = -1;
+               }
        }
        kfree(ld_buff);
        kfree(size_buff);
@@ -2727,6 +2908,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        i = alloc_cciss_hba();
        if(i < 0)
                return (-1);
+
+       hba[i]->busy_initializing = 1;
+
        if (cciss_pci_init(hba[i], pdev) != 0)
                goto clean1;
 
@@ -2849,6 +3033,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                add_disk(disk);
        }
 
+       hba[i]->busy_initializing = 0;
        return(1);
 
 clean4:
@@ -2869,6 +3054,7 @@ clean2:
 clean1:
        release_io_mem(hba[i]);
        free_hba(i);
+       hba[i]->busy_initializing = 0;
        return(-1);
 }
 
@@ -2913,9 +3099,10 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
        /* remove it from the disk list */
        for (j = 0; j < NWD; j++) {
                struct gendisk *disk = hba[i]->gendisk[j];
-               if (disk->flags & GENHD_FL_UP)
-                       blk_cleanup_queue(disk->queue);
+               if (disk->flags & GENHD_FL_UP) {
                        del_gendisk(disk);
+                       blk_cleanup_queue(disk->queue);
+               }
        }
 
        pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
@@ -2964,5 +3151,43 @@ static void __exit cciss_cleanup(void)
        remove_proc_entry("cciss", proc_root_driver);
 }
 
+static void fail_all_cmds(unsigned long ctlr)
+{
+       /* If we get here, the board is apparently dead. */
+       ctlr_info_t *h = hba[ctlr];
+       CommandList_struct *c;
+       unsigned long flags;
+
+       printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
+       h->alive = 0;   /* the controller apparently died... */
+
+       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+
+       pci_disable_device(h->pdev); /* Make sure it is really dead. */
+
+       /* move everything off the request queue onto the completed queue */
+       while( (c = h->reqQ) != NULL ) {
+               removeQ(&(h->reqQ), c);
+               h->Qdepth--;
+               addQ (&(h->cmpQ), c);
+       }
+
+       /* Now, fail everything on the completed queue with a HW error */
+       while( (c = h->cmpQ) != NULL ) {
+               removeQ(&h->cmpQ, c);
+               c->err_info->CommandStatus = CMD_HARDWARE_ERR;
+               if (c->cmd_type == CMD_RWREQ) {
+                       complete_command(h, c, 0);
+               } else if (c->cmd_type == CMD_IOCTL_PEND)
+                       complete(c->waiting);
+#ifdef CONFIG_CISS_SCSI_TAPE
+                       else if (c->cmd_type == CMD_SCSI)
+                               complete_scsi_command(c, 0, 0);
+#endif
+       }
+       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+       return;
+}
+
 module_init(cciss_init);
 module_exit(cciss_cleanup);
index 566587d0a5003726dc75e5fe7ea67ad639581c54..ef277baee9fdc565834a04dda71f1da3014bba72 100644 (file)
@@ -35,7 +35,13 @@ typedef struct _drive_info_struct
        int     heads;
        int     sectors;
        int     cylinders;
-       int     raid_level;
+       int     raid_level; /* set to -1 to indicate that
+                            * the drive is not in use/configured
+                           */
+       int     busy_configuring; /*This is set when the drive is being removed
+                                  *to prevent it from being opened or it's queue
+                                  *from being started.
+                                 */
 } drive_info_struct;
 
 struct ctlr_info 
@@ -83,6 +89,7 @@ struct ctlr_info
        int                     nr_allocs;
        int                     nr_frees; 
        int                     busy_configuring;
+       int                     busy_initializing;
 
        /* This element holds the zero based queue number of the last
         * queue to be started.  It is used for fairness.
@@ -94,6 +101,7 @@ struct ctlr_info
 #ifdef CONFIG_CISS_SCSI_TAPE
        void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
 #endif
+       unsigned char alive;
 };
 
 /*  Defining the diffent access_menthods */
index a88a88817623fb34b230141eba5f0ae7d068c95b..53fea549ba8b23a6714cfd8a33fc55705893986e 100644 (file)
@@ -226,6 +226,10 @@ typedef struct _ErrorInfo_struct {
 #define CMD_MSG_DONE   0x04
 #define CMD_MSG_TIMEOUT 0x05
 
+/* This structure needs to be divisible by 8 for new
+ * indexing method.
+ */
+#define PADSIZE (sizeof(long) - 4)
 typedef struct _CommandList_struct {
   CommandListHeader_struct Header;
   RequestBlock_struct      Request;
@@ -236,14 +240,14 @@ typedef struct _CommandList_struct {
   ErrorInfo_struct *      err_info; /* pointer to the allocated mem */ 
   int                     ctlr;
   int                     cmd_type; 
+  long                    cmdindex;
   struct _CommandList_struct *prev;
   struct _CommandList_struct *next;
   struct request *        rq;
   struct completion *waiting;
   int   retry_count;
-#ifdef CONFIG_CISS_SCSI_TAPE
   void * scsi_cmd;
-#endif
+  char   pad[PADSIZE];
 } CommandList_struct;
 
 //Configuration Table Structure
index f16e3caed58a36129ff7046531607ea6cfb07fa3..e183a3ef7839fdabd5dfc8a2ec9d1f1fa11d94db 100644 (file)
@@ -93,6 +93,7 @@ struct cciss_scsi_cmd_stack_elem_t {
        CommandList_struct cmd;
        ErrorInfo_struct Err;
        __u32 busaddr;
+       __u32 pad;
 };
 
 #pragma pack()
@@ -877,7 +878,7 @@ cciss_scsi_interpret_error(CommandList_struct *cp)
 
 static int
 cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, 
-                InquiryData_struct *buf)
+                unsigned char *buf, unsigned char bufsize)
 {
        int rc;
        CommandList_struct *cp;
@@ -900,11 +901,10 @@ cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr,
        cdb[1] = 0;
        cdb[2] = 0;
        cdb[3] = 0;
-       cdb[4] = sizeof(*buf) & 0xff;
+       cdb[4] = bufsize;
        cdb[5] = 0;
        rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb, 
-                               6, (unsigned char *) buf, 
-                               sizeof(*buf), XFER_READ);
+                               6, buf, bufsize, XFER_READ);
 
        if (rc != 0) return rc; /* something went wrong */
 
@@ -1000,9 +1000,10 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
           that though.  
 
         */
-
+#define OBDR_TAPE_INQ_SIZE 49
+#define OBDR_TAPE_SIG "$DR-10"
        ReportLunData_struct *ld_buff;
-       InquiryData_struct *inq_buff;
+       unsigned char *inq_buff;
        unsigned char scsi3addr[8];
        ctlr_info_t *c;
        __u32 num_luns=0;
@@ -1020,7 +1021,7 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
                return;
        }
        memset(ld_buff, 0, reportlunsize);
-       inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+       inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
         if (inq_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
                 kfree(ld_buff);
@@ -1051,19 +1052,36 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
 
                /* for each physical lun, do an inquiry */
                if (ld_buff->LUN[i][3] & 0xC0) continue;
-               memset(inq_buff, 0, sizeof(InquiryData_struct));
+               memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE);
                memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);
 
-               if (cciss_scsi_do_inquiry(hba[cntl_num], 
-                       scsi3addr, inq_buff) != 0)
-               {
+               if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, inq_buff,
+                       (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
                        /* Inquiry failed (msg printed already) */
                        devtype = 0; /* so we will skip this device. */
                } else /* what kind of device is this? */
-                       devtype = (inq_buff->data_byte[0] & 0x1f);
+                       devtype = (inq_buff[0] & 0x1f);
 
                switch (devtype)
                {
+                 case 0x05: /* CD-ROM */ {
+
+                       /* We don't *really* support actual CD-ROM devices,
+                        * just this "One Button Disaster Recovery" tape drive
+                        * which temporarily pretends to be a CD-ROM drive.
+                        * So we check that the device is really an OBDR tape
+                        * device by checking for "$DR-10" in bytes 43-48 of
+                        * the inquiry data.
+                        */
+                               char obdr_sig[7];
+
+                               strncpy(obdr_sig, &inq_buff[43], 6);
+                               obdr_sig[6] = '\0';
+                               if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0)
+                                       /* Not OBDR device, ignore it. */
+                                       break;
+                       }
+                       /* fall through . . . */
                  case 0x01: /* sequential access, (tape) */
                  case 0x08: /* medium changer */
                        if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
@@ -1126,6 +1144,7 @@ cciss_scsi_proc_info(struct Scsi_Host *sh,
 
        int buflen, datalen;
        ctlr_info_t *ci;
+       int i;
        int cntl_num;
 
 
@@ -1136,8 +1155,28 @@ cciss_scsi_proc_info(struct Scsi_Host *sh,
        cntl_num = ci->ctlr;    /* Get our index into the hba[] array */
 
        if (func == 0) {        /* User is reading from /proc/scsi/ciss*?/?*  */
-               buflen = sprintf(buffer, "hostnum=%d\n", sh->host_no);  
-
+               buflen = sprintf(buffer, "cciss%d: SCSI host: %d\n",
+                               cntl_num, sh->host_no);
+
+               /* this information is needed by apps to know which cciss
+                  device corresponds to which scsi host number without
+                  having to open a scsi target device node.  The device
+                  information is not a duplicate of /proc/scsi/scsi because
+                  the two may be out of sync due to scsi hotplug, rather
+                  this info is for an app to be able to use to know how to
+                  get them back in sync. */
+
+               for (i=0;i<ccissscsi[cntl_num].ndevices;i++) {
+                       struct cciss_scsi_dev_t *sd = &ccissscsi[cntl_num].dev[i];
+                       buflen += sprintf(&buffer[buflen], "c%db%dt%dl%d %02d "
+                               "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+                               sh->host_no, sd->bus, sd->target, sd->lun,
+                               sd->devtype,
+                               sd->scsi3addr[0], sd->scsi3addr[1],
+                               sd->scsi3addr[2], sd->scsi3addr[3],
+                               sd->scsi3addr[4], sd->scsi3addr[5],
+                               sd->scsi3addr[6], sd->scsi3addr[7]);
+               }
                datalen = buflen - offset;
                if (datalen < 0) {      /* they're reading past EOF. */
                        datalen = 0;
@@ -1399,7 +1438,7 @@ cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
 
        CPQ_TAPE_LOCK(ctlr, flags);
        size = sprintf(buffer + *len, 
-               "       Sequential access devices: %d\n\n",
+               "Sequential access devices: %d\n\n",
                        ccissscsi[ctlr].ndevices);
        CPQ_TAPE_UNLOCK(ctlr, flags);
        *pos += size; *len += size;
index 7b838342f0a353939324c228212074b15ea48c76..7e22a58926b8ed790636c62f1a036a4799391ee3 100644 (file)
@@ -5,29 +5,41 @@
  * May be copied or modified under the terms of the GNU General Public
  * License.  See linux/COPYING for more information.
  *
- * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and
- * DVD-RW devices (aka an exercise in block layer masturbation)
+ * Packet writing layer for ATAPI and SCSI CD-RW, DVD+RW, DVD-RW and
+ * DVD-RAM devices.
  *
+ * Theory of operation:
  *
- * TODO: (circa order of when I will fix it)
- * - Only able to write on CD-RW media right now.
- * - check host application code on media and set it in write page
- * - interface for UDF <-> packet to negotiate a new location when a write
- *   fails.
- * - handle OPC, especially for -RW media
+ * At the lowest level, there is the standard driver for the CD/DVD device,
+ * typically ide-cd.c or sr.c. This driver can handle read and write requests,
+ * but it doesn't know anything about the special restrictions that apply to
+ * packet writing. One restriction is that write requests must be aligned to
+ * packet boundaries on the physical media, and the size of a write request
+ * must be equal to the packet size. Another restriction is that a
+ * GPCMD_FLUSH_CACHE command has to be issued to the drive before a read
+ * command, if the previous command was a write.
  *
- * Theory of operation:
+ * The purpose of the packet writing driver is to hide these restrictions from
+ * higher layers, such as file systems, and present a block device that can be
+ * randomly read and written using 2kB-sized blocks.
+ *
+ * The lowest layer in the packet writing driver is the packet I/O scheduler.
+ * Its data is defined by the struct packet_iosched and includes two bio
+ * queues with pending read and write requests. These queues are processed
+ * by the pkt_iosched_process_queue() function. The write requests in this
+ * queue are already properly aligned and sized. This layer is responsible for
+ * issuing the flush cache commands and scheduling the I/O in a good order.
  *
- * We use a custom make_request_fn function that forwards reads directly to
- * the underlying CD device. Write requests are either attached directly to
- * a live packet_data object, or simply stored sequentially in a list for
- * later processing by the kcdrwd kernel thread. This driver doesn't use
- * any elevator functionally as defined by the elevator_s struct, but the
- * underlying CD device uses a standard elevator.
+ * The next layer transforms unaligned write requests to aligned writes. This
+ * transformation requires reading missing pieces of data from the underlying
+ * block device, assembling the pieces to full packets and queuing them to the
+ * packet I/O scheduler.
  *
- * This strategy makes it possible to do very late merging of IO requests.
- * A new bio sent to pkt_make_request can be merged with a live packet_data
- * object even if the object is in the data gathering state.
+ * At the top layer there is a custom make_request_fn function that forwards
+ * read requests directly to the iosched queue and puts write requests in the
+ * unaligned write queue. A kernel thread performs the necessary read
+ * gathering to convert the unaligned writes to aligned writes and then feeds
+ * them to the packet I/O scheduler.
  *
  *************************************************************************/
 
@@ -100,10 +112,9 @@ static struct bio *pkt_bio_alloc(int nr_iovecs)
                goto no_bio;
        bio_init(bio);
 
-       bvl = kmalloc(nr_iovecs * sizeof(struct bio_vec), GFP_KERNEL);
+       bvl = kcalloc(nr_iovecs, sizeof(struct bio_vec), GFP_KERNEL);
        if (!bvl)
                goto no_bvl;
-       memset(bvl, 0, nr_iovecs * sizeof(struct bio_vec));
 
        bio->bi_max_vecs = nr_iovecs;
        bio->bi_io_vec = bvl;
@@ -125,10 +136,9 @@ static struct packet_data *pkt_alloc_packet_data(void)
        int i;
        struct packet_data *pkt;
 
-       pkt = kmalloc(sizeof(struct packet_data), GFP_KERNEL);
+       pkt = kzalloc(sizeof(struct packet_data), GFP_KERNEL);
        if (!pkt)
                goto no_pkt;
-       memset(pkt, 0, sizeof(struct packet_data));
 
        pkt->w_bio = pkt_bio_alloc(PACKET_MAX_SIZE);
        if (!pkt->w_bio)
@@ -659,7 +669,6 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct page **pages, in
                }
                offs += CD_FRAMESIZE;
                if (offs >= PAGE_SIZE) {
-                       BUG_ON(offs > PAGE_SIZE);
                        offs = 0;
                        p++;
                }
@@ -724,12 +733,6 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
        atomic_set(&pkt->io_wait, 0);
        atomic_set(&pkt->io_errors, 0);
 
-       if (pkt->cache_valid) {
-               VPRINTK("pkt_gather_data: zone %llx cached\n",
-                       (unsigned long long)pkt->sector);
-               goto out_account;
-       }
-
        /*
         * Figure out which frames we need to read before we can write.
         */
@@ -738,6 +741,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
        for (bio = pkt->orig_bios; bio; bio = bio->bi_next) {
                int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
                int num_frames = bio->bi_size / CD_FRAMESIZE;
+               pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9);
                BUG_ON(first_frame < 0);
                BUG_ON(first_frame + num_frames > pkt->frames);
                for (f = first_frame; f < first_frame + num_frames; f++)
@@ -745,6 +749,12 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
        }
        spin_unlock(&pkt->lock);
 
+       if (pkt->cache_valid) {
+               VPRINTK("pkt_gather_data: zone %llx cached\n",
+                       (unsigned long long)pkt->sector);
+               goto out_account;
+       }
+
        /*
         * Schedule reads for missing parts of the packet.
         */
@@ -778,7 +788,6 @@ out_account:
                frames_read, (unsigned long long)pkt->sector);
        pd->stats.pkt_started++;
        pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9);
-       pd->stats.secs_w += pd->settings.size;
 }
 
 /*
@@ -794,10 +803,11 @@ static struct packet_data *pkt_get_packet_data(struct pktcdvd_device *pd, int zo
                        list_del_init(&pkt->list);
                        if (pkt->sector != zone)
                                pkt->cache_valid = 0;
-                       break;
+                       return pkt;
                }
        }
-       return pkt;
+       BUG();
+       return NULL;
 }
 
 static void pkt_put_packet_data(struct pktcdvd_device *pd, struct packet_data *pkt)
@@ -941,12 +951,10 @@ try_next_bio:
        }
 
        pkt = pkt_get_packet_data(pd, zone);
-       BUG_ON(!pkt);
 
        pd->current_sector = zone + pd->settings.size;
        pkt->sector = zone;
        pkt->frames = pd->settings.size >> 2;
-       BUG_ON(pkt->frames > PACKET_MAX_SIZE);
        pkt->write_size = 0;
 
        /*
@@ -1636,6 +1644,10 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
                printk("pktcdvd: detected zero packet size!\n");
                pd->settings.size = 128;
        }
+       if (pd->settings.size > PACKET_MAX_SECTORS) {
+               printk("pktcdvd: packet size is too big\n");
+               return -ENXIO;
+       }
        pd->settings.fp = ti.fp;
        pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1);
 
@@ -2198,7 +2210,6 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio)
         * No matching packet found. Store the bio in the work queue.
         */
        node = mempool_alloc(pd->rb_pool, GFP_NOIO);
-       BUG_ON(!node);
        node->bio = bio;
        spin_lock(&pd->lock);
        BUG_ON(pd->bio_queue_size < 0);
@@ -2406,7 +2417,6 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
        struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data;
 
        VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode));
-       BUG_ON(!pd);
 
        switch (cmd) {
        /*
@@ -2477,10 +2487,9 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
                return -EBUSY;
        }
 
-       pd = kmalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
+       pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL);
        if (!pd)
                return ret;
-       memset(pd, 0, sizeof(struct pktcdvd_device));
 
        pd->rb_pool = mempool_create(PKT_RB_POOL_SIZE, pkt_rb_alloc, pkt_rb_free, NULL);
        if (!pd->rb_pool)
index 67d96b5cbb96535568bb26f28595d75e1b869e6d..57c48bbf6fe6766117b5362c7c8aebd38a09b3a2 100644 (file)
 #endif
 
 static int ignore = 0;
+static int ignore_csr = 0;
+static int ignore_sniffer = 0;
 static int reset = 0;
 
 #ifdef CONFIG_BT_HCIUSB_SCO
 static int isoc = 2;
 #endif
 
-#define VERSION "2.8"
+#define VERSION "2.9"
 
 static struct usb_driver hci_usb_driver; 
 
@@ -98,6 +100,9 @@ static struct usb_device_id bluetooth_ids[] = {
 MODULE_DEVICE_TABLE (usb, bluetooth_ids);
 
 static struct usb_device_id blacklist_ids[] = {
+       /* CSR BlueCore devices */
+       { USB_DEVICE(0x0a12, 0x0001), .driver_info = HCI_CSR },
+
        /* Broadcom BCM2033 without firmware */
        { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
 
@@ -836,6 +841,12 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
        if (ignore || id->driver_info & HCI_IGNORE)
                return -ENODEV;
 
+       if (ignore_csr && id->driver_info & HCI_CSR)
+               return -ENODEV;
+
+       if (ignore_sniffer && id->driver_info & HCI_SNIFFER)
+               return -ENODEV;
+
        if (intf->cur_altsetting->desc.bInterfaceNumber > 0)
                return -ENODEV;
 
@@ -1061,6 +1072,12 @@ module_exit(hci_usb_exit);
 module_param(ignore, bool, 0644);
 MODULE_PARM_DESC(ignore, "Ignore devices from the matching table");
 
+module_param(ignore_csr, bool, 0644);
+MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001");
+
+module_param(ignore_sniffer, bool, 0644);
+MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002");
+
 module_param(reset, bool, 0644);
 MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
 
index 29936b43d4f861e84e4799eccf92d10e45fe936b..37100a6ea1a895a0b7a020550d590aef5bdff382 100644 (file)
 #define HCI_IGNORE             0x01
 #define HCI_RESET              0x02
 #define HCI_DIGIANSWER         0x04
-#define HCI_SNIFFER            0x08
-#define HCI_BROKEN_ISOC                0x10
+#define HCI_CSR                        0x08
+#define HCI_SNIFFER            0x10
 #define HCI_BCM92035           0x20
+#define HCI_BROKEN_ISOC                0x40
 
 #define HCI_MAX_IFACE_NUM      3
 
index 2a36561eec68dab6efc8e690167df7a78668f1eb..a124f8c5d062dd65b29775881f9b9c55a0d95a14 100644 (file)
@@ -2053,10 +2053,6 @@ static int __init rs_init(void)
        state->icount.rx = state->icount.tx = 0;
        state->icount.frame = state->icount.parity = 0;
        state->icount.overrun = state->icount.brk = 0;
-       /*
-       if(state->port && check_region(state->port,REGION_LENGTH(state)))
-         continue;
-       */
 
        printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n",
                       state->line);
index fa789ea36bbe3169490c02204e9e6209cd860eb9..344001b45af94b3caa8ac0cf83979e224bb61e96 100644 (file)
@@ -84,6 +84,17 @@ config 977_WATCHDOG
 
          Not sure? It's safe to say N.
 
+config IXP2000_WATCHDOG
+       tristate "IXP2000 Watchdog"
+       depends on WATCHDOG && ARCH_IXP2000
+       help
+         Say Y here if to include support for the watchdog timer
+         in the Intel IXP2000(2400, 2800, 2850) network processors.
+         This driver can be built as a module by choosing M. The module
+         will be called ixp2000_wdt.
+
+         Say N if you are unsure.
+
 config IXP4XX_WATCHDOG
        tristate "IXP4xx Watchdog"
        depends on WATCHDOG && ARCH_IXP4XX
@@ -100,17 +111,6 @@ config IXP4XX_WATCHDOG
 
          Say N if you are unsure.
 
-config IXP2000_WATCHDOG
-       tristate "IXP2000 Watchdog"
-       depends on WATCHDOG && ARCH_IXP2000
-       help
-         Say Y here if to include support for the watchdog timer
-         in the Intel IXP2000(2400, 2800, 2850) network processors.
-         This driver can be built as a module by choosing M. The module
-         will be called ixp2000_wdt.
-
-         Say N if you are unsure.
-
 config S3C2410_WATCHDOG
        tristate "S3C2410 Watchdog"
        depends on WATCHDOG && ARCH_S3C2410
@@ -233,6 +233,16 @@ config IB700_WDT
 
          Most people will say N.
 
+config IBMASR
+        tristate "IBM Automatic Server Restart"
+        depends on WATCHDOG && X86
+        help
+         This is the driver for the IBM Automatic Server Restart watchdog
+         timer builtin into some eServer xSeries machines.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ibmasr.
+
 config WAFER_WDT
        tristate "ICP Wafer 5823 Single Board Computer Watchdog"
        depends on WATCHDOG && X86
@@ -243,6 +253,16 @@ config WAFER_WDT
          To compile this driver as a module, choose M here: the
          module will be called wafer5823wdt.
 
+config I6300ESB_WDT
+       tristate "Intel 6300ESB Timer/Watchdog"
+       depends on WATCHDOG && X86 && PCI
+       ---help---
+         Hardware driver for the watchdog timer built into the Intel
+         6300ESB controller hub.
+
+         To compile this driver as a module, choose M here: the
+         module will be called i6300esb.
+
 config I8XX_TCO
        tristate "Intel i8xx TCO Timer/Watchdog"
        depends on WATCHDOG && (X86 || IA64) && PCI
@@ -298,6 +318,19 @@ config 60XX_WDT
          You can compile this driver directly into the kernel, or use
          it as a module.  The module will be called sbc60xxwdt.
 
+config SBC8360_WDT
+       tristate "SBC8360 Watchdog Timer"
+       depends on WATCHDOG && X86
+       ---help---
+
+         This is the driver for the hardware watchdog on the SBC8360 Single
+         Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com).
+
+         To compile this driver as a module, choose M here: the
+         module will be called sbc8360.ko.
+
+         Most people will say N.
+
 config CPU5_WDT
        tristate "SMA CPU5 Watchdog"
        depends on WATCHDOG && X86
@@ -336,6 +369,19 @@ config W83877F_WDT
 
          Most people will say N.
 
+config W83977F_WDT
+       tristate "W83977F (PCM-5335) Watchdog Timer"
+       depends on WATCHDOG && X86
+       ---help---
+         This is the driver for the hardware watchdog on the W83977F I/O chip
+         as used in AAEON's PCM-5335 SBC (and likely others).  This
+         watchdog simply watches your kernel to make sure it doesn't freeze,
+         and if it does, it reboots your computer after a certain amount of
+         time.
+
+         To compile this driver as a module, choose M here: the
+         module will be called w83977f_wdt.
+
 config MACHZ_WDT
        tristate "ZF MachZ Watchdog"
        depends on WATCHDOG && X86
@@ -355,6 +401,10 @@ config 8xx_WDT
        tristate "MPC8xx Watchdog Timer"
        depends on WATCHDOG && 8xx
 
+config MV64X60_WDT
+       tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
+       depends on WATCHDOG && MV64X60
+
 config BOOKE_WDT
        tristate "PowerPC Book-E Watchdog Timer"
        depends on WATCHDOG && (BOOKE || 4xx)
@@ -362,6 +412,17 @@ config BOOKE_WDT
          Please see Documentation/watchdog/watchdog-api.txt for
          more information.
 
+# PPC64 Architecture
+
+config WATCHDOG_RTAS
+       tristate "RTAS watchdog"
+       depends on WATCHDOG && PPC_RTAS
+       help
+         This driver adds watchdog support for the RTAS watchdog.
+
+          To compile this driver as a module, choose M here. The module
+         will be called wdrtas.
+
 # MIPS Architecture
 
 config INDYDOG
@@ -430,16 +491,6 @@ config WATCHDOG_RIO
          machines.  The watchdog timeout period is normally one minute but
          can be changed with a boot-time parameter.
 
-# ppc64 RTAS watchdog
-config WATCHDOG_RTAS
-       tristate "RTAS watchdog"
-       depends on WATCHDOG && PPC_RTAS
-       help
-         This driver adds watchdog support for the RTAS watchdog.
-
-          To compile this driver as a module, choose M here. The module
-         will be called wdrtas.
-
 #
 # ISA-based Watchdog Cards
 #
index bc6f5fe88c8c24f200c13a0caf38fc3c02d6344a..cfd0a39877102224f901856f805562ed4feb1b33 100644 (file)
@@ -39,22 +39,27 @@ obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
 obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
 obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
 obj-$(CONFIG_IB700_WDT) += ib700wdt.o
+obj-$(CONFIG_IBMASR) += ibmasr.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
+obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
 obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
 obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
+obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
 obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
 obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
+obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
 
 # PowerPC Architecture
 obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
+obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
 
 # PPC64 Architecture
 obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
-obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
 
 # MIPS Architecture
 obj-$(CONFIG_INDYDOG) += indydog.o
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c
new file mode 100644 (file)
index 0000000..93785f1
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ *     i6300esb:       Watchdog timer driver for Intel 6300ESB chipset
+ *
+ *     (c) Copyright 2004 Google Inc.
+ *     (c) Copyright 2005 David Härdeman <david@2gen.com>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *      based on i810-tco.c which is in turn based on softdog.c
+ *
+ *     The timer is implemented in the following I/O controller hubs:
+ *     (See the intel documentation on http://developer.intel.com.)
+ *     6300ESB chip : document number 300641-003
+ *
+ *  2004YYZZ Ross Biro
+ *     Initial version 0.01
+ *  2004YYZZ Ross Biro
+ *     Version 0.02
+ *  20050210 David Härdeman <david@2gen.com>
+ *      Ported driver to kernel 2.6
+ */
+
+/*
+ *      Includes, defines, variables, module parameters, ...
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* Module and version information */
+#define ESB_VERSION "0.03"
+#define ESB_MODULE_NAME "i6300ESB timer"
+#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
+#define PFX ESB_MODULE_NAME ": "
+
+/* PCI configuration registers */
+#define ESB_CONFIG_REG  0x60            /* Config register                   */
+#define ESB_LOCK_REG    0x68            /* WDT lock register                 */
+
+/* Memory mapped registers */
+#define ESB_TIMER1_REG  BASEADDR + 0x00 /* Timer1 value after each reset     */
+#define ESB_TIMER2_REG  BASEADDR + 0x04 /* Timer2 value after each reset     */
+#define ESB_GINTSR_REG  BASEADDR + 0x08 /* General Interrupt Status Register */
+#define ESB_RELOAD_REG  BASEADDR + 0x0c /* Reload register                   */
+
+/* Lock register bits */
+#define ESB_WDT_FUNC    ( 0x01 << 2 )   /* Watchdog functionality            */
+#define ESB_WDT_ENABLE  ( 0x01 << 1 )   /* Enable WDT                        */
+#define ESB_WDT_LOCK    ( 0x01 << 0 )   /* Lock (nowayout)                   */
+
+/* Config register bits */
+#define ESB_WDT_REBOOT  ( 0x01 << 5 )   /* Enable reboot on timeout          */
+#define ESB_WDT_FREQ    ( 0x01 << 2 )   /* Decrement frequency               */
+#define ESB_WDT_INTTYPE ( 0x11 << 0 )   /* Interrupt type on timer1 timeout  */
+
+/* Reload register bits */
+#define ESB_WDT_RELOAD ( 0x01 << 8 )    /* prevent timeout                   */
+
+/* Magic constants */
+#define ESB_UNLOCK1     0x80            /* Step 1 to unlock reset registers  */
+#define ESB_UNLOCK2     0x86            /* Step 2 to unlock reset registers  */
+
+/* internal variables */
+static void __iomem *BASEADDR;
+static spinlock_t esb_lock; /* Guards the hardware */
+static unsigned long timer_alive;
+static struct pci_dev *esb_pci;
+static unsigned short triggered; /* The status of the watchdog upon boot */
+static char esb_expect_close;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 30   /* 30 sec default heartbeat (1<heartbeat<2*1023) */
+static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Some i6300ESB specific functions
+ */
+
+/*
+ * Prepare for reloading the timer by unlocking the proper registers.
+ * This is performed by first writing 0x80 followed by 0x86 to the
+ * reload register. After this the appropriate registers can be written
+ * to once before they need to be unlocked again.
+ */
+static inline void esb_unlock_registers(void) {
+        writeb(ESB_UNLOCK1, ESB_RELOAD_REG);
+        writeb(ESB_UNLOCK2, ESB_RELOAD_REG);
+}
+
+static void esb_timer_start(void)
+{
+       u8 val;
+
+       /* Enable or Enable + Lock? */
+       val = 0x02 | (nowayout ? 0x01 : 0x00);
+
+        pci_write_config_byte(esb_pci, ESB_LOCK_REG, val);
+}
+
+static int esb_timer_stop(void)
+{
+       u8 val;
+
+       spin_lock(&esb_lock);
+       /* First, reset timers as suggested by the docs */
+       esb_unlock_registers();
+       writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+       /* Then disable the WDT */
+       pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0);
+       pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val);
+       spin_unlock(&esb_lock);
+
+       /* Returns 0 if the timer was disabled, non-zero otherwise */
+       return (val & 0x01);
+}
+
+static void esb_timer_keepalive(void)
+{
+       spin_lock(&esb_lock);
+       esb_unlock_registers();
+       writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+        /* FIXME: Do we need to flush anything here? */
+       spin_unlock(&esb_lock);
+}
+
+static int esb_timer_set_heartbeat(int time)
+{
+       u32 val;
+
+       if (time < 0x1 || time > (2 * 0x03ff))
+               return -EINVAL;
+
+       spin_lock(&esb_lock);
+
+       /* We shift by 9, so if we are passed a value of 1 sec,
+        * val will be 1 << 9 = 512, then write that to two
+        * timers => 2 * 512 = 1024 (which is decremented at 1KHz)
+        */
+       val = time << 9;
+
+       /* Write timer 1 */
+       esb_unlock_registers();
+       writel(val, ESB_TIMER1_REG);
+
+       /* Write timer 2 */
+       esb_unlock_registers();
+        writel(val, ESB_TIMER2_REG);
+
+        /* Reload */
+       esb_unlock_registers();
+       writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
+
+       /* FIXME: Do we need to flush everything out? */
+
+       /* Done */
+       heartbeat = time;
+       spin_unlock(&esb_lock);
+       return 0;
+}
+
+static int esb_timer_read (void)
+{
+               u32 count;
+
+       /* This isn't documented, and doesn't take into
+         * acount which stage is running, but it looks
+         * like a 20 bit count down, so we might as well report it.
+         */
+        pci_read_config_dword(esb_pci, 0x64, &count);
+        return (int)count;
+}
+
+/*
+ *     /dev/watchdog handling
+ */
+
+static int esb_open (struct inode *inode, struct file *file)
+{
+        /* /dev/watchdog can only be opened once */
+        if (test_and_set_bit(0, &timer_alive))
+                return -EBUSY;
+
+        /* Reload and activate timer */
+        esb_timer_keepalive ();
+        esb_timer_start ();
+
+       return nonseekable_open(inode, file);
+}
+
+static int esb_release (struct inode *inode, struct file *file)
+{
+        /* Shut off the timer. */
+        if (esb_expect_close == 42) {
+                esb_timer_stop ();
+        } else {
+                printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+                esb_timer_keepalive ();
+        }
+        clear_bit(0, &timer_alive);
+        esb_expect_close = 0;
+        return 0;
+}
+
+static ssize_t esb_write (struct file *file, const char __user *data,
+                         size_t len, loff_t * ppos)
+{
+       /* See if we got the magic character 'V' and reload the timer */
+        if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       /* note: just in case someone wrote the magic character
+                        * five months ago... */
+                       esb_expect_close = 0;
+
+                       /* scan to see whether or not we got the magic character */
+                       for (i = 0; i != len; i++) {
+                               char c;
+                               if(get_user(c, data+i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       esb_expect_close = 42;
+                       }
+               }
+
+               /* someone wrote to us, we should reload the timer */
+               esb_timer_keepalive ();
+       }
+       return len;
+}
+
+static int esb_ioctl (struct inode *inode, struct file *file,
+                     unsigned int cmd, unsigned long arg)
+{
+       int new_options, retval = -EINVAL;
+       int new_heartbeat;
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       static struct watchdog_info ident = {
+               .options =              WDIOF_SETTIMEOUT |
+                                       WDIOF_KEEPALIVEPING |
+                                       WDIOF_MAGICCLOSE,
+               .firmware_version =     0,
+               .identity =             ESB_MODULE_NAME,
+       };
+
+       switch (cmd) {
+               case WDIOC_GETSUPPORT:
+                       return copy_to_user(argp, &ident,
+                                           sizeof (ident)) ? -EFAULT : 0;
+
+               case WDIOC_GETSTATUS:
+                       return put_user (esb_timer_read(), p);
+
+               case WDIOC_GETBOOTSTATUS:
+                       return put_user (triggered, p);
+
+                case WDIOC_KEEPALIVE:
+                        esb_timer_keepalive ();
+                        return 0;
+
+                case WDIOC_SETOPTIONS:
+                {
+                        if (get_user (new_options, p))
+                                return -EFAULT;
+
+                        if (new_options & WDIOS_DISABLECARD) {
+                                esb_timer_stop ();
+                                retval = 0;
+                        }
+
+                        if (new_options & WDIOS_ENABLECARD) {
+                                esb_timer_keepalive ();
+                                esb_timer_start ();
+                                retval = 0;
+                        }
+
+                        return retval;
+                }
+
+                case WDIOC_SETTIMEOUT:
+                {
+                        if (get_user(new_heartbeat, p))
+                                return -EFAULT;
+
+                        if (esb_timer_set_heartbeat(new_heartbeat))
+                            return -EINVAL;
+
+                        esb_timer_keepalive ();
+                        /* Fall */
+                }
+
+                case WDIOC_GETTIMEOUT:
+                        return put_user(heartbeat, p);
+
+                default:
+                        return -ENOIOCTLCMD;
+        }
+}
+
+/*
+ *      Notify system
+ */
+
+static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
+{
+        if (code==SYS_DOWN || code==SYS_HALT) {
+                /* Turn the WDT off */
+                esb_timer_stop ();
+        }
+
+        return NOTIFY_DONE;
+}
+
+/*
+ *      Kernel Interfaces
+ */
+
+static struct file_operations esb_fops = {
+        .owner =        THIS_MODULE,
+        .llseek =       no_llseek,
+        .write =        esb_write,
+        .ioctl =        esb_ioctl,
+        .open =         esb_open,
+        .release =      esb_release,
+};
+
+static struct miscdevice esb_miscdev = {
+        .minor =        WATCHDOG_MINOR,
+        .name =         "watchdog",
+        .fops =         &esb_fops,
+};
+
+static struct notifier_block esb_notifier = {
+        .notifier_call =        esb_notify_sys,
+};
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static struct pci_device_id esb_pci_tbl[] = {
+        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
+        { 0, },                 /* End of list */
+};
+MODULE_DEVICE_TABLE (pci, esb_pci_tbl);
+
+/*
+ *      Init & exit routines
+ */
+
+static unsigned char __init esb_getdevice (void)
+{
+       u8 val1;
+       unsigned short val2;
+
+        struct pci_dev *dev = NULL;
+        /*
+         *      Find the PCI device
+         */
+
+        for_each_pci_dev(dev) {
+                if (pci_match_id(esb_pci_tbl, dev)) {
+                        esb_pci = dev;
+                        break;
+                }
+       }
+
+        if (esb_pci) {
+               if (pci_enable_device(esb_pci)) {
+                       printk (KERN_ERR PFX "failed to enable device\n");
+                       goto err_devput;
+               }
+
+               if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) {
+                       printk (KERN_ERR PFX "failed to request region\n");
+                       goto err_disable;
+               }
+
+               BASEADDR = ioremap(pci_resource_start(esb_pci, 0),
+                                  pci_resource_len(esb_pci, 0));
+               if (BASEADDR == NULL) {
+                       /* Something's wrong here, BASEADDR has to be set */
+                       printk (KERN_ERR PFX "failed to get BASEADDR\n");
+                        goto err_release;
+                }
+
+               /*
+                * The watchdog has two timers, it can be setup so that the
+                * expiry of timer1 results in an interrupt and the expiry of
+                * timer2 results in a reboot. We set it to not generate
+                * any interrupts as there is not much we can do with it
+                * right now.
+                *
+                * We also enable reboots and set the timer frequency to
+                * the PCI clock divided by 2^15 (approx 1KHz).
+                */
+               pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003);
+
+               /* Check that the WDT isn't already locked */
+               pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
+               if (val1 & ESB_WDT_LOCK)
+                       printk (KERN_WARNING PFX "nowayout already set\n");
+
+               /* Set the timer to watchdog mode and disable it for now */
+               pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
+
+               /* Check if the watchdog was previously triggered */
+               esb_unlock_registers();
+               val2 = readw(ESB_RELOAD_REG);
+               triggered = (val2 & (0x01 << 9) >> 9);
+
+               /* Reset trigger flag and timers */
+               esb_unlock_registers();
+               writew((0x11 << 8), ESB_RELOAD_REG);
+
+               /* Done */
+               return 1;
+
+err_release:
+               pci_release_region(esb_pci, 0);
+err_disable:
+               pci_disable_device(esb_pci);
+err_devput:
+               pci_dev_put(esb_pci);
+       }
+       return 0;
+}
+
+static int __init watchdog_init (void)
+{
+        int ret;
+
+        spin_lock_init(&esb_lock);
+
+        /* Check whether or not the hardware watchdog is there */
+        if (!esb_getdevice () || esb_pci == NULL)
+                return -ENODEV;
+
+        /* Check that the heartbeat value is within it's range ; if not reset to the default */
+        if (esb_timer_set_heartbeat (heartbeat)) {
+                esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT);
+                printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n",
+                      heartbeat);
+        }
+
+        ret = register_reboot_notifier(&esb_notifier);
+        if (ret != 0) {
+                printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+                        ret);
+                goto err_unmap;
+        }
+
+        ret = misc_register(&esb_miscdev);
+        if (ret != 0) {
+                printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+                        WATCHDOG_MINOR, ret);
+                goto err_notifier;
+        }
+
+        esb_timer_stop ();
+
+        printk (KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
+                BASEADDR, heartbeat, nowayout);
+
+        return 0;
+
+err_notifier:
+        unregister_reboot_notifier(&esb_notifier);
+err_unmap:
+       iounmap(BASEADDR);
+/* err_release: */
+       pci_release_region(esb_pci, 0);
+/* err_disable: */
+       pci_disable_device(esb_pci);
+/* err_devput: */
+       pci_dev_put(esb_pci);
+        return ret;
+}
+
+static void __exit watchdog_cleanup (void)
+{
+       /* Stop the timer before we leave */
+       if (!nowayout)
+               esb_timer_stop ();
+
+       /* Deregister */
+       misc_deregister(&esb_miscdev);
+        unregister_reboot_notifier(&esb_notifier);
+       iounmap(BASEADDR);
+       pci_release_region(esb_pci, 0);
+       pci_disable_device(esb_pci);
+       pci_dev_put(esb_pci);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_cleanup);
+
+MODULE_AUTHOR("Ross Biro and David Härdeman");
+MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c
new file mode 100644 (file)
index 0000000..294c474
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * IBM Automatic Server Restart driver.
+ *
+ * Copyright (c) 2005 Andrey Panin <pazke@donpac.ru>
+ *
+ * Based on driver written by Pete Reynolds.
+ * Copyright (c) IBM Corporation, 1998-2004.
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/dmi.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+enum {
+       ASMTYPE_UNKNOWN,
+       ASMTYPE_TOPAZ,
+       ASMTYPE_JASPER,
+       ASMTYPE_PEARL,
+       ASMTYPE_JUNIPER,
+       ASMTYPE_SPRUCE,
+};
+
+#define PFX "ibmasr: "
+
+#define TOPAZ_ASR_REG_OFFSET   4
+#define TOPAZ_ASR_TOGGLE       0x40
+#define TOPAZ_ASR_DISABLE      0x80
+
+/* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */
+#define PEARL_BASE     0xe04
+#define PEARL_WRITE    0xe06
+#define PEARL_READ     0xe07
+
+#define PEARL_ASR_DISABLE_MASK 0x80    /* bit 7: disable = 1, enable = 0 */
+#define PEARL_ASR_TOGGLE_MASK  0x40    /* bit 6: 0, then 1, then 0 */
+
+/* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */
+#define JASPER_ASR_REG_OFFSET  0x38
+
+#define JASPER_ASR_DISABLE_MASK        0x01    /* bit 0: disable = 1, enable = 0 */
+#define JASPER_ASR_TOGGLE_MASK 0x02    /* bit 1: 0, then 1, then 0 */
+
+#define JUNIPER_BASE_ADDRESS   0x54b   /* Base address of Juniper ASR */
+#define JUNIPER_ASR_DISABLE_MASK 0x01  /* bit 0: disable = 1 enable = 0 */
+#define JUNIPER_ASR_TOGGLE_MASK        0x02    /* bit 1: 0, then 1, then 0 */
+
+#define SPRUCE_BASE_ADDRESS    0x118e  /* Base address of Spruce ASR */
+#define SPRUCE_ASR_DISABLE_MASK        0x01    /* bit 1: disable = 1 enable = 0 */
+#define SPRUCE_ASR_TOGGLE_MASK 0x02    /* bit 0: 0, then 1, then 0 */
+
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+static unsigned long asr_is_open;
+static char asr_expect_close;
+
+static unsigned int asr_type, asr_base, asr_length;
+static unsigned int asr_read_addr, asr_write_addr;
+static unsigned char asr_toggle_mask, asr_disable_mask;
+
+static void asr_toggle(void)
+{
+       unsigned char reg = inb(asr_read_addr);
+
+       outb(reg & ~asr_toggle_mask, asr_write_addr);
+       reg = inb(asr_read_addr);
+
+       outb(reg | asr_toggle_mask, asr_write_addr);
+       reg = inb(asr_read_addr);
+
+       outb(reg & ~asr_toggle_mask, asr_write_addr);
+       reg = inb(asr_read_addr);
+}
+
+static void asr_enable(void)
+{
+       unsigned char reg;
+
+       if (asr_type == ASMTYPE_TOPAZ) {
+               /* asr_write_addr == asr_read_addr */
+               reg = inb(asr_read_addr);
+               outb(reg & ~(TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE),
+                    asr_read_addr);
+       } else {
+               /*
+                * First make sure the hardware timer is reset by toggling
+                * ASR hardware timer line.
+                */
+               asr_toggle();
+
+               reg = inb(asr_read_addr);
+               outb(reg & ~asr_disable_mask, asr_write_addr);
+       }
+       reg = inb(asr_read_addr);
+}
+
+static void asr_disable(void)
+{
+       unsigned char reg = inb(asr_read_addr);
+
+       if (asr_type == ASMTYPE_TOPAZ)
+               /* asr_write_addr == asr_read_addr */
+               outb(reg | TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE,
+                    asr_read_addr);
+       else {
+               outb(reg | asr_toggle_mask, asr_write_addr);
+               reg = inb(asr_read_addr);
+
+               outb(reg | asr_disable_mask, asr_write_addr);
+       }
+       reg = inb(asr_read_addr);
+}
+
+static int __init asr_get_base_address(void)
+{
+       unsigned char low, high;
+       const char *type = "";
+
+       asr_length = 1;
+
+       switch (asr_type) {
+       case ASMTYPE_TOPAZ:
+               /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */
+               outb(0x07, 0x2e);
+               outb(0x07, 0x2f);
+
+               /* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */
+               outb(0x60, 0x2e);
+               high = inb(0x2f);
+
+               /* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */
+               outb(0x61, 0x2e);
+               low = inb(0x2f);
+
+               asr_base = (high << 16) | low;
+               asr_read_addr = asr_write_addr =
+                       asr_base + TOPAZ_ASR_REG_OFFSET;
+               asr_length = 5;
+
+               break;
+
+       case ASMTYPE_JASPER:
+               type = "Jaspers ";
+
+               /* FIXME: need to use pci_config_lock here, but it's not exported */
+
+/*             spin_lock_irqsave(&pci_config_lock, flags);*/
+
+               /* Select the SuperIO chip in the PCI I/O port register */
+               outl(0x8000f858, 0xcf8);
+
+               /*
+                * Read the base address for the SuperIO chip.
+                * Only the lower 16 bits are valid, but the address is word
+                * aligned so the last bit must be masked off.
+                */
+               asr_base = inl(0xcfc) & 0xfffe;
+
+/*             spin_unlock_irqrestore(&pci_config_lock, flags);*/
+
+               asr_read_addr = asr_write_addr =
+                       asr_base + JASPER_ASR_REG_OFFSET;
+               asr_toggle_mask = JASPER_ASR_TOGGLE_MASK;
+               asr_disable_mask = JASPER_ASR_DISABLE_MASK;
+               asr_length = JASPER_ASR_REG_OFFSET + 1;
+
+               break;
+
+       case ASMTYPE_PEARL:
+               type = "Pearls ";
+               asr_base = PEARL_BASE;
+               asr_read_addr = PEARL_READ;
+               asr_write_addr = PEARL_WRITE;
+               asr_toggle_mask = PEARL_ASR_TOGGLE_MASK;
+               asr_disable_mask = PEARL_ASR_DISABLE_MASK;
+               asr_length = 4;
+               break;
+
+       case ASMTYPE_JUNIPER:
+               type = "Junipers ";
+               asr_base = JUNIPER_BASE_ADDRESS;
+               asr_read_addr = asr_write_addr = asr_base;
+               asr_toggle_mask = JUNIPER_ASR_TOGGLE_MASK;
+               asr_disable_mask = JUNIPER_ASR_DISABLE_MASK;
+               break;
+
+       case ASMTYPE_SPRUCE:
+               type = "Spruce's ";
+               asr_base = SPRUCE_BASE_ADDRESS;
+               asr_read_addr = asr_write_addr = asr_base;
+               asr_toggle_mask = SPRUCE_ASR_TOGGLE_MASK;
+               asr_disable_mask = SPRUCE_ASR_DISABLE_MASK;
+               break;
+       }
+
+       if (!request_region(asr_base, asr_length, "ibmasr")) {
+               printk(KERN_ERR PFX "address %#x already in use\n",
+                       asr_base);
+               return -EBUSY;
+       }
+
+       printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base);
+
+       return 0;
+}
+
+
+static ssize_t asr_write(struct file *file, const char __user *buf,
+                        size_t count, loff_t *ppos)
+{
+       if (count) {
+               if (!nowayout) {
+                       size_t i;
+
+                       /* In case it was set long ago */
+                       asr_expect_close = 0;
+
+                       for (i = 0; i != count; i++) {
+                               char c;
+                               if (get_user(c, buf + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       asr_expect_close = 42;
+                       }
+               }
+               asr_toggle();
+       }
+       return count;
+}
+
+static int asr_ioctl(struct inode *inode, struct file *file,
+                    unsigned int cmd, unsigned long arg)
+{
+       static const struct watchdog_info ident = {
+               .options =      WDIOF_KEEPALIVEPING | 
+                               WDIOF_MAGICCLOSE,
+               .identity =     "IBM ASR"
+       };
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int heartbeat;
+
+       switch (cmd) {
+               case WDIOC_GETSUPPORT:
+                       return copy_to_user(argp, &ident, sizeof(ident)) ?
+                               -EFAULT : 0;
+
+               case WDIOC_GETSTATUS:
+               case WDIOC_GETBOOTSTATUS:
+                       return put_user(0, p);
+
+               case WDIOC_KEEPALIVE:
+                       asr_toggle();
+                       return 0;
+
+               /*
+                * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
+                * and WDIOC_GETTIMEOUT always returns 256.
+                */
+               case WDIOC_GETTIMEOUT:
+                       heartbeat = 256;
+                       return put_user(heartbeat, p);
+
+               case WDIOC_SETOPTIONS: {
+                       int new_options, retval = -EINVAL;
+
+                       if (get_user(new_options, p))
+                               return -EFAULT;
+
+                       if (new_options & WDIOS_DISABLECARD) {
+                               asr_disable();
+                               retval = 0;
+                       }
+
+                       if (new_options & WDIOS_ENABLECARD) {
+                               asr_enable();
+                               asr_toggle();
+                               retval = 0;
+                       }
+
+                       return retval;
+               }
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+static int asr_open(struct inode *inode, struct file *file)
+{
+       if(test_and_set_bit(0, &asr_is_open))
+               return -EBUSY;
+
+       asr_toggle();
+       asr_enable();
+
+       return nonseekable_open(inode, file);
+}
+
+static int asr_release(struct inode *inode, struct file *file)
+{
+       if (asr_expect_close == 42)
+               asr_disable();
+       else {
+               printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
+               asr_toggle();
+       }
+       clear_bit(0, &asr_is_open);
+       asr_expect_close = 0;
+       return 0;
+}
+
+static struct file_operations asr_fops = {
+       .owner =        THIS_MODULE,
+       .llseek =       no_llseek,
+       .write =        asr_write,
+       .ioctl =        asr_ioctl,
+       .open =         asr_open,
+       .release =      asr_release,
+};
+
+static struct miscdevice asr_miscdev = {
+       .minor =        WATCHDOG_MINOR,
+       .name =         "watchdog",
+       .fops =         &asr_fops,
+};
+
+
+struct ibmasr_id {
+       const char *desc;
+       int type;
+};
+
+static struct ibmasr_id __initdata ibmasr_id_table[] = {
+       { "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ },
+       { "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL },
+       { "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER },
+       { "IBM Automatic Server Restart - Machine Type 8482", ASMTYPE_JUNIPER },
+       { "IBM Automatic Server Restart - Machine Type 8648", ASMTYPE_SPRUCE },
+       { NULL }
+};
+
+static int __init ibmasr_init(void)
+{
+       struct ibmasr_id *id;
+       int rc;
+
+       for (id = ibmasr_id_table; id->desc; id++) {
+               if (dmi_find_device(DMI_DEV_TYPE_OTHER, id->desc, NULL)) {
+                       asr_type = id->type;
+                       break;
+               }
+       }
+
+       if (!asr_type)
+               return -ENODEV;
+
+       rc = misc_register(&asr_miscdev);
+       if (rc < 0) {
+               printk(KERN_ERR PFX "failed to register misc device\n");
+               return rc;
+       }
+
+       rc = asr_get_base_address();
+       if (rc) {
+               misc_deregister(&asr_miscdev);
+               return rc;
+       }
+
+       return 0;
+}
+
+static void __exit ibmasr_exit(void)
+{
+       if (!nowayout)
+               asr_disable();
+
+       misc_deregister(&asr_miscdev);
+
+       release_region(asr_base, asr_length);
+}
+
+module_init(ibmasr_init);
+module_exit(ibmasr_exit);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+MODULE_DESCRIPTION("IBM Automatic Server Restart driver");
+MODULE_AUTHOR("Andrey Panin");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
new file mode 100644 (file)
index 0000000..1436aea
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ *
+ * Platform-specific setup code should configure the dog to generate
+ * interrupt or reset as required.  This code only enables/disables
+ * and services the watchdog.
+ *
+ * Derived from mpc8xx_wdt.c, with the following copyright.
+ * 
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <asm/mv64x60.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* MV64x60 WDC (config) register access definitions */
+#define MV64x60_WDC_CTL1_MASK  (3 << 24)
+#define MV64x60_WDC_CTL1(val)  ((val & 3) << 24)
+#define MV64x60_WDC_CTL2_MASK  (3 << 26)
+#define MV64x60_WDC_CTL2(val)  ((val & 3) << 26)
+
+/* Flags bits */
+#define MV64x60_WDOG_FLAG_OPENED       0
+#define MV64x60_WDOG_FLAG_ENABLED      1
+
+static unsigned long wdt_flags;
+static int wdt_status;
+static void __iomem *mv64x60_regs;
+static int mv64x60_wdt_timeout;
+
+static void mv64x60_wdt_reg_write(u32 val)
+{
+       /* Allow write only to CTL1 / CTL2 fields, retaining values in
+        * other fields.
+        */
+       u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC);
+       data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK);
+       data |= val;
+       writel(data, mv64x60_regs + MV64x60_WDT_WDC);
+}
+
+static void mv64x60_wdt_service(void)
+{
+       /* Write 01 followed by 10 to CTL2 */
+       mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01));
+       mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02));
+}
+
+static void mv64x60_wdt_handler_disable(void)
+{
+       if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
+               /* Write 01 followed by 10 to CTL1 */
+               mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
+               mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+               printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
+       }
+}
+
+static void mv64x60_wdt_handler_enable(void)
+{
+       if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
+               /* Write 01 followed by 10 to CTL1 */
+               mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
+               mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+               printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
+       }
+}
+
+static int mv64x60_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
+               return -EBUSY;
+
+       mv64x60_wdt_service();
+       mv64x60_wdt_handler_enable();
+
+       return 0;
+}
+
+static int mv64x60_wdt_release(struct inode *inode, struct file *file)
+{
+       mv64x60_wdt_service();
+
+#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
+       mv64x60_wdt_handler_disable();
+#endif
+
+       clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);
+
+       return 0;
+}
+
+static ssize_t mv64x60_wdt_write(struct file *file, const char *data,
+                                size_t len, loff_t * ppos)
+{
+       if (*ppos != file->f_pos)
+               return -ESPIPE;
+
+       if (len)
+               mv64x60_wdt_service();
+
+       return len;
+}
+
+static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
+                            unsigned int cmd, unsigned long arg)
+{
+       int timeout;
+       static struct watchdog_info info = {
+               .options = WDIOF_KEEPALIVEPING,
+               .firmware_version = 0,
+               .identity = "MV64x60 watchdog",
+       };
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user((void *)arg, &info, sizeof(info)))
+                       return -EFAULT;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               if (put_user(wdt_status, (int *)arg))
+                       return -EFAULT;
+               wdt_status &= ~WDIOF_KEEPALIVEPING;
+               break;
+
+       case WDIOC_GETTEMP:
+               return -EOPNOTSUPP;
+
+       case WDIOC_SETOPTIONS:
+               return -EOPNOTSUPP;
+
+       case WDIOC_KEEPALIVE:
+               mv64x60_wdt_service();
+               wdt_status |= WDIOF_KEEPALIVEPING;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               return -EOPNOTSUPP;
+
+       case WDIOC_GETTIMEOUT:
+               timeout = mv64x60_wdt_timeout * HZ;
+               if (put_user(timeout, (int *)arg))
+                       return -EFAULT;
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return 0;
+}
+
+static struct file_operations mv64x60_wdt_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .write = mv64x60_wdt_write,
+       .ioctl = mv64x60_wdt_ioctl,
+       .open = mv64x60_wdt_open,
+       .release = mv64x60_wdt_release,
+};
+
+static struct miscdevice mv64x60_wdt_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &mv64x60_wdt_fops,
+};
+
+static int __devinit mv64x60_wdt_probe(struct device *dev)
+{
+       struct platform_device *pd = to_platform_device(dev);
+       struct mv64x60_wdt_pdata *pdata = pd->dev.platform_data;
+       int bus_clk = 133;
+
+       mv64x60_wdt_timeout = 10;
+       if (pdata) {
+               mv64x60_wdt_timeout = pdata->timeout;
+               bus_clk = pdata->bus_clk;
+       }
+
+       mv64x60_regs = mv64x60_get_bridge_vbase();
+
+       writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8,
+              mv64x60_regs + MV64x60_WDT_WDC);
+
+       return misc_register(&mv64x60_wdt_miscdev);
+}
+
+static int __devexit mv64x60_wdt_remove(struct device *dev)
+{
+       misc_deregister(&mv64x60_wdt_miscdev);
+
+       mv64x60_wdt_service();
+       mv64x60_wdt_handler_disable();
+
+       return 0;
+}
+
+static struct device_driver mv64x60_wdt_driver = {
+       .name = MV64x60_WDT_NAME,
+       .bus = &platform_bus_type,
+       .probe = mv64x60_wdt_probe,
+       .remove = __devexit_p(mv64x60_wdt_remove),
+};
+
+static struct platform_device *mv64x60_wdt_dev;
+
+static int __init mv64x60_wdt_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "MV64x60 watchdog driver\n");
+
+       mv64x60_wdt_dev = platform_device_register_simple(MV64x60_WDT_NAME,
+                                                         -1, NULL, 0);
+       if (IS_ERR(mv64x60_wdt_dev)) {
+               ret = PTR_ERR(mv64x60_wdt_dev);
+               goto out;
+       }
+
+       ret = driver_register(&mv64x60_wdt_driver);
+      out:
+       return ret;
+}
+
+static void __exit mv64x60_wdt_exit(void)
+{
+       driver_unregister(&mv64x60_wdt_driver);
+       platform_device_unregister(mv64x60_wdt_dev);
+}
+
+module_init(mv64x60_wdt_init);
+module_exit(mv64x60_wdt_exit);
+
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("MV64x60 watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 2b13afb09c5dfc4d601e65256ccf20bacc0641b2..5a80adbf8032565aec110a5f050d30612af62497 100644 (file)
  *     Includes, defines, variables, module parameters, ...
  */
 
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/config.h>      /* For CONFIG_WATCHDOG_NOWAYOUT/... */
+#include <linux/module.h>      /* For module specific items */
+#include <linux/moduleparam.h> /* For new moduleparam's */
+#include <linux/types.h>       /* For standard types (like size_t) */
+#include <linux/errno.h>       /* For the -ENODEV/... values */
+#include <linux/kernel.h>      /* For printk/panic/... */
+#include <linux/delay.h>       /* For mdelay function */
+#include <linux/miscdevice.h>  /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
+#include <linux/watchdog.h>    /* For the watchdog specific items */
+#include <linux/notifier.h>    /* For notifier support */
+#include <linux/reboot.h>      /* For reboot_notifier stuff */
+#include <linux/init.h>                /* For __init/__exit/... */
+#include <linux/fs.h>          /* For file operations */
+#include <linux/pci.h>         /* For pci functions */
+#include <linux/ioport.h>      /* For io-port access */
+#include <linux/spinlock.h>    /* For spin_lock/spin_unlock/... */
+
+#include <asm/uaccess.h>       /* For copy_to_user/put_user/... */
+#include <asm/io.h>            /* For inb/outb/... */
 
 /* Module and version information */
 #define WATCHDOG_VERSION "1.01"
-#define WATCHDOG_DATE "15 Mar 2005"
+#define WATCHDOG_DATE "02 Sep 2005"
 #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
 #define WATCHDOG_NAME "pcwd_pci"
 #define PFX WATCHDOG_NAME ": "
@@ -335,12 +337,14 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
                                return -EFAULT;
 
                        if (new_options & WDIOS_DISABLECARD) {
-                               pcipcwd_stop();
+                               if (pcipcwd_stop())
+                                       return -EIO;
                                retval = 0;
                        }
 
                        if (new_options & WDIOS_ENABLECARD) {
-                               pcipcwd_start();
+                               if (pcipcwd_start())
+                                       return -EIO;
                                retval = 0;
                        }
 
index 8b292bf343c4169d57ee694fbc14f38d9c659695..3625b2601b4257603b6e0b365a012cdc06fbe2a5 100644 (file)
@@ -464,7 +464,7 @@ static void s3c2410wdt_shutdown(struct device *dev)
 static unsigned long wtcon_save;
 static unsigned long wtdat_save;
 
-static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level)
+static int s3c2410wdt_suspend(struct device *dev, pm_message_t state, u32 level)
 {
        if (level == SUSPEND_POWER_DOWN) {
                /* Save watchdog state, and turn it off. */
diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c
new file mode 100644 (file)
index 0000000..c6cbf80
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ *     SBC8360 Watchdog driver
+ *
+ *     (c) Copyright 2005 Webcon, Inc.
+ *
+ *     Based on ib700wdt.c, which is based on advantechwdt.c which is based
+ *      on acquirewdt.c which is based on wdt.c.
+ *
+ *     (c) Copyright 2001 Charles Howes <chowes@vsol.net>
+ *
+ *      Based on advantechwdt.c which is based on acquirewdt.c which
+ *       is based on wdt.c.
+ *
+ *     (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ *     Based on acquirewdt.c which is based on wdt.c.
+ *     Original copyright messages:
+ *
+ *     (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *                             http://www.redhat.com
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ *     warranty for any of this software. This material is provided
+ *     "AS-IS" and at no charge.
+ *
+ *     (c) Copyright 1995    Alan Cox <alan@redhat.com>
+ *
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *           Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *           Added timeout module option to override default
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/notifier.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/moduleparam.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+static unsigned long sbc8360_is_open;
+static spinlock_t sbc8360_lock;
+static char expect_close;
+
+#define PFX "sbc8360: "
+
+/*
+ *
+ * Watchdog Timer Configuration
+ *
+ * The function of the watchdog timer is to reset the system automatically
+ * and is defined at I/O port 0120H and 0121H.  To enable the watchdog timer
+ * and allow the system to reset, write appropriate values from the table
+ * below to I/O port 0120H and 0121H.  To disable the timer, write a zero
+ * value to I/O port 0121H for the system to stop the watchdog function.
+ *
+ * The following describes how the timer should be programmed (according to
+ * the vendor documentation)
+ *
+ * Enabling Watchdog:
+ * MOV AX,000AH (enable, phase I)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000BH (enable, phase II)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000nH (set multiplier n, from 1-4)
+ * MOV DX,0120H
+ * OUT DX,AX
+ * MOV AX,000mH (set base timer m, from 0-F)
+ * MOV DX,0121H
+ * OUT DX,AX
+ *
+ * Reset timer:
+ * MOV AX,000mH (same as set base timer, above)
+ * MOV DX,0121H
+ * OUT DX,AX
+ *
+ * Disabling Watchdog:
+ * MOV AX,0000H (a zero value)
+ * MOV DX,0120H
+ * OUT DX,AX
+ *
+ * Watchdog timeout configuration values:
+ *             N
+ *     M |     1       2       3       4
+ *     --|----------------------------------
+ *     0 |     0.5s    5s      50s     100s
+ *     1 |     1s      10s     100s    200s
+ *     2 |     1.5s    15s     150s    300s
+ *     3 |     2s      20s     200s    400s
+ *     4 |     2.5s    25s     250s    500s
+ *     5 |     3s      30s     300s    600s
+ *     6 |     3.5s    35s     350s    700s
+ *     7 |     4s      40s     400s    800s
+ *     8 |     4.5s    45s     450s    900s
+ *     9 |     5s      50s     500s    1000s
+ *     A |     5.5s    55s     550s    1100s
+ *     B |     6s      60s     600s    1200s
+ *     C |     6.5s    65s     650s    1300s
+ *     D |     7s      70s     700s    1400s
+ *     E |     7.5s    75s     750s    1500s
+ *     F |     8s      80s     800s    1600s
+ *
+ * Another way to say the same things is:
+ *  For N=1, Timeout = (M+1) * 0.5s
+ *  For N=2, Timeout = (M+1) * 5s
+ *  For N=3, Timeout = (M+1) * 50s
+ *  For N=4, Timeout = (M+1) * 100s
+ *
+ */
+
+static int wd_times[64][2] = {
+       {0, 1},                 /* 0  = 0.5s */
+       {1, 1},                 /* 1  = 1s   */
+       {2, 1},                 /* 2  = 1.5s */
+       {3, 1},                 /* 3  = 2s   */
+       {4, 1},                 /* 4  = 2.5s */
+       {5, 1},                 /* 5  = 3s   */
+       {6, 1},                 /* 6  = 3.5s */
+       {7, 1},                 /* 7  = 4s   */
+       {8, 1},                 /* 8  = 4.5s */
+       {9, 1},                 /* 9  = 5s   */
+       {0xA, 1},               /* 10 = 5.5s */
+       {0xB, 1},               /* 11 = 6s   */
+       {0xC, 1},               /* 12 = 6.5s */
+       {0xD, 1},               /* 13 = 7s   */
+       {0xE, 1},               /* 14 = 7.5s */
+       {0xF, 1},               /* 15 = 8s   */
+       {0, 2},                 /* 16 = 5s  */
+       {1, 2},                 /* 17 = 10s */
+       {2, 2},                 /* 18 = 15s */
+       {3, 2},                 /* 19 = 20s */
+       {4, 2},                 /* 20 = 25s */
+       {5, 2},                 /* 21 = 30s */
+       {6, 2},                 /* 22 = 35s */
+       {7, 2},                 /* 23 = 40s */
+       {8, 2},                 /* 24 = 45s */
+       {9, 2},                 /* 25 = 50s */
+       {0xA, 2},               /* 26 = 55s */
+       {0xB, 2},               /* 27 = 60s */
+       {0xC, 2},               /* 28 = 65s */
+       {0xD, 2},               /* 29 = 70s */
+       {0xE, 2},               /* 30 = 75s */
+       {0xF, 2},               /* 31 = 80s */
+       {0, 3},                 /* 32 = 50s  */
+       {1, 3},                 /* 33 = 100s */
+       {2, 3},                 /* 34 = 150s */
+       {3, 3},                 /* 35 = 200s */
+       {4, 3},                 /* 36 = 250s */
+       {5, 3},                 /* 37 = 300s */
+       {6, 3},                 /* 38 = 350s */
+       {7, 3},                 /* 39 = 400s */
+       {8, 3},                 /* 40 = 450s */
+       {9, 3},                 /* 41 = 500s */
+       {0xA, 3},               /* 42 = 550s */
+       {0xB, 3},               /* 43 = 600s */
+       {0xC, 3},               /* 44 = 650s */
+       {0xD, 3},               /* 45 = 700s */
+       {0xE, 3},               /* 46 = 750s */
+       {0xF, 3},               /* 47 = 800s */
+       {0, 4},                 /* 48 = 100s */
+       {1, 4},                 /* 49 = 200s */
+       {2, 4},                 /* 50 = 300s */
+       {3, 4},                 /* 51 = 400s */
+       {4, 4},                 /* 52 = 500s */
+       {5, 4},                 /* 53 = 600s */
+       {6, 4},                 /* 54 = 700s */
+       {7, 4},                 /* 55 = 800s */
+       {8, 4},                 /* 56 = 900s */
+       {9, 4},                 /* 57 = 1000s */
+       {0xA, 4},               /* 58 = 1100s */
+       {0xB, 4},               /* 59 = 1200s */
+       {0xC, 4},               /* 60 = 1300s */
+       {0xD, 4},               /* 61 = 1400s */
+       {0xE, 4},               /* 62 = 1500s */
+       {0xF, 4}                /* 63 = 1600s */
+};
+
+#define SBC8360_ENABLE 0x120
+#define SBC8360_BASETIME 0x121
+
+static int timeout = 27;
+static int wd_margin = 0xB;
+static int wd_multiplier = 2;
+static int nowayout = WATCHDOG_NOWAYOUT;
+
+module_param(timeout, int, 27);
+MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+                "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ *     Kernel methods.
+ */
+
+/* Activate and pre-configure watchdog */
+static void sbc8360_activate(void)
+{
+       /* Enable the watchdog */
+       outb(0x0A, SBC8360_ENABLE);
+       msleep_interruptible(100);
+       outb(0x0B, SBC8360_ENABLE);
+       msleep_interruptible(100);
+       /* Set timeout multiplier */
+       outb(wd_multiplier, SBC8360_ENABLE);
+       msleep_interruptible(100);
+       /* Nothing happens until first sbc8360_ping() */
+}
+
+/* Kernel pings watchdog */
+static void sbc8360_ping(void)
+{
+       /* Write the base timer register */
+       outb(wd_margin, SBC8360_BASETIME);
+}
+
+/* Userspace pings kernel driver, or requests clean close */
+static ssize_t sbc8360_write(struct file *file, const char __user * buf,
+                            size_t count, loff_t * ppos)
+{
+       if (count) {
+               if (!nowayout) {
+                       size_t i;
+
+                       /* In case it was set long ago */
+                       expect_close = 0;
+
+                       for (i = 0; i != count; i++) {
+                               char c;
+                               if (get_user(c, buf + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       expect_close = 42;
+                       }
+               }
+               sbc8360_ping();
+       }
+       return count;
+}
+
+static int sbc8360_open(struct inode *inode, struct file *file)
+{
+       spin_lock(&sbc8360_lock);
+       if (test_and_set_bit(0, &sbc8360_is_open)) {
+               spin_unlock(&sbc8360_lock);
+               return -EBUSY;
+       }
+       if (nowayout)
+               __module_get(THIS_MODULE);
+
+       /* Activate and ping once to start the countdown */
+       spin_unlock(&sbc8360_lock);
+       sbc8360_activate();
+       sbc8360_ping();
+       return nonseekable_open(inode, file);
+}
+
+static int sbc8360_close(struct inode *inode, struct file *file)
+{
+       spin_lock(&sbc8360_lock);
+       if (expect_close == 42)
+               outb(0, SBC8360_ENABLE);
+       else
+               printk(KERN_CRIT PFX
+                      "SBC8360 device closed unexpectedly.  SBC8360 will not stop!\n");
+
+       clear_bit(0, &sbc8360_is_open);
+       expect_close = 0;
+       spin_unlock(&sbc8360_lock);
+       return 0;
+}
+
+/*
+ *     Notifier for system down
+ */
+
+static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code,
+                             void *unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT) {
+               /* Disable the SBC8360 Watchdog */
+               outb(0, SBC8360_ENABLE);
+       }
+       return NOTIFY_DONE;
+}
+
+/*
+ *     Kernel Interfaces
+ */
+
+static struct file_operations sbc8360_fops = {
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .write = sbc8360_write,
+       .open = sbc8360_open,
+       .release = sbc8360_close,
+};
+
+static struct miscdevice sbc8360_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &sbc8360_fops,
+};
+
+/*
+ *     The SBC8360 needs to learn about soft shutdowns in order to
+ *     turn the timebomb registers off.
+ */
+
+static struct notifier_block sbc8360_notifier = {
+       .notifier_call = sbc8360_notify_sys,
+};
+
+static int __init sbc8360_init(void)
+{
+       int res;
+       unsigned long int mseconds = 60000;
+
+       spin_lock_init(&sbc8360_lock);
+       res = misc_register(&sbc8360_miscdev);
+       if (res) {
+               printk(KERN_ERR PFX "failed to register misc device\n");
+               goto out_nomisc;
+       }
+
+       if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
+               printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
+                      SBC8360_ENABLE);
+               res = -EIO;
+               goto out_noenablereg;
+       }
+       if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
+               printk(KERN_ERR PFX
+                      "BASETIME method I/O %X is not available.\n",
+                      SBC8360_BASETIME);
+               res = -EIO;
+               goto out_nobasetimereg;
+       }
+
+       res = register_reboot_notifier(&sbc8360_notifier);
+       if (res) {
+               printk(KERN_ERR PFX "Failed to register reboot notifier.\n");
+               goto out_noreboot;
+       }
+
+       if (timeout < 0 || timeout > 63) {
+               printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
+               res = -EINVAL;
+               goto out_noreboot;
+       }
+
+       wd_margin = wd_times[timeout][0];
+       wd_multiplier = wd_times[timeout][1];
+
+       if (wd_multiplier == 1)
+               mseconds = (wd_margin + 1) * 500;
+       else if (wd_multiplier == 2)
+               mseconds = (wd_margin + 1) * 5000;
+       else if (wd_multiplier == 3)
+               mseconds = (wd_margin + 1) * 50000;
+       else if (wd_multiplier == 4)
+               mseconds = (wd_margin + 1) * 100000;
+
+       /* My kingdom for the ability to print "0.5 seconds" in the kernel! */
+       printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds);
+
+       return 0;
+
+      out_noreboot:
+       release_region(SBC8360_ENABLE, 1);
+       release_region(SBC8360_BASETIME, 1);
+      out_noenablereg:
+      out_nobasetimereg:
+       misc_deregister(&sbc8360_miscdev);
+      out_nomisc:
+       return res;
+}
+
+static void __exit sbc8360_exit(void)
+{
+       misc_deregister(&sbc8360_miscdev);
+       unregister_reboot_notifier(&sbc8360_notifier);
+       release_region(SBC8360_ENABLE, 1);
+       release_region(SBC8360_BASETIME, 1);
+}
+
+module_init(sbc8360_init);
+module_exit(sbc8360_exit);
+
+MODULE_AUTHOR("Ian E. Morgan <imorgan@webcon.ca>");
+MODULE_DESCRIPTION("SBC8360 watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+/* end of sbc8360.c */
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c
new file mode 100644 (file)
index 0000000..a7ff64c
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ *     W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip
+ *
+ *     (c) Copyright 2005  Jose Goncalves <jose.goncalves@inov.pt>
+ *
+ *      Based on w83877f_wdt.c by Scott Jennings,
+ *           and wdt977.c by Woody Suwalski
+ *
+ *                     -----------------------
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define WATCHDOG_VERSION  "1.00"
+#define WATCHDOG_NAME     "W83977F WDT"
+#define PFX WATCHDOG_NAME ": "
+#define DRIVER_VERSION    WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+
+#define IO_INDEX_PORT     0x3F0
+#define IO_DATA_PORT      (IO_INDEX_PORT+1)
+
+#define UNLOCK_DATA       0x87
+#define LOCK_DATA         0xAA
+#define DEVICE_REGISTER   0x07
+
+#define        DEFAULT_TIMEOUT   45            /* default timeout in seconds */
+
+static int timeout = DEFAULT_TIMEOUT;
+static int timeoutW;                   /* timeout in watchdog counter units */
+static unsigned long timer_alive;
+static int testmode;
+static char expect_close;
+static spinlock_t spinlock;
+
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
+module_param(testmode, int, 0);
+MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Start the watchdog
+ */
+
+static int wdt_start(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+
+       /* Unlock the SuperIO chip */
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+       /*
+        * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
+        * F2 has the timeout in watchdog counter units.
+        * F3 is set to enable watchdog LED blink at timeout.
+        * F4 is used to just clear the TIMEOUT'ed state (bit 0).
+        */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+       outb_p(0xF2,IO_INDEX_PORT);
+       outb_p(timeoutW,IO_DATA_PORT);
+       outb_p(0xF3,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+       outb_p(0xF4,IO_INDEX_PORT);
+       outb_p(0x00,IO_DATA_PORT);
+
+       /* Set device Aux2 active */
+       outb_p(0x30,IO_INDEX_PORT);
+       outb_p(0x01,IO_DATA_PORT);
+
+       /* 
+        * Select device Aux1 (dev=7) to set GP16 as the watchdog output
+        * (in reg E6) and GP13 as the watchdog LED output (in reg E3).
+        * Map GP16 at pin 119.
+        * In test mode watch the bit 0 on F4 to indicate "triggered" or
+        * check watchdog LED on SBC.
+        */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x07,IO_DATA_PORT);
+       if (!testmode)
+       {
+               unsigned pin_map;
+
+               outb_p(0xE6,IO_INDEX_PORT);
+               outb_p(0x0A,IO_DATA_PORT);
+               outb_p(0x2C,IO_INDEX_PORT);
+               pin_map = inb_p(IO_DATA_PORT);
+               pin_map |= 0x10;
+               pin_map &= ~(0x20);
+               outb_p(0x2C,IO_INDEX_PORT);
+               outb_p(pin_map,IO_DATA_PORT);
+       }
+       outb_p(0xE3,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+
+       /* Set device Aux1 active */
+       outb_p(0x30,IO_INDEX_PORT);
+       outb_p(0x01,IO_DATA_PORT);
+
+       /* Lock the SuperIO chip */
+       outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       printk(KERN_INFO PFX "activated.\n");
+
+       return 0;
+}
+
+/*
+ * Stop the watchdog
+ */
+
+static int wdt_stop(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+
+       /* Unlock the SuperIO chip */
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+       /* 
+        * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
+        * F2 is reset to its default value (watchdog timer disabled).
+        * F3 is reset to its default state.
+        * F4 clears the TIMEOUT'ed state (bit 0) - back to default.
+        */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+       outb_p(0xF2,IO_INDEX_PORT);
+       outb_p(0xFF,IO_DATA_PORT);
+       outb_p(0xF3,IO_INDEX_PORT);
+       outb_p(0x00,IO_DATA_PORT);
+       outb_p(0xF4,IO_INDEX_PORT);
+       outb_p(0x00,IO_DATA_PORT);
+       outb_p(0xF2,IO_INDEX_PORT);
+       outb_p(0x00,IO_DATA_PORT);
+
+       /*
+        * Select device Aux1 (dev=7) to set GP16 (in reg E6) and 
+        * Gp13 (in reg E3) as inputs.
+        */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x07,IO_DATA_PORT);
+       if (!testmode)
+       {
+               outb_p(0xE6,IO_INDEX_PORT);
+               outb_p(0x01,IO_DATA_PORT);
+       }
+       outb_p(0xE3,IO_INDEX_PORT);
+       outb_p(0x01,IO_DATA_PORT);
+
+       /* Lock the SuperIO chip */
+       outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       printk(KERN_INFO PFX "shutdown.\n");
+
+       return 0;
+}
+
+/*
+ * Send a keepalive ping to the watchdog
+ * This is done by simply re-writing the timeout to reg. 0xF2
+ */
+
+static int wdt_keepalive(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+
+       /* Unlock the SuperIO chip */
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+       /* Select device Aux2 (device=8) to kick watchdog reg F2 */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+       outb_p(0xF2,IO_INDEX_PORT);
+       outb_p(timeoutW,IO_DATA_PORT);
+
+       /* Lock the SuperIO chip */
+       outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       return 0;
+}
+
+/*
+ * Set the watchdog timeout value
+ */
+
+static int wdt_set_timeout(int t)
+{
+       int tmrval;
+
+       /*
+        * Convert seconds to watchdog counter time units, rounding up.
+        * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup 
+        * value. This information is supplied in the PCM-5335 manual and was
+        * checked by me on a real board. This is a bit strange because W83977f
+        * datasheet says counter unit is in minutes!
+        */
+       if (t < 15)
+               return -EINVAL;
+
+       tmrval = ((t + 15) + 29) / 30;
+
+       if (tmrval > 255)
+               return -EINVAL;
+
+       /*
+        * timeout is the timeout in seconds, 
+        * timeoutW is the timeout in watchdog counter units.
+        */
+       timeoutW = tmrval;
+       timeout = (timeoutW * 30) - 15;
+       return 0;
+}
+
+/*
+ * Get the watchdog status
+ */
+
+static int wdt_get_status(int *status)
+{
+       int new_status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+
+       /* Unlock the SuperIO chip */
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+       outb_p(UNLOCK_DATA,IO_INDEX_PORT);
+
+       /* Select device Aux2 (device=8) to read watchdog reg F4 */
+       outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
+       outb_p(0x08,IO_DATA_PORT);
+       outb_p(0xF4,IO_INDEX_PORT);
+       new_status = inb_p(IO_DATA_PORT);
+
+       /* Lock the SuperIO chip */
+       outb_p(LOCK_DATA,IO_INDEX_PORT);
+
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       *status = 0;
+       if (new_status & 1)
+               *status |= WDIOF_CARDRESET;
+
+       return 0;
+}
+
+
+/*
+ *     /dev/watchdog handling
+ */
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+       /* If the watchdog is alive we don't need to start it again */
+       if( test_and_set_bit(0, &timer_alive) )
+               return -EBUSY;
+
+       if (nowayout)
+               __module_get(THIS_MODULE);
+
+       wdt_start();
+       return nonseekable_open(inode, file);
+}
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+       /*
+        * Shut off the timer.
+        * Lock it in if it's a module and we set nowayout
+        */
+       if (expect_close == 42)
+       {
+               wdt_stop();
+               clear_bit(0, &timer_alive);
+       } else {
+               wdt_keepalive();
+               printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
+       }
+       expect_close = 0;
+       return 0;
+}
+
+/*
+ *      wdt_write:
+ *      @file: file handle to the watchdog
+ *      @buf: buffer to write (unused as data does not matter here
+ *      @count: count of bytes
+ *      @ppos: pointer to the position to write. No seeks allowed
+ *
+ *      A write to a watchdog device is defined as a keepalive signal. Any
+ *      write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       /* See if we got the magic character 'V' and reload the timer */
+       if(count)
+       {
+               if (!nowayout)
+               {
+                       size_t ofs;
+
+                       /* note: just in case someone wrote the magic character long ago */
+                       expect_close = 0;
+
+                       /* scan to see whether or not we got the magic character */
+                       for(ofs = 0; ofs != count; ofs++)
+                       {
+                               char c;
+                               if (get_user(c, buf + ofs))
+                                       return -EFAULT;
+                               if (c == 'V') {
+                                       expect_close = 42;
+                               }
+                       }
+               }
+
+               /* someone wrote to us, we should restart timer */
+               wdt_keepalive();
+       }
+       return count;
+}
+
+/*
+ *      wdt_ioctl:
+ *      @inode: inode of the device
+ *      @file: file handle to the device
+ *      @cmd: watchdog command
+ *      @arg: argument pointer
+ *
+ *      The watchdog API defines a common set of functions for all watchdogs
+ *      according to their available features.
+ */
+
+static struct watchdog_info ident = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+       .firmware